synthesisui 0.4.7 → 0.4.8
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/dist/commands/add.js +24 -4
- package/dist/fonts.js +49 -0
- package/package.json +1 -1
package/dist/commands/add.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { syncClaudeMd } from "../claude-md.js";
|
|
4
|
-
import { resolveRegistry } from "../config.js";
|
|
5
|
-
import { customFontFamilies, googleFontsHref } from "../fonts.js";
|
|
4
|
+
import { readProjectConfig, resolveRegistry } from "../config.js";
|
|
5
|
+
import { customFontFamilies, googleFontsHref, nextFontSnippet, } from "../fonts.js";
|
|
6
6
|
import { buildGuide } from "../guide.js";
|
|
7
7
|
import { body as line, section, snippet } from "../output.js";
|
|
8
8
|
import { fetchDesignSystem } from "../registry.js";
|
|
@@ -131,10 +131,30 @@ export async function add(slug, opts) {
|
|
|
131
131
|
console.log("");
|
|
132
132
|
console.log(snippet([`<body data-ds="${payload.slug}">{children}</body>`]));
|
|
133
133
|
// 3. Load the type - the DS ships token NAMES, not the fonts themselves.
|
|
134
|
-
//
|
|
134
|
+
// Next apps get the next/font recipe (self-hosted + preloaded + adjusted
|
|
135
|
+
// fallback = no FOUT "blink" on refresh); the Google Fonts <link> stays
|
|
136
|
+
// as the framework-agnostic path.
|
|
135
137
|
const families = payload.document.foundations.typography.families;
|
|
136
138
|
const fontsHref = googleFontsHref(families);
|
|
137
|
-
|
|
139
|
+
const projectConfig = await readProjectConfig(projectRoot);
|
|
140
|
+
const nextFonts = projectConfig.target === "next"
|
|
141
|
+
? nextFontSnippet(families, payload.slug)
|
|
142
|
+
: null;
|
|
143
|
+
if (nextFonts) {
|
|
144
|
+
console.log("");
|
|
145
|
+
console.log(line("3. Load the type via next/font (recommended: self-hosted, preloaded, no font flash on refresh). Three small blocks:"));
|
|
146
|
+
console.log("");
|
|
147
|
+
console.log(snippet(nextFonts.fontsFile));
|
|
148
|
+
console.log("");
|
|
149
|
+
console.log(snippet(nextFonts.layout));
|
|
150
|
+
console.log("");
|
|
151
|
+
console.log(snippet(nextFonts.css));
|
|
152
|
+
if (fontsHref) {
|
|
153
|
+
console.log("");
|
|
154
|
+
console.log(line(` Quick alternative (works anywhere, may flash on cold loads): <link rel="stylesheet" href="${fontsHref}" /> in the <head>.`));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else if (fontsHref) {
|
|
138
158
|
console.log("");
|
|
139
159
|
console.log(line("3. Load the type - this system ships font NAMES, not the fonts. Add to your app's <head> (e.g. app/layout.tsx) so the families resolve (else they fall back and the look is lost):"));
|
|
140
160
|
console.log("");
|
package/dist/fonts.js
CHANGED
|
@@ -38,3 +38,52 @@ export function googleFontsHref(families) {
|
|
|
38
38
|
.join("&");
|
|
39
39
|
return `https://fonts.googleapis.com/css2?${query}&display=swap`;
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* The RECOMMENDED wiring for Next apps: `next/font` self-hosts the families
|
|
43
|
+
* (preloaded, size-adjusted fallbacks - no FOUT "blink" on refresh), and a
|
|
44
|
+
* small CSS block re-points the DS's family tokens to next/font's variables.
|
|
45
|
+
* Returns null when the doc only uses generic families. The naive
|
|
46
|
+
* `<link href="fonts.googleapis.com...">` stays as the framework-agnostic
|
|
47
|
+
* fallback - it works everywhere but swaps visibly on cold loads.
|
|
48
|
+
*/
|
|
49
|
+
export function nextFontSnippet(families, slug) {
|
|
50
|
+
const roles = ["display", "body", "mono"].filter((role) => {
|
|
51
|
+
const name = families[role]?.trim();
|
|
52
|
+
return name && !GENERIC_FAMILIES.has(name.toLowerCase());
|
|
53
|
+
});
|
|
54
|
+
if (roles.length === 0)
|
|
55
|
+
return null;
|
|
56
|
+
const importName = (name) => name.trim().replace(/ /g, "_");
|
|
57
|
+
const seen = new Map(); // family name -> const name
|
|
58
|
+
const importNames = [];
|
|
59
|
+
const consts = [];
|
|
60
|
+
for (const role of roles) {
|
|
61
|
+
const name = families[role].trim();
|
|
62
|
+
if (!seen.has(name)) {
|
|
63
|
+
seen.set(name, role);
|
|
64
|
+
importNames.push(importName(name));
|
|
65
|
+
consts.push(`export const ${seen.get(name)} = ${importName(name)}({`, ` subsets: ["latin"],`, ` variable: "--font-ds-${seen.get(name)}",`, `});`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const fontsFile = [
|
|
69
|
+
`// app/fonts.ts`,
|
|
70
|
+
`import { ${importNames.join(", ")} } from "next/font/google";`,
|
|
71
|
+
...consts,
|
|
72
|
+
];
|
|
73
|
+
const roleVar = (role) => {
|
|
74
|
+
const name = families[role].trim();
|
|
75
|
+
return `--font-ds-${seen.get(name)}`;
|
|
76
|
+
};
|
|
77
|
+
const layout = [
|
|
78
|
+
`// app/layout.tsx`,
|
|
79
|
+
`import { ${[...new Set(roles.map((r) => seen.get(families[r].trim())))].join(", ")} } from "./fonts";`,
|
|
80
|
+
`<body data-ds="${slug}" className={\`${[...new Set(roles.map((r) => `\${${seen.get(families[r].trim())}.variable}`))].join(" ")}\`}>`,
|
|
81
|
+
];
|
|
82
|
+
const css = [
|
|
83
|
+
`/* app/globals.css - AFTER the tokens.css import */`,
|
|
84
|
+
`[data-ds="${slug}"] {`,
|
|
85
|
+
...roles.map((role) => ` --ds-typography-families-${role}: var(${roleVar(role)});`),
|
|
86
|
+
`}`,
|
|
87
|
+
];
|
|
88
|
+
return { fontsFile, layout, css };
|
|
89
|
+
}
|