astrotype 0.1.4 → 0.1.6
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/cli/commands/add.mjs +57 -2
- package/cli/lib/add-utils.mjs +75 -7
- package/package.json +1 -1
package/cli/commands/add.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { getFontByName, getPairingByName } from "../lib/registry.mjs";
|
|
2
|
+
import { getAllPairings, getFontByName, getPairingByName } from "../lib/registry.mjs";
|
|
3
3
|
import {
|
|
4
|
+
activatePairingCssImport,
|
|
4
5
|
ensureAstroFontsApiSetup,
|
|
5
6
|
isAstroProject,
|
|
6
7
|
writeAstrotypeCss,
|
|
@@ -17,6 +18,52 @@ function toCssRules(ruleMap) {
|
|
|
17
18
|
.join("\n\n");
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
function fontFamilyFallback(font) {
|
|
22
|
+
const raw =
|
|
23
|
+
font?.font?.provider === "google"
|
|
24
|
+
? String(font?.font?.family || font?.title || "")
|
|
25
|
+
: String(font?.title || "");
|
|
26
|
+
const normalized = raw.replace(/ Variable$/, "").replace(/"/g, '\\"');
|
|
27
|
+
return `"${normalized}"`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function withPairingFontFallbacks(pairing, fonts) {
|
|
31
|
+
const headingFont = fonts[0];
|
|
32
|
+
const bodyFont = fonts[1];
|
|
33
|
+
const monoFont = fonts[2];
|
|
34
|
+
const css = JSON.parse(JSON.stringify(pairing.css || {}));
|
|
35
|
+
const root = { ...css[":root"] };
|
|
36
|
+
|
|
37
|
+
if (headingFont) {
|
|
38
|
+
const variable = headingFont.font?.variable || "--font-heading";
|
|
39
|
+
root["--font-heading"] = `var(${variable}, ${fontFamilyFallback(headingFont)})`;
|
|
40
|
+
}
|
|
41
|
+
if (bodyFont) {
|
|
42
|
+
const variable = bodyFont.font?.variable || "--font-body";
|
|
43
|
+
root["--font-body"] = `var(${variable}, ${fontFamilyFallback(bodyFont)})`;
|
|
44
|
+
}
|
|
45
|
+
if (monoFont) {
|
|
46
|
+
const variable = monoFont.font?.variable || "--font-mono";
|
|
47
|
+
root["--font-mono"] = `var(${variable}, ${fontFamilyFallback(monoFont)})`;
|
|
48
|
+
}
|
|
49
|
+
css[":root"] = root;
|
|
50
|
+
return css;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function toUtilityClassRules() {
|
|
54
|
+
return `.font-heading {
|
|
55
|
+
font-family: var(--font-heading);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.font-body {
|
|
59
|
+
font-family: var(--font-body);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.font-mono {
|
|
63
|
+
font-family: var(--font-mono);
|
|
64
|
+
}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
20
67
|
export async function addPairingCommand(pairingName, options = {}) {
|
|
21
68
|
const targetDir = path.resolve(options.cwd || process.cwd());
|
|
22
69
|
if (!isAstroProject(targetDir)) {
|
|
@@ -40,12 +87,20 @@ export async function addPairingCommand(pairingName, options = {}) {
|
|
|
40
87
|
process.exit(1);
|
|
41
88
|
}
|
|
42
89
|
|
|
43
|
-
const
|
|
90
|
+
const cssRulesWithFallbacks = withPairingFontFallbacks(pairing, fonts);
|
|
91
|
+
const cssText = `${toCssRules(cssRulesWithFallbacks)}
|
|
92
|
+
|
|
93
|
+
${toUtilityClassRules()}
|
|
44
94
|
`;
|
|
45
95
|
const pairingCssPath = writeAstrotypeCss(targetDir, pairing.name, cssText);
|
|
96
|
+
const pairingSlugs = getAllPairings().map((item) => item.name).filter(Boolean);
|
|
97
|
+
const importUpdate = activatePairingCssImport(targetDir, pairing.name, pairingSlugs);
|
|
46
98
|
const fontsSetup = ensureAstroFontsApiSetup(targetDir, fonts);
|
|
47
99
|
|
|
48
100
|
console.log(`Installed pairing "${pairing.name}" -> ${path.relative(targetDir, pairingCssPath)}`);
|
|
101
|
+
if (importUpdate.removed.length > 0) {
|
|
102
|
+
console.log(`Switched active pairing import (removed: ${importUpdate.removed.join(", ")}).`);
|
|
103
|
+
}
|
|
49
104
|
if (fontsSetup.configured) {
|
|
50
105
|
console.log("Wired Astro Fonts API entries for this pairing.");
|
|
51
106
|
if (fontsSetup.manualMergeRequired) {
|
package/cli/lib/add-utils.mjs
CHANGED
|
@@ -38,10 +38,14 @@ function toAstroFontDescriptor(font) {
|
|
|
38
38
|
if (provider === "npm") {
|
|
39
39
|
const npmPackage = font.font.npmPackage || font.font.package;
|
|
40
40
|
if (!npmPackage) return null;
|
|
41
|
-
let file = null;
|
|
42
41
|
if (npmPackage === "geist") {
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
return {
|
|
43
|
+
name: font.name,
|
|
44
|
+
familyName: font.name === "geist-mono" ? "Geist Mono" : "Geist",
|
|
45
|
+
cssVariable,
|
|
46
|
+
provider: "google",
|
|
47
|
+
options: null,
|
|
48
|
+
};
|
|
45
49
|
}
|
|
46
50
|
return {
|
|
47
51
|
name: font.name,
|
|
@@ -50,7 +54,6 @@ function toAstroFontDescriptor(font) {
|
|
|
50
54
|
provider: "npm",
|
|
51
55
|
options: {
|
|
52
56
|
package: npmPackage,
|
|
53
|
-
...(file ? { file } : {}),
|
|
54
57
|
},
|
|
55
58
|
};
|
|
56
59
|
}
|
|
@@ -58,11 +61,15 @@ function toAstroFontDescriptor(font) {
|
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
function serializeAstroFontDescriptor(descriptor) {
|
|
64
|
+
const providerCall =
|
|
65
|
+
descriptor.provider === "npm"
|
|
66
|
+
? 'fontProviders.npm({ cdn: "https://cdn.jsdelivr.net/npm/" })'
|
|
67
|
+
: `fontProviders.${descriptor.provider}()`;
|
|
61
68
|
const optionsLine = descriptor.options
|
|
62
69
|
? `,\n options: ${JSON.stringify(descriptor.options)}`
|
|
63
70
|
: "";
|
|
64
71
|
return ` {
|
|
65
|
-
provider:
|
|
72
|
+
provider: ${providerCall},
|
|
66
73
|
name: ${JSON.stringify(descriptor.familyName)},
|
|
67
74
|
cssVariable: ${JSON.stringify(descriptor.cssVariable)}${optionsLine}
|
|
68
75
|
}`;
|
|
@@ -150,18 +157,29 @@ ${lines}
|
|
|
150
157
|
configText = ensureAstroConfigHasAstrotypeImport(configText);
|
|
151
158
|
const result = ensureAstroConfigHasFontsProperty(configText);
|
|
152
159
|
fs.writeFileSync(astroConfigPath, result.text);
|
|
160
|
+
const isAlreadyWired = /\bfonts\s*:\s*astrotypeFonts\b/.test(result.text);
|
|
153
161
|
|
|
154
162
|
return {
|
|
155
163
|
configured: true,
|
|
156
164
|
configPath: astroConfigPath,
|
|
157
|
-
manualMergeRequired: !result.injected && /\bfonts\s*:/.test(configText),
|
|
165
|
+
manualMergeRequired: !result.injected && !isAlreadyWired && /\bfonts\s*:/.test(configText),
|
|
158
166
|
};
|
|
159
167
|
}
|
|
160
168
|
|
|
161
169
|
export function ensureImport(globalCssPath, importLine) {
|
|
162
170
|
const css = fs.existsSync(globalCssPath) ? fs.readFileSync(globalCssPath, "utf-8") : "";
|
|
163
171
|
if (css.includes(importLine)) return;
|
|
164
|
-
|
|
172
|
+
const lines = css.split(/\r?\n/);
|
|
173
|
+
let lastImportIndex = -1;
|
|
174
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
175
|
+
if (/^\s*@import\s+/.test(lines[index])) lastImportIndex = index;
|
|
176
|
+
}
|
|
177
|
+
if (lastImportIndex === -1) {
|
|
178
|
+
fs.writeFileSync(globalCssPath, `${importLine}\n${css}`);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
lines.splice(lastImportIndex + 1, 0, importLine);
|
|
182
|
+
fs.writeFileSync(globalCssPath, `${lines.join("\n")}\n`);
|
|
165
183
|
}
|
|
166
184
|
|
|
167
185
|
export function writeAstrotypeCss(targetDir, slug, cssText) {
|
|
@@ -175,3 +193,53 @@ export function writeAstrotypeCss(targetDir, slug, cssText) {
|
|
|
175
193
|
ensureImport(globalCssPath, `@import "./astrotypes/${slug}.css";`);
|
|
176
194
|
return cssPath;
|
|
177
195
|
}
|
|
196
|
+
|
|
197
|
+
export function activatePairingCssImport(targetDir, activePairingSlug, pairingSlugs) {
|
|
198
|
+
const globalCssPath = path.join(targetDir, "src", "styles", "global.css");
|
|
199
|
+
ensureDir(path.dirname(globalCssPath));
|
|
200
|
+
const importLine = `@import "./astrotypes/${activePairingSlug}.css";`;
|
|
201
|
+
const knownPairings = new Set(pairingSlugs || []);
|
|
202
|
+
|
|
203
|
+
if (!fs.existsSync(globalCssPath)) {
|
|
204
|
+
fs.writeFileSync(globalCssPath, `${importLine}\n`);
|
|
205
|
+
return { removed: [], added: true };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const css = fs.readFileSync(globalCssPath, "utf-8");
|
|
209
|
+
const lines = css.split(/\r?\n/);
|
|
210
|
+
const keptLines = [];
|
|
211
|
+
const removed = [];
|
|
212
|
+
let hasActive = false;
|
|
213
|
+
|
|
214
|
+
for (const line of lines) {
|
|
215
|
+
const match = line.match(
|
|
216
|
+
/^\s*@import\s+["']\.\/astrotypes\/([a-z0-9-]+)\.css["'];\s*$/
|
|
217
|
+
);
|
|
218
|
+
if (!match) {
|
|
219
|
+
keptLines.push(line);
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
const slug = match[1];
|
|
223
|
+
if (slug === activePairingSlug) {
|
|
224
|
+
hasActive = true;
|
|
225
|
+
keptLines.push(importLine);
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (knownPairings.has(slug)) {
|
|
229
|
+
removed.push(slug);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
keptLines.push(line);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (!hasActive) {
|
|
236
|
+
let lastImportIndex = -1;
|
|
237
|
+
for (let index = 0; index < keptLines.length; index += 1) {
|
|
238
|
+
if (/^\s*@import\s+/.test(keptLines[index])) lastImportIndex = index;
|
|
239
|
+
}
|
|
240
|
+
if (lastImportIndex === -1) keptLines.unshift(importLine);
|
|
241
|
+
else keptLines.splice(lastImportIndex + 1, 0, importLine);
|
|
242
|
+
}
|
|
243
|
+
fs.writeFileSync(globalCssPath, `${keptLines.join("\n")}\n`);
|
|
244
|
+
return { removed, added: !hasActive };
|
|
245
|
+
}
|