@archetypeai/ds-cli 0.3.16 → 0.3.18

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.
@@ -0,0 +1,212 @@
1
+ import { existsSync, readdirSync, copyFileSync, mkdirSync, writeFileSync } from 'fs';
2
+ import { join, resolve } from 'path';
3
+
4
+ // all 15 required font files
5
+ export const REQUIRED_FONTS = [
6
+ // PP Neue Montreal Sans (.ttf)
7
+ 'PPNeueMontreal-Thin.ttf',
8
+ 'PPNeueMontreal-ThinItalic.ttf',
9
+ 'PPNeueMontreal-Light.ttf',
10
+ 'PPNeueMontreal-Regular.ttf',
11
+ 'PPNeueMontreal-Italic.ttf',
12
+ 'PPNeueMontreal-Book.ttf',
13
+ 'PPNeueMontreal-Medium.ttf',
14
+ 'PPNeueMontreal-Bold.ttf',
15
+ 'PPNeueMontreal-BoldItalic.ttf',
16
+ // PP Neue Montreal Mono (.otf)
17
+ 'PPNeueMontrealMono-Thin.otf',
18
+ 'PPNeueMontrealMono-Regular.otf',
19
+ 'PPNeueMontrealMono-RegularItalic.otf',
20
+ 'PPNeueMontrealMono-Book.otf',
21
+ 'PPNeueMontrealMono-Medium.otf',
22
+ 'PPNeueMontrealMono-Bold.otf'
23
+ ];
24
+
25
+ // hardcoded fonts.css template
26
+ export const FONTS_CSS = `/* PP Neue Montreal Sans*/
27
+
28
+ @font-face {
29
+ font-family: 'PP Neue Montreal';
30
+ src: url('/fonts/PPNeueMontreal-Thin.ttf') format('truetype');
31
+ font-weight: 100;
32
+ font-style: normal;
33
+ font-display: swap;
34
+ }
35
+
36
+ @font-face {
37
+ font-family: 'PP Neue Montreal';
38
+ src: url('/fonts/PPNeueMontreal-ThinItalic.ttf') format('truetype');
39
+ font-weight: 100;
40
+ font-style: italic;
41
+ font-display: swap;
42
+ }
43
+
44
+ @font-face {
45
+ font-family: 'PP Neue Montreal';
46
+ src: url('/fonts/PPNeueMontreal-Light.ttf') format('truetype');
47
+ font-weight: 300;
48
+ font-style: normal;
49
+ font-display: swap;
50
+ }
51
+
52
+ @font-face {
53
+ font-family: 'PP Neue Montreal';
54
+ src: url('/fonts/PPNeueMontreal-Regular.ttf') format('truetype');
55
+ font-weight: 400;
56
+ font-style: normal;
57
+ font-display: swap;
58
+ }
59
+
60
+ @font-face {
61
+ font-family: 'PP Neue Montreal';
62
+ src: url('/fonts/PPNeueMontreal-Italic.ttf') format('truetype');
63
+ font-weight: 400;
64
+ font-style: italic;
65
+ font-display: swap;
66
+ }
67
+
68
+ @font-face {
69
+ font-family: 'PP Neue Montreal';
70
+ src: url('/fonts/PPNeueMontreal-Book.ttf') format('truetype');
71
+ font-weight: 400;
72
+ font-style: normal;
73
+ font-display: swap;
74
+ }
75
+
76
+ @font-face {
77
+ font-family: 'PP Neue Montreal';
78
+ src: url('/fonts/PPNeueMontreal-Medium.ttf') format('truetype');
79
+ font-weight: 500;
80
+ font-style: normal;
81
+ font-display: swap;
82
+ }
83
+
84
+ @font-face {
85
+ font-family: 'PP Neue Montreal';
86
+ src: url('/fonts/PPNeueMontreal-Bold.ttf') format('truetype');
87
+ font-weight: 700;
88
+ font-style: normal;
89
+ font-display: swap;
90
+ }
91
+
92
+ @font-face {
93
+ font-family: 'PP Neue Montreal';
94
+ src: url('/fonts/PPNeueMontreal-BoldItalic.ttf') format('truetype');
95
+ font-weight: 700;
96
+ font-style: italic;
97
+ font-display: swap;
98
+ }
99
+
100
+ /* PP Neue Montreal Mono */
101
+
102
+ @font-face {
103
+ font-family: 'PP Neue Montreal Mono';
104
+ src: url('/fonts/PPNeueMontrealMono-Thin.otf') format('opentype');
105
+ font-weight: 100;
106
+ font-style: normal;
107
+ font-display: swap;
108
+ }
109
+
110
+ @font-face {
111
+ font-family: 'PP Neue Montreal Mono';
112
+ src: url('/fonts/PPNeueMontrealMono-Regular.otf') format('opentype');
113
+ font-weight: 400;
114
+ font-style: normal;
115
+ font-display: swap;
116
+ }
117
+
118
+ @font-face {
119
+ font-family: 'PP Neue Montreal Mono';
120
+ src: url('/fonts/PPNeueMontrealMono-RegularItalic.otf') format('opentype');
121
+ font-weight: 400;
122
+ font-style: italic;
123
+ font-display: swap;
124
+ }
125
+
126
+ @font-face {
127
+ font-family: 'PP Neue Montreal Mono';
128
+ src: url('/fonts/PPNeueMontrealMono-Book.otf') format('opentype');
129
+ font-weight: 400;
130
+ font-style: normal;
131
+ font-display: swap;
132
+ }
133
+
134
+ @font-face {
135
+ font-family: 'PP Neue Montreal Mono';
136
+ src: url('/fonts/PPNeueMontrealMono-Medium.otf') format('opentype');
137
+ font-weight: 500;
138
+ font-style: normal;
139
+ font-display: swap;
140
+ }
141
+
142
+ @font-face {
143
+ font-family: 'PP Neue Montreal Mono';
144
+ src: url('/fonts/PPNeueMontrealMono-Bold.otf') format('opentype');
145
+ font-weight: 700;
146
+ font-style: normal;
147
+ font-display: swap;
148
+ }
149
+ `;
150
+
151
+ // validate that a directory contains all required font files
152
+ export function validateFontsPath(fontsPath) {
153
+ const resolved = resolve(fontsPath);
154
+
155
+ if (!existsSync(resolved)) {
156
+ return { valid: false, missing: REQUIRED_FONTS, error: `Path does not exist: ${resolved}` };
157
+ }
158
+
159
+ let entries;
160
+ try {
161
+ entries = readdirSync(resolved);
162
+ } catch {
163
+ return { valid: false, missing: REQUIRED_FONTS, error: `Cannot read directory: ${resolved}` };
164
+ }
165
+
166
+ const missing = REQUIRED_FONTS.filter((f) => !entries.includes(f));
167
+ if (missing.length > 0) {
168
+ return {
169
+ valid: false,
170
+ missing,
171
+ error: `Missing ${missing.length} font file(s): ${missing.join(', ')}`
172
+ };
173
+ }
174
+
175
+ return { valid: true, missing: [] };
176
+ }
177
+
178
+ // copy required font files to <project>/static/fonts/
179
+ export function copyFontsToStatic(fontsPath, projectPath) {
180
+ const src = resolve(fontsPath);
181
+ const dest = join(projectPath, 'static', 'fonts');
182
+ mkdirSync(dest, { recursive: true });
183
+
184
+ for (const file of REQUIRED_FONTS) {
185
+ copyFileSync(join(src, file), join(dest, file));
186
+ }
187
+
188
+ return REQUIRED_FONTS.length;
189
+ }
190
+
191
+ // write fonts.css to src/routes/fonts.css
192
+ function writeFontsCss(projectPath) {
193
+ const cssPath = join(projectPath, 'src', 'routes', 'fonts.css');
194
+ const dir = join(projectPath, 'src', 'routes');
195
+ if (!existsSync(dir)) {
196
+ mkdirSync(dir, { recursive: true });
197
+ }
198
+ writeFileSync(cssPath, FONTS_CSS);
199
+ }
200
+
201
+ // orchestrate: validate, copy fonts, write fonts.css
202
+ export function installLocalFonts(fontsPath, projectPath) {
203
+ const validation = validateFontsPath(fontsPath);
204
+ if (!validation.valid) {
205
+ return { success: false, fileCount: 0, error: validation.error };
206
+ }
207
+
208
+ const fileCount = copyFontsToStatic(fontsPath, projectPath);
209
+ writeFontsCss(projectPath);
210
+
211
+ return { success: true, fileCount };
212
+ }
@@ -1,5 +1,3 @@
1
- import * as p from '@clack/prompts';
2
-
3
1
  export const DEFAULTS = {
4
2
  framework: 'svelte',
5
3
  pm: 'npm',
@@ -10,10 +8,3 @@ export function isInteractive(flags) {
10
8
  if (flags.defaults) return false;
11
9
  return !!process.stdin.isTTY;
12
10
  }
13
-
14
- export function logDefaultsNotice(applied) {
15
- const parts = Object.entries(applied).map(([k, v]) => `${k}=${v}`);
16
- if (parts.length > 0) {
17
- p.log.info(`Non-interactive mode: using defaults (${parts.join(', ')})`);
18
- }
19
- }
@@ -88,23 +88,6 @@ export async function installTokens(pm, projectPath) {
88
88
  }
89
89
  }
90
90
 
91
- // install internal fonts package
92
- export async function installFonts(pm, projectPath) {
93
- const [cmd, ...baseArgs] = splitCmd(pm.install);
94
- const args = [...baseArgs, '@archetypeai/ds-lib-fonts-internal'];
95
- const s = p.spinner();
96
- s.start('Installing internal fonts');
97
- try {
98
- await run(cmd, args, { cwd: projectPath });
99
- s.stop('Internal fonts installed');
100
- return true;
101
- } catch {
102
- s.stop('Failed to install internal fonts');
103
- p.log.warn('Make sure you are authenticated with npm (run: npm login)');
104
- return false;
105
- }
106
- }
107
-
108
91
  // init shadcn-svelte
109
92
  export async function initShadcn(pm, projectPath) {
110
93
  const s = p.spinner();
@@ -166,7 +149,7 @@ export function cn(...inputs) {
166
149
  export function configureCss(projectPath, includeFonts) {
167
150
  let css = '';
168
151
  if (includeFonts) {
169
- css += '@import "@archetypeai/ds-lib-fonts-internal";\n';
152
+ css += '@import "./fonts.css";\n';
170
153
  }
171
154
  css += '@import "@archetypeai/ds-lib-tokens/theme.css";\n';
172
155
  css += '@import "tailwindcss";\n';
@@ -211,7 +194,7 @@ export function prependCss(projectPath, includeFonts) {
211
194
 
212
195
  let imports = '';
213
196
  if (includeFonts) {
214
- imports += '@import "@archetypeai/ds-lib-fonts-internal";\n';
197
+ imports += '@import "./fonts.css";\n';
215
198
  }
216
199
  imports += '@import "@archetypeai/ds-lib-tokens/theme.css";\n';
217
200
  imports += '@import "tailwindcss";\n';
@@ -256,20 +239,40 @@ export async function installComponents(pm, projectPath, componentUrls) {
256
239
  }
257
240
  }
258
241
 
259
- // add a demo page with Button examples to app
242
+ // add a demo page with design system examples to app
260
243
  export function createDemoPage(projectPath) {
261
244
  const pagePath = join(projectPath, 'src/routes/+page.svelte');
262
245
  const demoContent = `<script>
263
- \timport Button from "$lib/components/ui/primitives/button/button.svelte";
246
+ \timport Menubar from '$lib/components/ui/patterns/menubar/index.js';
247
+ \timport { Button } from '$lib/components/ui/primitives/button/index.js';
248
+ \timport BackgroundCard from '$lib/components/ui/patterns/background-card/index.js';
249
+ \timport ActivityIcon from '@lucide/svelte/icons/activity';
250
+ \timport CpuIcon from '@lucide/svelte/icons/cpu';
251
+ \timport GaugeIcon from '@lucide/svelte/icons/gauge';
252
+ \timport ThermometerIcon from '@lucide/svelte/icons/thermometer';
264
253
  </script>
265
254
 
266
- <div class="flex flex-col items-center justify-center min-h-screen space-y-xl">
267
- <Button variant="default">Default</Button>
268
- <Button variant="ghost">Ghost</Button>
269
- <Button variant="outline">Outline</Button>
270
- <Button variant="secondary">Secondary</Button>
271
- <Button variant="destructive">Destructive</Button>
272
- <Button variant="link">Link</Button>
255
+ <div
256
+ \tclass="bg-background text-foreground grid h-screen w-screen grid-rows-[auto_1fr] overflow-hidden"
257
+ >
258
+ \t<Menubar>
259
+ \t\t<Button variant="link" class="text-muted-foreground">Send Report</Button>
260
+ \t</Menubar>
261
+
262
+ \t<main class="grid grid-cols-2 grid-rows-2 gap-4 overflow-hidden p-4">
263
+ \t\t<BackgroundCard title="Panel 1" icon={ActivityIcon} class="max-h-full">
264
+ \t\t\t<p class="text-muted-foreground text-sm">Placeholder content</p>
265
+ \t\t</BackgroundCard>
266
+ \t\t<BackgroundCard title="Panel 2" icon={CpuIcon} class="max-h-full">
267
+ \t\t\t<p class="text-muted-foreground text-sm">Placeholder content</p>
268
+ \t\t</BackgroundCard>
269
+ \t\t<BackgroundCard title="Panel 3" icon={GaugeIcon} class="max-h-full">
270
+ \t\t\t<p class="text-muted-foreground text-sm">Placeholder content</p>
271
+ \t\t</BackgroundCard>
272
+ \t\t<BackgroundCard title="Panel 4" icon={ThermometerIcon} class="max-h-full">
273
+ \t\t\t<p class="text-muted-foreground text-sm">Placeholder content</p>
274
+ \t\t</BackgroundCard>
275
+ \t</main>
273
276
  </div>
274
277
  `;
275
278
  writeFile(pagePath, demoContent);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archetypeai/ds-cli",
3
- "version": "0.3.16",
3
+ "version": "0.3.18",
4
4
  "description": "Archetype AI Design System CLI Tool",
5
5
  "type": "module",
6
6
  "bin": {