stera-ui 0.6.0 → 0.7.0

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.
@@ -255,43 +255,15 @@ function detectAliasPrefix(cwd) {
255
255
  return first ? first.replace(/\/\*$/, "") : null;
256
256
  }
257
257
 
258
- // src/utils/write-stera-css.ts
259
- import fs3 from "fs/promises";
260
- import path4 from "path";
261
- function stripImportLines(content) {
262
- const lines = content.split("\n");
263
- const imports = [];
264
- const kept = [];
265
- for (const line of lines) {
266
- if (line.trim().match(/^@import\s+["'].+["']/)) {
267
- if (!line.trim().match(/^@import\s+["']tailwindcss["']/)) {
268
- imports.push(line.trim());
269
- }
270
- } else {
271
- kept.push(line);
272
- }
273
- }
274
- return { content: kept.join("\n"), imports };
275
- }
276
- async function writeSteraUiCss(config, cwd) {
277
- const item = await fetchRegistryItem("globals");
278
- const rawContent = item.files?.[0]?.content ?? "";
279
- const { content, imports } = stripImportLines(rawContent);
280
- const cssDir = path4.dirname(path4.resolve(cwd, config.css));
281
- const steraUiPath = path4.join(cssDir, "stera-ui.css");
282
- await fs3.mkdir(cssDir, { recursive: true });
283
- await fs3.writeFile(steraUiPath, content, "utf-8");
284
- return {
285
- steraUiPath,
286
- extraImports: imports,
287
- dependencies: item.dependencies ?? []
288
- };
289
- }
258
+ // src/utils/write-styles.ts
259
+ import fs6 from "fs/promises";
260
+ import { existsSync } from "fs";
261
+ import path5 from "path";
290
262
 
291
263
  // src/utils/css-imports.ts
292
- import fs4 from "fs/promises";
264
+ import fs3 from "fs/promises";
293
265
  async function insertImportLine(filePath, importStatement) {
294
- const content = await fs4.readFile(filePath, "utf-8");
266
+ const content = await fs3.readFile(filePath, "utf-8");
295
267
  const importPath = importStatement.match(/["']([^"']+)["']/)?.[1];
296
268
  if (importPath) {
297
269
  const escaped = importPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -309,12 +281,147 @@ async function insertImportLine(filePath, importStatement) {
309
281
  } else {
310
282
  lines.unshift(importStatement);
311
283
  }
312
- await fs4.writeFile(filePath, lines.join("\n"), "utf-8");
284
+ await fs3.writeFile(filePath, lines.join("\n"), "utf-8");
313
285
  }
314
286
 
315
- // src/utils/install-deps.ts
287
+ // src/utils/patch-css-vars.ts
288
+ import fs4 from "fs";
289
+ function removeCssImport(filePath, importPath) {
290
+ const content = fs4.readFileSync(filePath, "utf-8");
291
+ const pattern = new RegExp(
292
+ `@import\\s+['"]${escapeRegex(importPath)}['"]\\s*;?\\n?`
293
+ );
294
+ if (!pattern.test(content)) return false;
295
+ fs4.writeFileSync(filePath, content.replace(pattern, ""), "utf-8");
296
+ return true;
297
+ }
298
+ function escapeRegex(str) {
299
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
300
+ }
301
+
302
+ // src/utils/write-files.ts
316
303
  import fs5 from "fs";
317
- import path5 from "path";
304
+ import path4 from "path";
305
+ import { confirm } from "@inquirer/prompts";
306
+ async function confirmOverwrite(relativePath) {
307
+ if (!process.stdin.isTTY) {
308
+ console.log(
309
+ ` Skipping ${relativePath} (already exists, use --overwrite to replace)`
310
+ );
311
+ return false;
312
+ }
313
+ return confirm({
314
+ message: `${relativePath} already exists. Overwrite?`,
315
+ default: false
316
+ });
317
+ }
318
+ async function writeComponentFiles(items, config, projectRoot, options = {}) {
319
+ const written = [];
320
+ const skipped = [];
321
+ for (const item of items) {
322
+ for (const file of item.files ?? []) {
323
+ const outputPath = resolveOutputPath(config, projectRoot, file);
324
+ const relativePath = path4.relative(projectRoot, outputPath);
325
+ if (fs5.existsSync(outputPath)) {
326
+ const existing = fs5.readFileSync(outputPath, "utf-8");
327
+ if (existing === file.content) {
328
+ skipped.push({ path: relativePath, reason: "unchanged" });
329
+ continue;
330
+ }
331
+ if (!options.overwrite) {
332
+ const confirmed = await confirmOverwrite(relativePath);
333
+ if (!confirmed) {
334
+ skipped.push({ path: relativePath, reason: "declined" });
335
+ continue;
336
+ }
337
+ }
338
+ }
339
+ const dir = path4.dirname(outputPath);
340
+ fs5.mkdirSync(dir, { recursive: true });
341
+ fs5.writeFileSync(outputPath, file.content ?? "", "utf-8");
342
+ written.push(relativePath);
343
+ }
344
+ }
345
+ return { written, skipped };
346
+ }
347
+
348
+ // src/utils/write-styles.ts
349
+ var INDEX_TARGET = "ui/index.css";
350
+ var TYPOGRAPHY_TARGET = "ui/typography.css";
351
+ var PROTECTED_TARGETS = /* @__PURE__ */ new Set([TYPOGRAPHY_TARGET, "ui/colors.css"]);
352
+ var LEGACY_FILENAME = "stera-ui.css";
353
+ var LEGACY_IMPORT = "./stera-ui.css";
354
+ function partitionImports(content) {
355
+ const lines = content.split("\n");
356
+ const hoisted = [];
357
+ const kept = [];
358
+ for (const line of lines) {
359
+ const specifier = line.trim().match(/^@import\s+["'](.+?)["']/)?.[1];
360
+ if (specifier === void 0) {
361
+ kept.push(line);
362
+ } else if (specifier.startsWith("./") || specifier.startsWith("../")) {
363
+ kept.push(line);
364
+ } else if (specifier !== "tailwindcss") {
365
+ hoisted.push(line.trim());
366
+ }
367
+ }
368
+ const cleaned = kept.join("\n").replace(/\n{3,}/g, "\n\n").replace(/^\n+/, "");
369
+ return { content: cleaned, hoisted };
370
+ }
371
+ async function migrateLegacyStyles(config, cwd) {
372
+ const globalsPath = path5.resolve(cwd, config.css);
373
+ const legacyPath = path5.join(path5.dirname(globalsPath), LEGACY_FILENAME);
374
+ if (!existsSync(legacyPath)) return null;
375
+ await fs6.rm(legacyPath);
376
+ if (existsSync(globalsPath)) {
377
+ removeCssImport(globalsPath, LEGACY_IMPORT);
378
+ await insertImportLine(globalsPath, `@import "./${INDEX_TARGET}";`);
379
+ }
380
+ return legacyPath;
381
+ }
382
+ async function writeStyles(config, cwd, options = {}) {
383
+ const item = await fetchRegistryItem("globals");
384
+ const cssDir = path5.dirname(path5.resolve(cwd, config.css));
385
+ const written = [];
386
+ const skipped = [];
387
+ let extraImports = [];
388
+ for (const file of item.files ?? []) {
389
+ const target = file.target ?? path5.basename(file.path);
390
+ const outputPath = path5.join(cssDir, target);
391
+ let content = file.content ?? "";
392
+ if (target === INDEX_TARGET) {
393
+ const partitioned = partitionImports(content);
394
+ content = partitioned.content;
395
+ extraImports = partitioned.hoisted;
396
+ }
397
+ if (PROTECTED_TARGETS.has(target) && existsSync(outputPath)) {
398
+ const existing = await fs6.readFile(outputPath, "utf-8");
399
+ if (existing === content) {
400
+ skipped.push({ path: target, reason: "unchanged" });
401
+ continue;
402
+ }
403
+ if (!options.overwrite && !await confirmOverwrite(target)) {
404
+ skipped.push({ path: target, reason: "declined" });
405
+ continue;
406
+ }
407
+ }
408
+ await fs6.mkdir(path5.dirname(outputPath), { recursive: true });
409
+ await fs6.writeFile(outputPath, content, "utf-8");
410
+ written.push(target);
411
+ }
412
+ return {
413
+ indexPath: path5.join(cssDir, INDEX_TARGET),
414
+ typographyPath: path5.join(cssDir, TYPOGRAPHY_TARGET),
415
+ extraImports,
416
+ dependencies: item.dependencies ?? [],
417
+ written,
418
+ skipped
419
+ };
420
+ }
421
+
422
+ // src/utils/install-deps.ts
423
+ import fs7 from "fs";
424
+ import path6 from "path";
318
425
  import { detect } from "@antfu/ni";
319
426
  import { execa } from "execa";
320
427
 
@@ -400,11 +507,11 @@ function getInstallArgs(pm, deps) {
400
507
  }
401
508
  async function installDependencies(deps, cwd) {
402
509
  if (deps.length === 0) return;
403
- const pkgPath = path5.join(cwd, "package.json");
510
+ const pkgPath = path6.join(cwd, "package.json");
404
511
  let existing = /* @__PURE__ */ new Set();
405
- if (fs5.existsSync(pkgPath)) {
512
+ if (fs7.existsSync(pkgPath)) {
406
513
  try {
407
- const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
514
+ const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
408
515
  existing = new Set(
409
516
  Object.keys({ ...pkg.dependencies, ...pkg.devDependencies })
410
517
  );
@@ -432,54 +539,8 @@ or use "pnpm add -w <package>" manually to install at the root.`
432
539
  }
433
540
  }
434
541
 
435
- // src/utils/write-files.ts
436
- import fs6 from "fs";
437
- import path6 from "path";
438
- import { confirm } from "@inquirer/prompts";
439
- async function confirmOverwrite(relativePath) {
440
- if (!process.stdin.isTTY) {
441
- console.log(
442
- ` Skipping ${relativePath} (already exists, use --overwrite to replace)`
443
- );
444
- return false;
445
- }
446
- return confirm({
447
- message: `${relativePath} already exists. Overwrite?`,
448
- default: false
449
- });
450
- }
451
- async function writeComponentFiles(items, config, projectRoot, options = {}) {
452
- const written = [];
453
- const skipped = [];
454
- for (const item of items) {
455
- for (const file of item.files ?? []) {
456
- const outputPath = resolveOutputPath(config, projectRoot, file);
457
- const relativePath = path6.relative(projectRoot, outputPath);
458
- if (fs6.existsSync(outputPath)) {
459
- const existing = fs6.readFileSync(outputPath, "utf-8");
460
- if (existing === file.content) {
461
- skipped.push({ path: relativePath, reason: "unchanged" });
462
- continue;
463
- }
464
- if (!options.overwrite) {
465
- const confirmed = await confirmOverwrite(relativePath);
466
- if (!confirmed) {
467
- skipped.push({ path: relativePath, reason: "declined" });
468
- continue;
469
- }
470
- }
471
- }
472
- const dir = path6.dirname(outputPath);
473
- fs6.mkdirSync(dir, { recursive: true });
474
- fs6.writeFileSync(outputPath, file.content ?? "", "utf-8");
475
- written.push(relativePath);
476
- }
477
- }
478
- return { written, skipped };
479
- }
480
-
481
542
  // src/utils/update-fonts.ts
482
- import { existsSync, promises as fs7 } from "fs";
543
+ import { existsSync as existsSync2, promises as fs8 } from "fs";
483
544
  import path7 from "path";
484
545
  import {
485
546
  Project,
@@ -520,10 +581,10 @@ async function updateFonts(fonts, project, cwd, options = {}) {
520
581
  if (!layoutPath) return;
521
582
  if (options.silent) {
522
583
  try {
523
- const layoutContent = await fs7.readFile(layoutPath, "utf-8");
584
+ const layoutContent = await fs8.readFile(layoutPath, "utf-8");
524
585
  const updatedContent = transformLayoutFonts(layoutContent, fonts);
525
586
  if (updatedContent !== layoutContent) {
526
- await fs7.writeFile(layoutPath, updatedContent, "utf-8");
587
+ await fs8.writeFile(layoutPath, updatedContent, "utf-8");
527
588
  }
528
589
  } catch {
529
590
  }
@@ -531,10 +592,10 @@ async function updateFonts(fonts, project, cwd, options = {}) {
531
592
  }
532
593
  const spinner = createSpinner("Updating fonts");
533
594
  try {
534
- const layoutContent = await fs7.readFile(layoutPath, "utf-8");
595
+ const layoutContent = await fs8.readFile(layoutPath, "utf-8");
535
596
  const updatedContent = transformLayoutFonts(layoutContent, fonts);
536
597
  if (updatedContent !== layoutContent) {
537
- await fs7.writeFile(layoutPath, updatedContent, "utf-8");
598
+ await fs8.writeFile(layoutPath, updatedContent, "utf-8");
538
599
  }
539
600
  spinner.succeed("Updated layout with font imports");
540
601
  } catch {
@@ -544,7 +605,7 @@ async function updateFonts(fonts, project, cwd, options = {}) {
544
605
  function findLayoutFile(project, cwd) {
545
606
  if (!project.layoutFile) return null;
546
607
  const fullPath = path7.join(cwd, project.layoutFile);
547
- return existsSync(fullPath) ? fullPath : null;
608
+ return existsSync2(fullPath) ? fullPath : null;
548
609
  }
549
610
  function transformLayoutFonts(input, fonts) {
550
611
  const project = new Project({ compilerOptions: {} });
@@ -799,8 +860,12 @@ export {
799
860
  loadConfig2 as loadConfig,
800
861
  detectProject,
801
862
  detectAliasPrefix,
802
- writeSteraUiCss,
803
863
  insertImportLine,
864
+ writeComponentFiles,
865
+ INDEX_TARGET,
866
+ TYPOGRAPHY_TARGET,
867
+ migrateLegacyStyles,
868
+ writeStyles,
804
869
  brand,
805
870
  dim,
806
871
  LOGO,
@@ -810,7 +875,6 @@ export {
810
875
  createSpinner,
811
876
  detectPackageManager,
812
877
  installDependencies,
813
- writeComponentFiles,
814
878
  massageTreeForFonts,
815
879
  updateFonts
816
880
  };
package/dist/cli.js CHANGED
@@ -10,11 +10,11 @@ var pkg = createRequire(import.meta.url)("../package.json");
10
10
  var program = new Command();
11
11
  program.name("stera-ui").description("Add Stera UI components to your project.").version(pkg.version);
12
12
  program.command("init").description("Initialize Stera UI in your project.").option("-c, --cwd <path>", "Working directory", process.cwd()).option("-y, --yes", "Skip confirmation prompts").action(async (options) => {
13
- const { init } = await import("./init-E7O5WAUI.js");
13
+ const { init } = await import("./init-QYYCGWYV.js");
14
14
  await init(options);
15
15
  });
16
16
  program.command("add").description("Add components to your project.").argument("<components...>", "Components to add").option("-c, --cwd <path>", "Working directory", process.cwd()).option("-y, --yes", "Skip confirmation prompts").option("-o, --overwrite", "Overwrite existing files without prompting").action(async (components, options) => {
17
- const { add } = await import("./add-JUBSRCDJ.js");
17
+ const { add } = await import("./add-WUTTJN25.js");
18
18
  await add(components, options);
19
19
  });
20
20
  program.command("list").description("List all available components.").action(async () => {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { ComponentNotFoundError, fetchRegistryIndex, fetchRegistryItem, getAllComponents, getComponent, resolveDependencies } from './registry/index.js';
2
2
  export { RegistryFontItem, RegistryIndex, RegistryIndexEntry, RegistryItem, RegistryItemFile, RegistryItemFont, RegistryItemType, SteraConfig, configSchema, registryIndexEntrySchema, registryIndexSchema, registryItemFileSchema, registryItemFontSchema, registryItemSchema, registryItemTypeSchema } from './schema/index.js';
3
- export { CHECK, CONFIG_FILE, CROSS, LEGACY_CONFIG_FILE, LOGO, ProjectInfo, SkippedFile, TransformContext, TransformFn, WARN, WriteOptions, WriteResult, WriteSteraCssResult, applyTransforms, brand, createSpinner, detectAliasPrefix, detectPackageManager, detectProject, dim, findConfigPath, insertImportLine, installDependencies, loadConfig, massageTreeForFonts, resolveOutputPath, transformImports, updateFonts, writeComponentFiles, writeSteraUiCss } from './utils/index.js';
3
+ export { CHECK, CONFIG_FILE, CROSS, INDEX_TARGET, LEGACY_CONFIG_FILE, LOGO, ProjectInfo, SkippedFile, TYPOGRAPHY_TARGET, TransformContext, TransformFn, WARN, WriteOptions, WriteResult, WriteStylesResult, applyTransforms, brand, createSpinner, detectAliasPrefix, detectPackageManager, detectProject, dim, findConfigPath, insertImportLine, installDependencies, loadConfig, massageTreeForFonts, migrateLegacyStyles, resolveOutputPath, transformImports, updateFonts, writeComponentFiles, writeStyles } from './utils/index.js';
4
4
  import 'zod';
package/dist/index.js CHANGED
@@ -2,8 +2,10 @@ import {
2
2
  CHECK,
3
3
  CONFIG_FILE,
4
4
  CROSS,
5
+ INDEX_TARGET,
5
6
  LEGACY_CONFIG_FILE,
6
7
  LOGO,
8
+ TYPOGRAPHY_TARGET,
7
9
  WARN,
8
10
  applyTransforms,
9
11
  brand,
@@ -17,12 +19,13 @@ import {
17
19
  installDependencies,
18
20
  loadConfig,
19
21
  massageTreeForFonts,
22
+ migrateLegacyStyles,
20
23
  resolveOutputPath,
21
24
  transformImports,
22
25
  updateFonts,
23
26
  writeComponentFiles,
24
- writeSteraUiCss
25
- } from "./chunk-SIXUH4HI.js";
27
+ writeStyles
28
+ } from "./chunk-V4TMOT6I.js";
26
29
  import {
27
30
  ComponentNotFoundError,
28
31
  fetchRegistryIndex,
@@ -45,8 +48,10 @@ export {
45
48
  CONFIG_FILE,
46
49
  CROSS,
47
50
  ComponentNotFoundError,
51
+ INDEX_TARGET,
48
52
  LEGACY_CONFIG_FILE,
49
53
  LOGO,
54
+ TYPOGRAPHY_TARGET,
50
55
  WARN,
51
56
  applyTransforms,
52
57
  brand,
@@ -65,6 +70,7 @@ export {
65
70
  installDependencies,
66
71
  loadConfig,
67
72
  massageTreeForFonts,
73
+ migrateLegacyStyles,
68
74
  registryIndexEntrySchema,
69
75
  registryIndexSchema,
70
76
  registryItemFileSchema,
@@ -76,5 +82,5 @@ export {
76
82
  transformImports,
77
83
  updateFonts,
78
84
  writeComponentFiles,
79
- writeSteraUiCss
85
+ writeStyles
80
86
  };
@@ -2,10 +2,14 @@
2
2
  import {
3
3
  CONFIG_FILE,
4
4
  LEGACY_CONFIG_FILE,
5
+ TYPOGRAPHY_TARGET,
5
6
  findConfigPath,
7
+ insertImportLine,
6
8
  installDependencies,
7
- writeSteraUiCss
8
- } from "./chunk-2Y64FOD3.js";
9
+ migrateLegacyStyles,
10
+ patchCssVariables,
11
+ writeStyles
12
+ } from "./chunk-5NLD52O5.js";
9
13
  import {
10
14
  createSpinner,
11
15
  fetchRegistryItem
@@ -17,7 +21,7 @@ import {
17
21
  } from "./chunk-KGMF6UW4.js";
18
22
 
19
23
  // src/commands/init.ts
20
- import fs6 from "fs";
24
+ import fs4 from "fs";
21
25
  import fsp from "fs/promises";
22
26
  import path4 from "path";
23
27
  import { confirm, select } from "@inquirer/prompts";
@@ -192,36 +196,8 @@ function detectFonts(cwd, project) {
192
196
  return result;
193
197
  }
194
198
 
195
- // src/utils/patch-css-vars.ts
196
- import fs3 from "fs";
197
- function patchCssVariables(filePath, patches) {
198
- const content = fs3.readFileSync(filePath, "utf-8");
199
- const lines = content.split("\n");
200
- const patched = [];
201
- const compiled = Object.entries(patches).map(([prop, newValue]) => ({
202
- prop,
203
- newValue,
204
- regex: new RegExp(`(\\s*${escapeRegex(prop)}:\\s*).+?(;)`)
205
- }));
206
- for (let i = 0; i < lines.length; i++) {
207
- for (const { prop, newValue, regex } of compiled) {
208
- if (regex.test(lines[i])) {
209
- lines[i] = lines[i].replace(regex, `$1${newValue}$2`);
210
- if (!patched.includes(prop)) patched.push(prop);
211
- }
212
- }
213
- }
214
- if (patched.length > 0) {
215
- fs3.writeFileSync(filePath, lines.join("\n"), "utf-8");
216
- }
217
- return patched;
218
- }
219
- function escapeRegex(str) {
220
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
221
- }
222
-
223
199
  // src/utils/update-fonts.ts
224
- import { existsSync, promises as fs4 } from "fs";
200
+ import { existsSync, promises as fs3 } from "fs";
225
201
  import path3 from "path";
226
202
  import {
227
203
  Project,
@@ -262,10 +238,10 @@ async function updateFonts(fonts, project, cwd, options = {}) {
262
238
  if (!layoutPath) return;
263
239
  if (options.silent) {
264
240
  try {
265
- const layoutContent = await fs4.readFile(layoutPath, "utf-8");
241
+ const layoutContent = await fs3.readFile(layoutPath, "utf-8");
266
242
  const updatedContent = transformLayoutFonts(layoutContent, fonts);
267
243
  if (updatedContent !== layoutContent) {
268
- await fs4.writeFile(layoutPath, updatedContent, "utf-8");
244
+ await fs3.writeFile(layoutPath, updatedContent, "utf-8");
269
245
  }
270
246
  } catch {
271
247
  }
@@ -273,10 +249,10 @@ async function updateFonts(fonts, project, cwd, options = {}) {
273
249
  }
274
250
  const spinner = createSpinner("Updating fonts");
275
251
  try {
276
- const layoutContent = await fs4.readFile(layoutPath, "utf-8");
252
+ const layoutContent = await fs3.readFile(layoutPath, "utf-8");
277
253
  const updatedContent = transformLayoutFonts(layoutContent, fonts);
278
254
  if (updatedContent !== layoutContent) {
279
- await fs4.writeFile(layoutPath, updatedContent, "utf-8");
255
+ await fs3.writeFile(layoutPath, updatedContent, "utf-8");
280
256
  }
281
257
  spinner.succeed("Updated layout with font imports");
282
258
  } catch {
@@ -531,41 +507,14 @@ function parseTemplateLiteralToCnArgs(templateLiteral) {
531
507
  return [...staticArgs, ...variableArgs];
532
508
  }
533
509
 
534
- // src/utils/css-imports.ts
535
- import fs5 from "fs/promises";
536
- async function insertImportLine(filePath, importStatement) {
537
- const content = await fs5.readFile(filePath, "utf-8");
538
- const importPath = importStatement.match(/["']([^"']+)["']/)?.[1];
539
- if (importPath) {
540
- const escaped = importPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
541
- if (new RegExp(`@import\\s+["']${escaped}["']`).test(content)) return;
542
- }
543
- const lines = content.split("\n");
544
- let lastImportIndex = -1;
545
- for (let i = 0; i < lines.length; i++) {
546
- if (lines[i].trim().startsWith("@import")) {
547
- lastImportIndex = i;
548
- }
549
- }
550
- if (lastImportIndex >= 0) {
551
- lines.splice(lastImportIndex + 1, 0, importStatement);
552
- } else {
553
- lines.unshift(importStatement);
554
- }
555
- await fs5.writeFile(filePath, lines.join("\n"), "utf-8");
556
- }
557
-
558
510
  // src/commands/init.ts
559
511
  var DEFAULT_FONT_NAMES = ["font-geist", "font-geist-mono"];
512
+ function resolveCssPath(project) {
513
+ if (project.existingCssFile) return project.existingCssFile;
514
+ return project.hasSrc ? "src/styles/globals.css" : "styles/globals.css";
515
+ }
560
516
  function buildConfig(project, strategy, aliasPrefix) {
561
- let cssPath;
562
- if (project.existingCssFile) {
563
- cssPath = project.existingCssFile;
564
- } else if (project.hasSrc) {
565
- cssPath = "src/styles/globals.css";
566
- } else {
567
- cssPath = "styles/globals.css";
568
- }
517
+ const cssPath = resolveCssPath(project);
569
518
  return {
570
519
  $schema: "https://ui.stera.sh/schema.json",
571
520
  version: 1,
@@ -640,11 +589,11 @@ async function fetchDefaultFonts() {
640
589
  async function executeFontStrategy(strategy, project, detected, config, cwd) {
641
590
  if (strategy === "skip") return;
642
591
  const cssDir = path4.dirname(path4.resolve(cwd, config.css));
643
- const steraUiPath = path4.join(cssDir, "stera-ui.css");
592
+ const typographyPath = path4.join(cssDir, TYPOGRAPHY_TARGET);
644
593
  if (strategy === "keep-existing") {
645
594
  const fontFamily = detected.fontFamilies.length > 0 ? detected.fontFamilies[0] : null;
646
595
  const fontValue = detected.nextFontVariable ? `var(${detected.nextFontVariable})` : fontFamily ?? "Geist";
647
- const patched = patchCssVariables(steraUiPath, {
596
+ const patched = patchCssVariables(typographyPath, {
648
597
  "--font-heading": fontValue,
649
598
  "--font-sans": fontValue
650
599
  });
@@ -661,17 +610,17 @@ async function executeFontStrategy(strategy, project, detected, config, cwd) {
661
610
  }
662
611
  if (fontTree.cssImports.length > 0) {
663
612
  for (const importLine of fontTree.cssImports) {
664
- await insertImportLine(steraUiPath, importLine);
613
+ await insertImportLine(typographyPath, importLine);
665
614
  }
666
615
  console.log(
667
- ` ${CHECK} Added font imports to ${path4.relative(cwd, steraUiPath)}`
616
+ ` ${CHECK} Added font imports to ${path4.relative(cwd, typographyPath)}`
668
617
  );
669
618
  }
670
619
  if (Object.keys(fontTree.cssVars).length > 0) {
671
- const patched = patchCssVariables(steraUiPath, fontTree.cssVars);
620
+ const patched = patchCssVariables(typographyPath, fontTree.cssVars);
672
621
  if (patched.length > 0) {
673
622
  console.log(
674
- ` ${CHECK} Updated font variables in ${path4.relative(cwd, steraUiPath)}`
623
+ ` ${CHECK} Updated font variables in ${path4.relative(cwd, typographyPath)}`
675
624
  );
676
625
  }
677
626
  }
@@ -693,7 +642,7 @@ async function init(options) {
693
642
  });
694
643
  if (shouldRename) {
695
644
  const renamed = path4.join(path4.dirname(existing), CONFIG_FILE);
696
- fs6.renameSync(existing, renamed);
645
+ fs4.renameSync(existing, renamed);
697
646
  console.log(` ${CHECK} Renamed to ${CONFIG_FILE}`);
698
647
  console.log(' Run "stera-ui add <component>" to add components.\n');
699
648
  } else {
@@ -709,7 +658,7 @@ async function init(options) {
709
658
  return;
710
659
  }
711
660
  const pkgPath = path4.join(cwd, "package.json");
712
- if (!fs6.existsSync(pkgPath)) {
661
+ if (!fs4.existsSync(pkgPath)) {
713
662
  console.error(
714
663
  " Error: No package.json found. Please run this in a project directory."
715
664
  );
@@ -738,29 +687,47 @@ async function init(options) {
738
687
  `);
739
688
  }
740
689
  const detectedFonts = detectFonts(cwd, project);
690
+ const uiDir = path4.join(path4.dirname(path4.resolve(cwd, resolveCssPath(project))), "ui");
691
+ if (fs4.existsSync(uiDir) && fs4.readdirSync(uiDir).length > 0) {
692
+ const relativeUiDir = path4.relative(cwd, uiDir);
693
+ console.log("");
694
+ console.log(` ${relativeUiDir} already exists and is not empty.`);
695
+ const proceed = options.yes || process.stdin.isTTY && await confirm({
696
+ message: `Write the style partials into ${relativeUiDir}?`,
697
+ default: false
698
+ });
699
+ if (!proceed) {
700
+ console.log("");
701
+ console.log(
702
+ ` Aborted. Move ${relativeUiDir} aside, or point "css" in ${CONFIG_FILE} at a different stylesheet, then run init again.`
703
+ );
704
+ return;
705
+ }
706
+ }
741
707
  const strategy = await promptFontStrategy(detectedFonts, options.yes ?? false);
742
708
  const config = buildConfig(project, strategy, aliasPrefix);
743
709
  const configPath = path4.join(cwd, CONFIG_FILE);
744
- fs6.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
710
+ fs4.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
745
711
  console.log(` ${CHECK} Created ${CONFIG_FILE}`);
746
712
  const fetchSpinner = createSpinner("Fetching base styles");
747
- let steraCssResult;
713
+ let stylesResult;
748
714
  try {
749
- steraCssResult = await writeSteraUiCss(config, cwd);
715
+ await migrateLegacyStyles(config, cwd);
716
+ stylesResult = await writeStyles(config, cwd);
750
717
  } catch (err) {
751
718
  fetchSpinner.fail("Failed to fetch base styles");
752
719
  throw err;
753
720
  }
754
721
  fetchSpinner.succeed("Base styles resolved");
755
722
  console.log(
756
- ` ${CHECK} Created ${path4.relative(cwd, steraCssResult.steraUiPath)}`
723
+ ` ${CHECK} Created ${path4.relative(cwd, stylesResult.indexPath)}`
757
724
  );
758
725
  const globalsPath = project.existingCssFile ? path4.resolve(cwd, project.existingCssFile) : path4.resolve(cwd, config.css);
759
- if (fs6.existsSync(globalsPath)) {
760
- for (const imp of steraCssResult.extraImports) {
726
+ if (fs4.existsSync(globalsPath)) {
727
+ for (const imp of stylesResult.extraImports) {
761
728
  await insertImportLine(globalsPath, imp);
762
729
  }
763
- await insertImportLine(globalsPath, '@import "./stera-ui.css";');
730
+ await insertImportLine(globalsPath, '@import "./ui/index.css";');
764
731
  console.log(
765
732
  ` ${CHECK} Added @import to ${path4.relative(cwd, globalsPath)}`
766
733
  );
@@ -768,15 +735,15 @@ async function init(options) {
768
735
  await fsp.mkdir(path4.dirname(globalsPath), { recursive: true });
769
736
  const scaffold = [
770
737
  '@import "tailwindcss";',
771
- ...steraCssResult.extraImports,
772
- '@import "./stera-ui.css";'
738
+ ...stylesResult.extraImports,
739
+ '@import "./ui/index.css";'
773
740
  ].join("\n") + "\n";
774
741
  await fsp.writeFile(globalsPath, scaffold, "utf-8");
775
742
  console.log(` ${CHECK} Created ${path4.relative(cwd, globalsPath)}`);
776
743
  }
777
744
  await executeFontStrategy(strategy, project, detectedFonts, config, cwd);
778
- if (steraCssResult.dependencies.length > 0) {
779
- const deps = [...new Set(steraCssResult.dependencies)].sort();
745
+ if (stylesResult.dependencies.length > 0) {
746
+ const deps = [...new Set(stylesResult.dependencies)].sort();
780
747
  console.log("");
781
748
  await installDependencies(deps, cwd);
782
749
  }