@jdcpuwiz/homelab-ui 0.10.1 → 0.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/fonts.css ADDED
@@ -0,0 +1,148 @@
1
+ /**
2
+ * homelab-ui — the sanctioned faces, self-hosted (C525).
3
+ *
4
+ * WHY THIS EXISTS. Every consuming dashboard used to load these through
5
+ * `next/font/google`, which makes `next build` fetch from fonts.gstatic.com.
6
+ * That put the NETWORK on the critical path of every deploy: zoovault's
7
+ * 2026-08-15 deploy died when a floating `next` release's font requests 404'd,
8
+ * on a commit that had built clean locally. Pinning the toolchain removes the
9
+ * trigger; this file removes the dependency.
10
+ *
11
+ * WHY PLAIN CSS AND NOT A RE-EXPORTED LOADER. `src/lib/fonts.ts` is right that
12
+ * this package cannot own `next/font` loading — Next's SWC plugin scans the
13
+ * app's own source for a literal `const X = Font({...})`, and bundling rewrites
14
+ * `const` to `var`, so a re-exported loader cannot work. That constraint is
15
+ * specific to `next/font`. It does not apply to `@font-face`.
16
+ *
17
+ * WHY IT NEEDS NO CSS-VAR WIRING. globals.css asks for
18
+ * `var(--font-poppins, "Poppins")` — the app's variable first, then the LITERAL
19
+ * family name. Registering a "Poppins" @font-face therefore satisfies the
20
+ * package on its own, and an app can keep its existing `.variable` classes on
21
+ * <html> harmlessly (an undefined var just falls through to the literal).
22
+ *
23
+ * USAGE — replaces the whole three-loader block in a consumer:
24
+ * import "@jdcpuwiz/homelab-ui/fonts.css"
25
+ *
26
+ * Latin subset only, sourced from @fontsource. OFL licences ship alongside in
27
+ * fonts/. `font-display: swap` matches what next/font/google emitted, so text
28
+ * paints immediately in the fallback rather than blocking on the face.
29
+ */
30
+
31
+
32
+ /* ── Poppins ── */
33
+ @font-face {
34
+ font-family: "Poppins";
35
+ font-style: normal;
36
+ font-weight: 300;
37
+ font-display: swap;
38
+ src: url("./fonts/poppins-latin-300-normal.woff2") format("woff2");
39
+ }
40
+ @font-face {
41
+ font-family: "Poppins";
42
+ font-style: normal;
43
+ font-weight: 400;
44
+ font-display: swap;
45
+ src: url("./fonts/poppins-latin-400-normal.woff2") format("woff2");
46
+ }
47
+ @font-face {
48
+ font-family: "Poppins";
49
+ font-style: normal;
50
+ font-weight: 500;
51
+ font-display: swap;
52
+ src: url("./fonts/poppins-latin-500-normal.woff2") format("woff2");
53
+ }
54
+ @font-face {
55
+ font-family: "Poppins";
56
+ font-style: normal;
57
+ font-weight: 600;
58
+ font-display: swap;
59
+ src: url("./fonts/poppins-latin-600-normal.woff2") format("woff2");
60
+ }
61
+ @font-face {
62
+ font-family: "Poppins";
63
+ font-style: normal;
64
+ font-weight: 700;
65
+ font-display: swap;
66
+ src: url("./fonts/poppins-latin-700-normal.woff2") format("woff2");
67
+ }
68
+ @font-face {
69
+ font-family: "Poppins";
70
+ font-style: normal;
71
+ font-weight: 800;
72
+ font-display: swap;
73
+ src: url("./fonts/poppins-latin-800-normal.woff2") format("woff2");
74
+ }
75
+
76
+ /* ── Orbitron ── */
77
+ @font-face {
78
+ font-family: "Orbitron";
79
+ font-style: normal;
80
+ font-weight: 400;
81
+ font-display: swap;
82
+ src: url("./fonts/orbitron-latin-400-normal.woff2") format("woff2");
83
+ }
84
+ @font-face {
85
+ font-family: "Orbitron";
86
+ font-style: normal;
87
+ font-weight: 500;
88
+ font-display: swap;
89
+ src: url("./fonts/orbitron-latin-500-normal.woff2") format("woff2");
90
+ }
91
+ @font-face {
92
+ font-family: "Orbitron";
93
+ font-style: normal;
94
+ font-weight: 600;
95
+ font-display: swap;
96
+ src: url("./fonts/orbitron-latin-600-normal.woff2") format("woff2");
97
+ }
98
+ @font-face {
99
+ font-family: "Orbitron";
100
+ font-style: normal;
101
+ font-weight: 700;
102
+ font-display: swap;
103
+ src: url("./fonts/orbitron-latin-700-normal.woff2") format("woff2");
104
+ }
105
+ @font-face {
106
+ font-family: "Orbitron";
107
+ font-style: normal;
108
+ font-weight: 800;
109
+ font-display: swap;
110
+ src: url("./fonts/orbitron-latin-800-normal.woff2") format("woff2");
111
+ }
112
+ @font-face {
113
+ font-family: "Orbitron";
114
+ font-style: normal;
115
+ font-weight: 900;
116
+ font-display: swap;
117
+ src: url("./fonts/orbitron-latin-900-normal.woff2") format("woff2");
118
+ }
119
+
120
+ /* ── JetBrains Mono ── */
121
+ @font-face {
122
+ font-family: "JetBrains Mono";
123
+ font-style: normal;
124
+ font-weight: 400;
125
+ font-display: swap;
126
+ src: url("./fonts/jetbrains-mono-latin-400-normal.woff2") format("woff2");
127
+ }
128
+ @font-face {
129
+ font-family: "JetBrains Mono";
130
+ font-style: normal;
131
+ font-weight: 500;
132
+ font-display: swap;
133
+ src: url("./fonts/jetbrains-mono-latin-500-normal.woff2") format("woff2");
134
+ }
135
+ @font-face {
136
+ font-family: "JetBrains Mono";
137
+ font-style: normal;
138
+ font-weight: 600;
139
+ font-display: swap;
140
+ src: url("./fonts/jetbrains-mono-latin-600-normal.woff2") format("woff2");
141
+ }
142
+ @font-face {
143
+ font-family: "JetBrains Mono";
144
+ font-style: normal;
145
+ font-weight: 700;
146
+ font-display: swap;
147
+ src: url("./fonts/jetbrains-mono-latin-700-normal.woff2") format("woff2");
148
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jdcpuwiz/homelab-ui",
3
- "version": "0.10.1",
4
- "description": "Shared dark-theme UI primitives for the JdCpuWiz homelab \u2014 Sidebar, Button, Modal, PageHeader, TagChips, plus the canonical Tailwind preset, CSS vars, and the sanctioned three-face typography (Poppins / Orbitron / JetBrains Mono) on one flat #f0f1f4 text color.",
3
+ "version": "0.10.3",
4
+ "description": "Shared dark-theme UI primitives for the JdCpuWiz homelab — Sidebar, Button, Modal, PageHeader, TagChips, plus the canonical Tailwind preset, CSS vars, and the sanctioned three-face typography (Poppins / Orbitron / JetBrains Mono) on one flat #f0f1f4 text color.",
5
5
  "license": "MIT",
6
6
  "author": "Wiz <shad@deckerzoo.com>",
7
7
  "repository": {
@@ -27,7 +27,8 @@
27
27
  "import": "./tailwind-preset.cjs",
28
28
  "default": "./tailwind-preset.cjs"
29
29
  },
30
- "./globals.css": "./globals.css"
30
+ "./globals.css": "./globals.css",
31
+ "./fonts.css": "./fonts.css"
31
32
  },
32
33
  "files": [
33
34
  "dist",
@@ -35,7 +36,9 @@
35
36
  "globals.css",
36
37
  "starter",
37
38
  "README.md",
38
- "LICENSE"
39
+ "LICENSE",
40
+ "fonts.css",
41
+ "fonts"
39
42
  ],
40
43
  "sideEffects": [
41
44
  "*.css"
@@ -46,8 +49,9 @@
46
49
  "ladle": "ladle serve",
47
50
  "ladle:build": "ladle build",
48
51
  "typecheck": "tsc --noEmit",
49
- "prepublishOnly": "npm run build",
50
- "prepare": "npm run build"
52
+ "prepublishOnly": "npm run build && npm run check:publish",
53
+ "prepare": "npm run build",
54
+ "check:publish": "node scripts/check-publish-clean.mjs"
51
55
  },
52
56
  "peerDependencies": {
53
57
  "next": ">=15",
@@ -85,4 +89,4 @@
85
89
  "react",
86
90
  "design-system"
87
91
  ]
88
- }
92
+ }
@@ -1,56 +1,62 @@
1
1
  /**
2
2
  * STARTER — Next.js root layout wiring the three sanctioned faces
3
3
  * (BuildPlan #57). Copy into your app's `app/layout.tsx` and adjust the
4
- * metadata / body content. Do NOT import this file from the package — a
5
- * next/font loader can't be re-exported (Next scans your own source for the
6
- * literal `const Foo = Font({...})` call), so the loaders must live in YOUR
7
- * app source. This file is a template, shipped for copy-paste only.
4
+ * metadata / body content. This file is a template, shipped for copy-paste
5
+ * only — do not import it from the package.
8
6
  *
9
7
  * SANS Poppins — body / UI / headings / labels
10
8
  * DISPLAY Orbitron — big numbers only (≥ ~1.5rem): stat heroes, clock
11
9
  * MONO JetBrains Mono — small values, version stamps, code (< ~1.5rem)
12
10
  *
13
- * The `variable` names below MUST match the package convention
14
- * (`FONT_APP_VARIABLES`): --font-poppins / --font-orbitron /
15
- * --font-jetbrains-mono. `@jdcpuwiz/homelab-ui/globals.css` reads exactly
16
- * these, so following the naming means zero extra config.
11
+ * There is no per-app font config to get right any more: the single
12
+ * `fonts.css` import registers every face, and `globals.css` picks them up.
13
+ *
14
+ * ## The faces are SELF-HOSTED — no network at build time (C525)
15
+ *
16
+ * `import "@jdcpuwiz/homelab-ui/fonts.css"` registers all three faces from
17
+ * woff2 files shipped inside the package. `next build` never reaches
18
+ * fonts.gstatic.com, so your DEPLOY has no font-related network dependency.
19
+ *
20
+ * This template used to use `next/font/google`, and that broke a real deploy:
21
+ * on 2026-08-15 zoovault's image floated `next` to a release whose
22
+ * next/font/google requests started 404ing, and the deploy died on a commit
23
+ * that had built clean locally. Nothing warned — a build that can reach
24
+ * Google looks identical to one that never needed to.
25
+ *
26
+ * ## ⚠ DO NOT reference --font-poppins / --font-orbitron / --font-jetbrains-mono
27
+ *
28
+ * Those variables existed only because `next/font` defined them. They do not
29
+ * exist here. Referencing one is worse than a no-op: `var(--x)` with no
30
+ * fallback ARGUMENT is invalid at computed-value time, so the entire
31
+ * font-family declaration is DISCARDED and the element inherits its parent's
32
+ * face — your authored fallbacks after the comma never engage. The text still
33
+ * renders, in a plausible font, with nothing in the console. Tailwind's
34
+ * `font-[family-name:var(--x)]` form fails identically.
35
+ *
36
+ * Use the package tokens instead, which resolve to the self-hosted faces:
37
+ * var(--hl-font-sans) Poppins
38
+ * var(--hl-font-display) Orbitron
39
+ * var(--hl-font-mono) JetBrains Mono
40
+ * or the `font-display` / `font-mono` utility classes.
41
+ *
42
+ * ## Still mandatory, separately
43
+ *
44
+ * PIN your dependencies from a committed lockfile inside the image (`npm ci`,
45
+ * not a bare `npm install`). Self-hosting the fonts removes one network
46
+ * dependency; it does not make a floating install safe.
17
47
  */
18
48
  import type { Metadata } from "next";
19
- import { Poppins, Orbitron, JetBrains_Mono } from "next/font/google";
49
+ import "@jdcpuwiz/homelab-ui/fonts.css"; // the three faces, self-hosted
20
50
  import "@jdcpuwiz/homelab-ui/globals.css";
21
51
  import "./globals.css"; // optional: your own overrides, AFTER the package
22
52
 
23
- const poppins = Poppins({
24
- subsets: ["latin"],
25
- weight: ["300", "400", "500", "600", "700", "800"],
26
- display: "swap",
27
- variable: "--font-poppins",
28
- });
29
-
30
- const orbitron = Orbitron({
31
- subsets: ["latin"],
32
- weight: ["400", "500", "600", "700", "800", "900"],
33
- display: "swap",
34
- variable: "--font-orbitron",
35
- });
36
-
37
- const jetbrainsMono = JetBrains_Mono({
38
- subsets: ["latin"],
39
- weight: ["400", "500", "600", "700"],
40
- display: "swap",
41
- variable: "--font-jetbrains-mono",
42
- });
43
-
44
53
  export const metadata: Metadata = { title: "My App" };
45
54
 
46
55
  export default function RootLayout({
47
56
  children,
48
57
  }: Readonly<{ children: React.ReactNode }>) {
49
58
  return (
50
- <html
51
- lang="en"
52
- className={`dark ${poppins.variable} ${orbitron.variable} ${jetbrainsMono.variable}`}
53
- >
59
+ <html lang="en" className="dark">
54
60
  {/* Body font is Poppins with no extra style — the package sets
55
61
  `font-family: var(--hl-font-sans)` on `body`. Reach for the other
56
62
  faces by job with the `font-display` / `font-mono` classes. */}