shapes-ui 0.5.0 → 0.6.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.
- package/.github/workflows/pr-preview.yml +9 -2
- package/CHANGELOG.md +11 -0
- package/README.md +13 -0
- package/content/components/accordion.mdx +13 -0
- package/content/components/alert-dialog.mdx +34 -0
- package/content/components/autocomplete.mdx +62 -0
- package/content/components/avatar.mdx +11 -0
- package/content/components/button.mdx +8 -0
- package/content/components/checkbox.mdx +11 -0
- package/content/components/collapsible.mdx +11 -0
- package/content/components/combobox.mdx +33 -0
- package/content/components/context-menu.mdx +29 -0
- package/content/components/dialog.mdx +33 -0
- package/content/components/drawer.mdx +38 -0
- package/content/components/field.mdx +21 -0
- package/content/components/fieldset.mdx +10 -0
- package/content/components/form.mdx +8 -0
- package/content/components/input.mdx +4 -0
- package/content/components/menu.mdx +27 -0
- package/content/components/menubar.mdx +31 -0
- package/content/components/meter.mdx +14 -0
- package/content/components/navigation-menu.mdx +28 -0
- package/content/components/number-field.mdx +25 -0
- package/content/components/popover.mdx +22 -0
- package/content/components/preview-card.mdx +14 -2
- package/content/components/progress.mdx +15 -1
- package/content/components/radio.mdx +11 -0
- package/content/components/scroll-area.mdx +23 -0
- package/content/components/select.mdx +27 -0
- package/content/components/separator.mdx +29 -0
- package/content/components/slider.mdx +4 -0
- package/content/components/switch.mdx +4 -0
- package/content/components/tabs.mdx +15 -0
- package/content/components/toast.mdx +10 -0
- package/content/components/toggle-group.mdx +37 -0
- package/content/components/toggle.mdx +12 -0
- package/content/components/toolbar.mdx +22 -0
- package/content/components/tooltip.mdx +13 -0
- package/content/docs/installation.mdx +30 -0
- package/content-collections.ts +65 -1
- package/dist/cli.js +947 -101
- package/examples/__index.tsx +136 -68
- package/examples/autocomplete-align.tsx +39 -0
- package/examples/autocomplete-controlled.tsx +44 -0
- package/examples/autocomplete-groups.tsx +65 -0
- package/examples/autocomplete-no-clear.tsx +40 -0
- package/examples/avatar-demo.tsx +3 -3
- package/examples/input-group-with-button.tsx +1 -1
- package/examples/separator-demo.tsx +13 -0
- package/examples/separator-horizontal.tsx +18 -0
- package/package.json +19 -18
- package/public/base-ui.svg +1 -0
- package/src/assets/base-ui.svg +1 -0
- package/src/commands/add.ts +79 -38
- package/src/commands/cli.ts +50 -3
- package/src/commands/create.ts +262 -0
- package/src/commands/init.ts +45 -12
- package/src/commands/palette.ts +55 -0
- package/src/components/docs/layout/footer.tsx +2 -2
- package/src/components/docs/layout/header.tsx +7 -9
- package/src/components/docs/layout/mobile-menu.tsx +0 -1
- package/src/components/docs/layout/nav-list.tsx +2 -2
- package/src/components/docs/layout/page-header.tsx +52 -7
- package/src/components/docs/layout/split-layout.tsx +9 -10
- package/src/components/docs/layout/table-of-content.tsx +145 -0
- package/src/components/docs/markdown/components.tsx +142 -29
- package/src/components/docs/markdown/copy-button.tsx +41 -0
- package/src/components/docs/markdown/installation-block.tsx +5 -24
- package/src/components/docs/markdown/render-preview.tsx +1 -1
- package/src/components/ui/button-group.tsx +1 -1
- package/src/components/ui/scroll-area.tsx +11 -2
- package/src/lib/docs-headings.ts +72 -0
- package/src/routeTree.gen.ts +60 -3
- package/src/routes/__root.tsx +2 -2
- package/src/routes/components.$slug.tsx +20 -4
- package/src/routes/docs.$slug.tsx +78 -0
- package/src/routes/docs.tsx +15 -0
- package/src/styles/styles.css +1 -1
- package/src/utils/cli-utils.ts +8 -8
- package/src/utils/dependency-installer.ts +30 -0
- package/src/utils/package-manager.ts +4 -4
- package/src/utils/palette.ts +666 -0
- package/src/utils/schema.ts +6 -0
package/dist/cli.js
CHANGED
|
@@ -784,10 +784,10 @@ function mergeDefs(...defs) {
|
|
|
784
784
|
function cloneDef(schema) {
|
|
785
785
|
return mergeDefs(schema._zod.def);
|
|
786
786
|
}
|
|
787
|
-
function getElementAtPath(obj,
|
|
788
|
-
if (!
|
|
787
|
+
function getElementAtPath(obj, path7) {
|
|
788
|
+
if (!path7)
|
|
789
789
|
return obj;
|
|
790
|
-
return
|
|
790
|
+
return path7.reduce((acc, key) => acc?.[key], obj);
|
|
791
791
|
}
|
|
792
792
|
function promiseAllObject(promisesObj) {
|
|
793
793
|
const keys = Object.keys(promisesObj);
|
|
@@ -1170,11 +1170,11 @@ function aborted(x, startIndex = 0) {
|
|
|
1170
1170
|
}
|
|
1171
1171
|
return false;
|
|
1172
1172
|
}
|
|
1173
|
-
function prefixIssues(
|
|
1173
|
+
function prefixIssues(path7, issues) {
|
|
1174
1174
|
return issues.map((iss) => {
|
|
1175
1175
|
var _a2;
|
|
1176
1176
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
1177
|
-
iss.path.unshift(
|
|
1177
|
+
iss.path.unshift(path7);
|
|
1178
1178
|
return iss;
|
|
1179
1179
|
});
|
|
1180
1180
|
}
|
|
@@ -1357,7 +1357,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
|
|
|
1357
1357
|
}
|
|
1358
1358
|
function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
1359
1359
|
const result = { errors: [] };
|
|
1360
|
-
const processError = (error49,
|
|
1360
|
+
const processError = (error49, path7 = []) => {
|
|
1361
1361
|
var _a2, _b;
|
|
1362
1362
|
for (const issue2 of error49.issues) {
|
|
1363
1363
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -1367,7 +1367,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
1367
1367
|
} else if (issue2.code === "invalid_element") {
|
|
1368
1368
|
processError({ issues: issue2.issues }, issue2.path);
|
|
1369
1369
|
} else {
|
|
1370
|
-
const fullpath = [...
|
|
1370
|
+
const fullpath = [...path7, ...issue2.path];
|
|
1371
1371
|
if (fullpath.length === 0) {
|
|
1372
1372
|
result.errors.push(mapper(issue2));
|
|
1373
1373
|
continue;
|
|
@@ -1399,8 +1399,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
1399
1399
|
}
|
|
1400
1400
|
function toDotPath(_path) {
|
|
1401
1401
|
const segs = [];
|
|
1402
|
-
const
|
|
1403
|
-
for (const seg of
|
|
1402
|
+
const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1403
|
+
for (const seg of path7) {
|
|
1404
1404
|
if (typeof seg === "number")
|
|
1405
1405
|
segs.push(`[${seg}]`);
|
|
1406
1406
|
else if (typeof seg === "symbol")
|
|
@@ -7249,8 +7249,8 @@ function ko_default() {
|
|
|
7249
7249
|
}
|
|
7250
7250
|
|
|
7251
7251
|
// node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/lt.js
|
|
7252
|
-
var capitalizeFirstCharacter = (
|
|
7253
|
-
return
|
|
7252
|
+
var capitalizeFirstCharacter = (text3) => {
|
|
7253
|
+
return text3.charAt(0).toUpperCase() + text3.slice(1);
|
|
7254
7254
|
};
|
|
7255
7255
|
function getUnitTypeFromNumber(number4) {
|
|
7256
7256
|
const abs = Math.abs(number4);
|
|
@@ -13377,13 +13377,13 @@ function resolveRef(ref, ctx) {
|
|
|
13377
13377
|
if (!ref.startsWith("#")) {
|
|
13378
13378
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
13379
13379
|
}
|
|
13380
|
-
const
|
|
13381
|
-
if (
|
|
13380
|
+
const path7 = ref.slice(1).split("/").filter(Boolean);
|
|
13381
|
+
if (path7.length === 0) {
|
|
13382
13382
|
return ctx.rootSchema;
|
|
13383
13383
|
}
|
|
13384
13384
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
13385
|
-
if (
|
|
13386
|
-
const key =
|
|
13385
|
+
if (path7[0] === defsKey) {
|
|
13386
|
+
const key = path7[1];
|
|
13387
13387
|
if (!key || !ctx.defs[key]) {
|
|
13388
13388
|
throw new Error(`Reference not found: ${ref}`);
|
|
13389
13389
|
}
|
|
@@ -13790,6 +13790,10 @@ import { zodToJsonSchema } from "zod-to-json-schema";
|
|
|
13790
13790
|
var configSchema = external_exports.object({
|
|
13791
13791
|
$schema: external_exports.string().optional(),
|
|
13792
13792
|
style: external_exports.enum(["default", "brutalist", "minimal"]).default("default"),
|
|
13793
|
+
palette: external_exports.object({
|
|
13794
|
+
name: external_exports.string().default("blue"),
|
|
13795
|
+
contrastMode: external_exports.enum(["deterministic", "dynamic"]).default("deterministic")
|
|
13796
|
+
}).default({ name: "blue", contrastMode: "deterministic" }),
|
|
13793
13797
|
tailwind: external_exports.object({
|
|
13794
13798
|
config: external_exports.string().optional(),
|
|
13795
13799
|
css: external_exports.string().default("src/styles/globals.css"),
|
|
@@ -13809,13 +13813,13 @@ function exitIfCancelled(value) {
|
|
|
13809
13813
|
}
|
|
13810
13814
|
return value;
|
|
13811
13815
|
}
|
|
13812
|
-
async function getConfig() {
|
|
13813
|
-
const configPath = path.join(
|
|
13816
|
+
async function getConfig(cwd = process.cwd()) {
|
|
13817
|
+
const configPath = path.join(cwd, "shapes.json");
|
|
13814
13818
|
if (!fs2.existsSync(configPath)) return null;
|
|
13815
13819
|
return configSchema.parse(await fs2.readJSON(configPath));
|
|
13816
13820
|
}
|
|
13817
|
-
async function readPackageJson() {
|
|
13818
|
-
const pkgPath = path.join(
|
|
13821
|
+
async function readPackageJson(cwd = process.cwd()) {
|
|
13822
|
+
const pkgPath = path.join(cwd, "package.json");
|
|
13819
13823
|
if (!await fs2.pathExists(pkgPath)) return null;
|
|
13820
13824
|
return fs2.readJSON(pkgPath);
|
|
13821
13825
|
}
|
|
@@ -13835,30 +13839,33 @@ function getMissingDeps(pkg, deps) {
|
|
|
13835
13839
|
if (!pkg) return deps;
|
|
13836
13840
|
return deps.filter((dep) => !pkg.dependencies?.[dep] && !pkg.devDependencies?.[dep]);
|
|
13837
13841
|
}
|
|
13838
|
-
async function isViteProject() {
|
|
13839
|
-
const viteConfigTs = path.join(
|
|
13840
|
-
const viteConfigJs = path.join(
|
|
13841
|
-
const viteConfigMjs = path.join(
|
|
13842
|
+
async function isViteProject(cwd = process.cwd()) {
|
|
13843
|
+
const viteConfigTs = path.join(cwd, "vite.config.ts");
|
|
13844
|
+
const viteConfigJs = path.join(cwd, "vite.config.js");
|
|
13845
|
+
const viteConfigMjs = path.join(cwd, "vite.config.mjs");
|
|
13842
13846
|
return await fs2.pathExists(viteConfigTs) || await fs2.pathExists(viteConfigJs) || await fs2.pathExists(viteConfigMjs);
|
|
13843
13847
|
}
|
|
13844
13848
|
|
|
13845
13849
|
// src/commands/add.ts
|
|
13846
13850
|
import path2 from "path";
|
|
13847
|
-
import { cancel as cancel2, multiselect, note, spinner } from "@clack/prompts";
|
|
13848
|
-
import { execa } from "execa";
|
|
13851
|
+
import { cancel as cancel2, multiselect, note, spinner as spinner2 } from "@clack/prompts";
|
|
13849
13852
|
import fs3 from "fs-extra";
|
|
13850
13853
|
|
|
13854
|
+
// src/utils/dependency-installer.ts
|
|
13855
|
+
import { spinner } from "@clack/prompts";
|
|
13856
|
+
import { execa } from "execa";
|
|
13857
|
+
|
|
13851
13858
|
// src/utils/package-manager.ts
|
|
13852
13859
|
import { detect } from "detect-package-manager";
|
|
13853
|
-
async function getPackageManager() {
|
|
13860
|
+
async function getPackageManager(cwd = process.cwd()) {
|
|
13854
13861
|
try {
|
|
13855
|
-
return await detect();
|
|
13862
|
+
return await detect({ cwd });
|
|
13856
13863
|
} catch {
|
|
13857
13864
|
return "npm";
|
|
13858
13865
|
}
|
|
13859
13866
|
}
|
|
13860
|
-
async function getInstallCommand(deps, dev = false) {
|
|
13861
|
-
const pm = await getPackageManager();
|
|
13867
|
+
async function getInstallCommand(deps, dev = false, cwd = process.cwd()) {
|
|
13868
|
+
const pm = await getPackageManager(cwd);
|
|
13862
13869
|
if (pm === "yarn") {
|
|
13863
13870
|
return ["yarn", "add", ...dev ? ["-D"] : [], ...deps];
|
|
13864
13871
|
}
|
|
@@ -13871,10 +13878,22 @@ async function getInstallCommand(deps, dev = false) {
|
|
|
13871
13878
|
return ["npm", "install", ...dev ? ["--save-dev"] : [], ...deps];
|
|
13872
13879
|
}
|
|
13873
13880
|
|
|
13881
|
+
// src/utils/dependency-installer.ts
|
|
13882
|
+
async function installDependencies(deps, options = {}) {
|
|
13883
|
+
if (!deps.length) return;
|
|
13884
|
+
const spin = spinner();
|
|
13885
|
+
const label = options.label ?? (options.dev ? "Installing dev dependencies" : "Installing dependencies");
|
|
13886
|
+
spin.start(label);
|
|
13887
|
+
const cwd = options.cwd ?? process.cwd();
|
|
13888
|
+
const [command, ...args] = await getInstallCommand(deps, options.dev ?? false, cwd);
|
|
13889
|
+
await execa(command, args, { cwd });
|
|
13890
|
+
spin.stop(options.successMessage ?? "Dependencies installed");
|
|
13891
|
+
}
|
|
13892
|
+
|
|
13874
13893
|
// src/commands/add.ts
|
|
13875
13894
|
var REGISTRY_URL = "https://shapes-ui.com/r";
|
|
13876
|
-
async function loadRegistryIndex() {
|
|
13877
|
-
const localRegistryDir = path2.resolve(
|
|
13895
|
+
async function loadRegistryIndex(cwd = process.cwd()) {
|
|
13896
|
+
const localRegistryDir = path2.resolve(cwd, "public/r");
|
|
13878
13897
|
if (await fs3.pathExists(localRegistryDir)) {
|
|
13879
13898
|
const files = await fs3.readdir(localRegistryDir);
|
|
13880
13899
|
const entries = [];
|
|
@@ -13899,7 +13918,7 @@ async function loadRegistryIndex() {
|
|
|
13899
13918
|
async function pickComponents() {
|
|
13900
13919
|
let components = [];
|
|
13901
13920
|
try {
|
|
13902
|
-
components = await loadRegistryIndex();
|
|
13921
|
+
components = await loadRegistryIndex(process.cwd());
|
|
13903
13922
|
} catch (error48) {
|
|
13904
13923
|
cancel2(error48 instanceof Error ? error48.message : "Failed to load registry.");
|
|
13905
13924
|
process.exit(1);
|
|
@@ -13916,59 +13935,607 @@ async function pickComponents() {
|
|
|
13916
13935
|
);
|
|
13917
13936
|
return selected;
|
|
13918
13937
|
}
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
throw new Error(`Component ${name} not found in registry.`);
|
|
13931
|
-
}
|
|
13932
|
-
data = await res.json();
|
|
13938
|
+
function createInstallContext() {
|
|
13939
|
+
return {
|
|
13940
|
+
installing: /* @__PURE__ */ new Set(),
|
|
13941
|
+
installed: /* @__PURE__ */ new Set()
|
|
13942
|
+
};
|
|
13943
|
+
}
|
|
13944
|
+
async function installComponent(name, config2, context = createInstallContext(), cwd = process.cwd()) {
|
|
13945
|
+
if (context.installed.has(name)) return;
|
|
13946
|
+
if (context.installing.has(name)) {
|
|
13947
|
+
note(`Skipped circular dependency while resolving ${name}`);
|
|
13948
|
+
return;
|
|
13933
13949
|
}
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13950
|
+
context.installing.add(name);
|
|
13951
|
+
try {
|
|
13952
|
+
const spin = spinner2();
|
|
13953
|
+
spin.start(`Fetching ${name}`);
|
|
13954
|
+
let data;
|
|
13955
|
+
const localFile = path2.resolve(cwd, `public/r/${name}.json`);
|
|
13956
|
+
if (await fs3.pathExists(localFile)) {
|
|
13957
|
+
data = await fs3.readJSON(localFile);
|
|
13958
|
+
} else {
|
|
13959
|
+
const res = await fetch(`${REGISTRY_URL}/${name}.json`);
|
|
13960
|
+
if (!res.ok) {
|
|
13961
|
+
spin.stop("Fetch failed");
|
|
13962
|
+
throw new Error(`Component ${name} not found in registry.`);
|
|
13940
13963
|
}
|
|
13964
|
+
data = await res.json();
|
|
13941
13965
|
}
|
|
13966
|
+
spin.stop(`Fetched ${name}`);
|
|
13967
|
+
if (data.registryDependencies) {
|
|
13968
|
+
for (const dep of data.registryDependencies) {
|
|
13969
|
+
const depPath = path2.join(cwd, config2.paths.ui, `${dep}.tsx`);
|
|
13970
|
+
if (!fs3.existsSync(depPath)) {
|
|
13971
|
+
await installComponent(dep, config2, context, cwd);
|
|
13972
|
+
}
|
|
13973
|
+
}
|
|
13974
|
+
}
|
|
13975
|
+
if (data.dependencies?.length) {
|
|
13976
|
+
await installDependencies(data.dependencies, {
|
|
13977
|
+
label: `Installing dependencies for ${name}`,
|
|
13978
|
+
successMessage: `Dependencies installed for ${name}`,
|
|
13979
|
+
cwd
|
|
13980
|
+
});
|
|
13981
|
+
}
|
|
13982
|
+
for (const file2 of data.files) {
|
|
13983
|
+
const target = path2.join(cwd, config2.paths.ui, file2.path);
|
|
13984
|
+
await fs3.ensureDir(path2.dirname(target));
|
|
13985
|
+
await fs3.writeFile(target, file2.content);
|
|
13986
|
+
}
|
|
13987
|
+
context.installed.add(name);
|
|
13988
|
+
note(`Added ${name}`);
|
|
13989
|
+
} finally {
|
|
13990
|
+
context.installing.delete(name);
|
|
13942
13991
|
}
|
|
13943
|
-
|
|
13944
|
-
|
|
13945
|
-
|
|
13946
|
-
|
|
13947
|
-
for (const
|
|
13948
|
-
|
|
13949
|
-
await fs3.ensureDir(path2.dirname(target));
|
|
13950
|
-
await fs3.writeFile(target, file2.content);
|
|
13992
|
+
}
|
|
13993
|
+
async function addAllComponents(config2, cwd = process.cwd()) {
|
|
13994
|
+
const all = await loadRegistryIndex(cwd);
|
|
13995
|
+
const context = createInstallContext();
|
|
13996
|
+
for (const name of all) {
|
|
13997
|
+
await installComponent(name, config2, context, cwd);
|
|
13951
13998
|
}
|
|
13952
|
-
note(`Added ${name}`);
|
|
13953
13999
|
}
|
|
13954
14000
|
async function addCommand(components, config2) {
|
|
13955
14001
|
let selections = components;
|
|
13956
14002
|
if (!selections?.length) {
|
|
13957
14003
|
selections = await pickComponents();
|
|
13958
14004
|
}
|
|
14005
|
+
const context = createInstallContext();
|
|
13959
14006
|
for (const name of selections) {
|
|
13960
|
-
await installComponent(name, config2);
|
|
14007
|
+
await installComponent(name, config2, context, process.cwd());
|
|
13961
14008
|
}
|
|
13962
14009
|
}
|
|
13963
14010
|
|
|
13964
|
-
// src/commands/
|
|
13965
|
-
import
|
|
13966
|
-
import { confirm, intro, note as note2, outro,
|
|
14011
|
+
// src/commands/create.ts
|
|
14012
|
+
import path4 from "path";
|
|
14013
|
+
import { confirm, intro, note as note2, outro, spinner as spinner3, text } from "@clack/prompts";
|
|
13967
14014
|
import { execa as execa2 } from "execa";
|
|
13968
|
-
import
|
|
13969
|
-
import fs4 from "fs-extra";
|
|
13970
|
-
import gradient from "gradient-string";
|
|
14015
|
+
import fs5 from "fs-extra";
|
|
13971
14016
|
import pc from "picocolors";
|
|
14017
|
+
|
|
14018
|
+
// src/utils/palette.ts
|
|
14019
|
+
import os from "os";
|
|
14020
|
+
import path3 from "path";
|
|
14021
|
+
import fs4 from "fs-extra";
|
|
14022
|
+
var CACHE_VERSION = 1;
|
|
14023
|
+
var TAILWIND_COLORS_URL = "https://tailwindcss.com/docs/colors";
|
|
14024
|
+
var MARKER_START = "/* shapes-ui:tokens:start v1 */";
|
|
14025
|
+
var MARKER_END = "/* shapes-ui:tokens:end */";
|
|
14026
|
+
var SHADE_STEPS = [
|
|
14027
|
+
"50",
|
|
14028
|
+
"100",
|
|
14029
|
+
"200",
|
|
14030
|
+
"300",
|
|
14031
|
+
"400",
|
|
14032
|
+
"500",
|
|
14033
|
+
"600",
|
|
14034
|
+
"700",
|
|
14035
|
+
"800",
|
|
14036
|
+
"900",
|
|
14037
|
+
"950"
|
|
14038
|
+
];
|
|
14039
|
+
var DEFAULT_BRAND_PALETTES = [
|
|
14040
|
+
"red",
|
|
14041
|
+
"orange",
|
|
14042
|
+
"amber",
|
|
14043
|
+
"yellow",
|
|
14044
|
+
"lime",
|
|
14045
|
+
"green",
|
|
14046
|
+
"emerald",
|
|
14047
|
+
"teal",
|
|
14048
|
+
"cyan",
|
|
14049
|
+
"sky",
|
|
14050
|
+
"blue",
|
|
14051
|
+
"indigo",
|
|
14052
|
+
"violet",
|
|
14053
|
+
"purple",
|
|
14054
|
+
"fuchsia",
|
|
14055
|
+
"pink",
|
|
14056
|
+
"rose"
|
|
14057
|
+
];
|
|
14058
|
+
var FOREGROUND_PAIRS = [
|
|
14059
|
+
{ background: "card", foreground: "card-foreground" },
|
|
14060
|
+
{ background: "popup", foreground: "popup-foreground" },
|
|
14061
|
+
{ background: "primary", foreground: "primary-foreground" },
|
|
14062
|
+
{ background: "secondary", foreground: "secondary-foreground" },
|
|
14063
|
+
{ background: "muted", foreground: "muted-foreground" },
|
|
14064
|
+
{ background: "accent", foreground: "accent-foreground" },
|
|
14065
|
+
{ background: "destructive", foreground: "destructive-foreground" },
|
|
14066
|
+
{ background: "success", foreground: "success-foreground" },
|
|
14067
|
+
{ background: "warning", foreground: "warning-foreground" },
|
|
14068
|
+
{ background: "info", foreground: "info-foreground" }
|
|
14069
|
+
];
|
|
14070
|
+
var DETERMINISTIC_FOREGROUND_SHADE = {
|
|
14071
|
+
light: {
|
|
14072
|
+
background: "950",
|
|
14073
|
+
foreground: "950",
|
|
14074
|
+
card: "950",
|
|
14075
|
+
"card-foreground": "950",
|
|
14076
|
+
popup: "950",
|
|
14077
|
+
"popup-foreground": "950",
|
|
14078
|
+
primary: "50",
|
|
14079
|
+
"primary-foreground": "50",
|
|
14080
|
+
secondary: "900",
|
|
14081
|
+
"secondary-foreground": "900",
|
|
14082
|
+
muted: "500",
|
|
14083
|
+
"muted-foreground": "500",
|
|
14084
|
+
accent: "900",
|
|
14085
|
+
"accent-foreground": "900",
|
|
14086
|
+
destructive: "50",
|
|
14087
|
+
"destructive-foreground": "50",
|
|
14088
|
+
success: "50",
|
|
14089
|
+
"success-foreground": "50",
|
|
14090
|
+
warning: "950",
|
|
14091
|
+
"warning-foreground": "950",
|
|
14092
|
+
info: "50",
|
|
14093
|
+
"info-foreground": "50",
|
|
14094
|
+
border: "900",
|
|
14095
|
+
input: "900",
|
|
14096
|
+
ring: "50"
|
|
14097
|
+
},
|
|
14098
|
+
dark: {
|
|
14099
|
+
background: "50",
|
|
14100
|
+
foreground: "50",
|
|
14101
|
+
card: "100",
|
|
14102
|
+
"card-foreground": "100",
|
|
14103
|
+
popup: "100",
|
|
14104
|
+
"popup-foreground": "100",
|
|
14105
|
+
primary: "950",
|
|
14106
|
+
"primary-foreground": "950",
|
|
14107
|
+
secondary: "100",
|
|
14108
|
+
"secondary-foreground": "100",
|
|
14109
|
+
muted: "400",
|
|
14110
|
+
"muted-foreground": "400",
|
|
14111
|
+
accent: "100",
|
|
14112
|
+
"accent-foreground": "100",
|
|
14113
|
+
destructive: "950",
|
|
14114
|
+
"destructive-foreground": "950",
|
|
14115
|
+
success: "950",
|
|
14116
|
+
"success-foreground": "950",
|
|
14117
|
+
warning: "950",
|
|
14118
|
+
"warning-foreground": "950",
|
|
14119
|
+
info: "950",
|
|
14120
|
+
"info-foreground": "950",
|
|
14121
|
+
border: "100",
|
|
14122
|
+
input: "100",
|
|
14123
|
+
ring: "950"
|
|
14124
|
+
}
|
|
14125
|
+
};
|
|
14126
|
+
function normalizeName(value) {
|
|
14127
|
+
return value.trim().toLowerCase();
|
|
14128
|
+
}
|
|
14129
|
+
function normalizeColorValue(value) {
|
|
14130
|
+
const trimmed = value.trim();
|
|
14131
|
+
if (trimmed.startsWith("oklch(")) {
|
|
14132
|
+
return trimmed.slice(6, -1).trim();
|
|
14133
|
+
}
|
|
14134
|
+
return trimmed;
|
|
14135
|
+
}
|
|
14136
|
+
function isValidScale(value) {
|
|
14137
|
+
if (!value || typeof value !== "object") return false;
|
|
14138
|
+
return SHADE_STEPS.every((step) => typeof value[step] === "string");
|
|
14139
|
+
}
|
|
14140
|
+
function getCacheFilePath() {
|
|
14141
|
+
return path3.join(os.homedir(), ".shapes-ui", "cache", "tailwind-colors-v4.json");
|
|
14142
|
+
}
|
|
14143
|
+
async function readCache() {
|
|
14144
|
+
const cachePath = getCacheFilePath();
|
|
14145
|
+
if (!await fs4.pathExists(cachePath)) return null;
|
|
14146
|
+
const payload = await fs4.readJSON(cachePath);
|
|
14147
|
+
if (payload.version !== CACHE_VERSION || !payload.palettes || typeof payload.palettes !== "object") {
|
|
14148
|
+
return null;
|
|
14149
|
+
}
|
|
14150
|
+
const validated = {};
|
|
14151
|
+
for (const [name, scale] of Object.entries(payload.palettes)) {
|
|
14152
|
+
if (isValidScale(scale)) {
|
|
14153
|
+
validated[normalizeName(name)] = scale;
|
|
14154
|
+
}
|
|
14155
|
+
}
|
|
14156
|
+
return Object.keys(validated).length > 0 ? validated : null;
|
|
14157
|
+
}
|
|
14158
|
+
async function writeCache(palettes) {
|
|
14159
|
+
const cachePath = getCacheFilePath();
|
|
14160
|
+
await fs4.ensureDir(path3.dirname(cachePath));
|
|
14161
|
+
const payload = {
|
|
14162
|
+
version: CACHE_VERSION,
|
|
14163
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14164
|
+
palettes
|
|
14165
|
+
};
|
|
14166
|
+
await fs4.writeJSON(cachePath, payload, { spaces: 2 });
|
|
14167
|
+
}
|
|
14168
|
+
async function loadFromTailwindPackage() {
|
|
14169
|
+
try {
|
|
14170
|
+
const colorsModule = await import("tailwindcss/colors");
|
|
14171
|
+
const source = colorsModule.default ?? colorsModule;
|
|
14172
|
+
const palettes = {};
|
|
14173
|
+
for (const [familyName, rawScale] of Object.entries(source)) {
|
|
14174
|
+
if (!rawScale || typeof rawScale !== "object") continue;
|
|
14175
|
+
const family = normalizeName(familyName);
|
|
14176
|
+
const scale = rawScale;
|
|
14177
|
+
const next = {};
|
|
14178
|
+
for (const step of SHADE_STEPS) {
|
|
14179
|
+
const value = scale[step];
|
|
14180
|
+
if (typeof value !== "string") {
|
|
14181
|
+
next[step] = void 0;
|
|
14182
|
+
continue;
|
|
14183
|
+
}
|
|
14184
|
+
next[step] = normalizeColorValue(value);
|
|
14185
|
+
}
|
|
14186
|
+
if (isValidScale(next)) {
|
|
14187
|
+
palettes[family] = next;
|
|
14188
|
+
}
|
|
14189
|
+
}
|
|
14190
|
+
return Object.keys(palettes).length > 0 ? palettes : null;
|
|
14191
|
+
} catch {
|
|
14192
|
+
return null;
|
|
14193
|
+
}
|
|
14194
|
+
}
|
|
14195
|
+
function parseTailwindColorsFromDocs(markup) {
|
|
14196
|
+
const regex = /--color-([a-z]+)-(50|100|200|300|400|500|600|700|800|900|950)\s*:\s*(oklch\([^)]+\))/g;
|
|
14197
|
+
const palettes = {};
|
|
14198
|
+
let match = regex.exec(markup);
|
|
14199
|
+
while (match) {
|
|
14200
|
+
const family = normalizeName(match[1]);
|
|
14201
|
+
const shade = match[2];
|
|
14202
|
+
const value = normalizeColorValue(match[3]);
|
|
14203
|
+
palettes[family] ??= {};
|
|
14204
|
+
palettes[family][shade] = value;
|
|
14205
|
+
match = regex.exec(markup);
|
|
14206
|
+
}
|
|
14207
|
+
const validated = {};
|
|
14208
|
+
for (const [family, scale] of Object.entries(palettes)) {
|
|
14209
|
+
if (isValidScale(scale)) {
|
|
14210
|
+
validated[family] = scale;
|
|
14211
|
+
}
|
|
14212
|
+
}
|
|
14213
|
+
return validated;
|
|
14214
|
+
}
|
|
14215
|
+
async function loadFromRemote() {
|
|
14216
|
+
try {
|
|
14217
|
+
const response = await fetch(TAILWIND_COLORS_URL);
|
|
14218
|
+
if (!response.ok) return null;
|
|
14219
|
+
const markup = await response.text();
|
|
14220
|
+
const palettes = parseTailwindColorsFromDocs(markup);
|
|
14221
|
+
if (Object.keys(palettes).length === 0) return null;
|
|
14222
|
+
return palettes;
|
|
14223
|
+
} catch {
|
|
14224
|
+
return null;
|
|
14225
|
+
}
|
|
14226
|
+
}
|
|
14227
|
+
async function resolvePaletteSource(refresh = false) {
|
|
14228
|
+
if (!refresh) {
|
|
14229
|
+
const fromCache2 = await readCache();
|
|
14230
|
+
if (fromCache2) {
|
|
14231
|
+
return { source: "cache", palettes: fromCache2 };
|
|
14232
|
+
}
|
|
14233
|
+
}
|
|
14234
|
+
const fromRemote = await loadFromRemote();
|
|
14235
|
+
if (fromRemote) {
|
|
14236
|
+
await writeCache(fromRemote);
|
|
14237
|
+
return { source: "remote", palettes: fromRemote };
|
|
14238
|
+
}
|
|
14239
|
+
const fromCache = await readCache();
|
|
14240
|
+
if (fromCache) {
|
|
14241
|
+
return { source: "cache", palettes: fromCache };
|
|
14242
|
+
}
|
|
14243
|
+
const fromPackage = await loadFromTailwindPackage();
|
|
14244
|
+
if (fromPackage) {
|
|
14245
|
+
return { source: "package", palettes: fromPackage };
|
|
14246
|
+
}
|
|
14247
|
+
throw new Error("Could not load Tailwind color palettes from docs, cache, or local package.");
|
|
14248
|
+
}
|
|
14249
|
+
function resolveFamily(palettes, familyName) {
|
|
14250
|
+
const family = normalizeName(familyName);
|
|
14251
|
+
const scale = palettes[family];
|
|
14252
|
+
if (!scale) {
|
|
14253
|
+
const available = Object.keys(palettes).sort().join(", ");
|
|
14254
|
+
throw new Error(`Palette "${familyName}" is not available. Available palettes: ${available}`);
|
|
14255
|
+
}
|
|
14256
|
+
return { family, scale };
|
|
14257
|
+
}
|
|
14258
|
+
function parseLightness(value) {
|
|
14259
|
+
const first = value.split(/\s+/)[0]?.trim() ?? "";
|
|
14260
|
+
if (!first) return Number.NaN;
|
|
14261
|
+
if (first.endsWith("%")) {
|
|
14262
|
+
return Number.parseFloat(first.slice(0, -1));
|
|
14263
|
+
}
|
|
14264
|
+
const numeric = Number.parseFloat(first);
|
|
14265
|
+
if (Number.isNaN(numeric)) return Number.NaN;
|
|
14266
|
+
return numeric <= 1 ? numeric * 100 : numeric;
|
|
14267
|
+
}
|
|
14268
|
+
function pickDynamicForegroundShade(scale, backgroundShade) {
|
|
14269
|
+
const backgroundValue = scale[backgroundShade];
|
|
14270
|
+
const backgroundLightness = parseLightness(backgroundValue);
|
|
14271
|
+
if (!Number.isFinite(backgroundLightness)) {
|
|
14272
|
+
return backgroundShade === "950" ? "50" : "950";
|
|
14273
|
+
}
|
|
14274
|
+
let bestShade = "950";
|
|
14275
|
+
let bestDelta = -1;
|
|
14276
|
+
for (const shade of SHADE_STEPS) {
|
|
14277
|
+
const delta = Math.abs(parseLightness(scale[shade]) - backgroundLightness);
|
|
14278
|
+
if (delta > bestDelta) {
|
|
14279
|
+
bestDelta = delta;
|
|
14280
|
+
bestShade = shade;
|
|
14281
|
+
}
|
|
14282
|
+
}
|
|
14283
|
+
return bestShade;
|
|
14284
|
+
}
|
|
14285
|
+
function buildAssignments(brandFamily, neutralFamily) {
|
|
14286
|
+
return {
|
|
14287
|
+
light: {
|
|
14288
|
+
background: { family: neutralFamily, shade: "50" },
|
|
14289
|
+
foreground: { family: neutralFamily, shade: "950" },
|
|
14290
|
+
card: { family: neutralFamily, shade: "50" },
|
|
14291
|
+
"card-foreground": { family: neutralFamily, shade: "950" },
|
|
14292
|
+
popup: { family: neutralFamily, shade: "50" },
|
|
14293
|
+
"popup-foreground": { family: neutralFamily, shade: "950" },
|
|
14294
|
+
primary: { family: brandFamily, shade: "600" },
|
|
14295
|
+
"primary-foreground": { family: brandFamily, shade: "50" },
|
|
14296
|
+
secondary: { family: neutralFamily, shade: "100" },
|
|
14297
|
+
"secondary-foreground": { family: neutralFamily, shade: "900" },
|
|
14298
|
+
muted: { family: neutralFamily, shade: "100" },
|
|
14299
|
+
"muted-foreground": { family: neutralFamily, shade: "500" },
|
|
14300
|
+
accent: { family: brandFamily, shade: "100" },
|
|
14301
|
+
"accent-foreground": { family: brandFamily, shade: "900" },
|
|
14302
|
+
destructive: { family: "red", shade: "600" },
|
|
14303
|
+
"destructive-foreground": { family: "red", shade: "50" },
|
|
14304
|
+
success: { family: "green", shade: "600" },
|
|
14305
|
+
"success-foreground": { family: "green", shade: "50" },
|
|
14306
|
+
warning: { family: "amber", shade: "500" },
|
|
14307
|
+
"warning-foreground": { family: "amber", shade: "950" },
|
|
14308
|
+
info: { family: brandFamily, shade: "600" },
|
|
14309
|
+
"info-foreground": { family: brandFamily, shade: "50" },
|
|
14310
|
+
border: { family: neutralFamily, shade: "200" },
|
|
14311
|
+
input: { family: neutralFamily, shade: "300" },
|
|
14312
|
+
ring: { family: brandFamily, shade: "500" }
|
|
14313
|
+
},
|
|
14314
|
+
dark: {
|
|
14315
|
+
background: { family: neutralFamily, shade: "950" },
|
|
14316
|
+
foreground: { family: neutralFamily, shade: "50" },
|
|
14317
|
+
card: { family: neutralFamily, shade: "900" },
|
|
14318
|
+
"card-foreground": { family: neutralFamily, shade: "100" },
|
|
14319
|
+
popup: { family: neutralFamily, shade: "900" },
|
|
14320
|
+
"popup-foreground": { family: neutralFamily, shade: "100" },
|
|
14321
|
+
primary: { family: brandFamily, shade: "500" },
|
|
14322
|
+
"primary-foreground": { family: brandFamily, shade: "950" },
|
|
14323
|
+
secondary: { family: neutralFamily, shade: "800" },
|
|
14324
|
+
"secondary-foreground": { family: neutralFamily, shade: "100" },
|
|
14325
|
+
muted: { family: neutralFamily, shade: "800" },
|
|
14326
|
+
"muted-foreground": { family: neutralFamily, shade: "400" },
|
|
14327
|
+
accent: { family: brandFamily, shade: "800" },
|
|
14328
|
+
"accent-foreground": { family: brandFamily, shade: "100" },
|
|
14329
|
+
destructive: { family: "red", shade: "500" },
|
|
14330
|
+
"destructive-foreground": { family: "red", shade: "950" },
|
|
14331
|
+
success: { family: "green", shade: "500" },
|
|
14332
|
+
"success-foreground": { family: "green", shade: "950" },
|
|
14333
|
+
warning: { family: "amber", shade: "500" },
|
|
14334
|
+
"warning-foreground": { family: "amber", shade: "950" },
|
|
14335
|
+
info: { family: brandFamily, shade: "500" },
|
|
14336
|
+
"info-foreground": { family: brandFamily, shade: "950" },
|
|
14337
|
+
border: { family: neutralFamily, shade: "800" },
|
|
14338
|
+
input: { family: neutralFamily, shade: "700" },
|
|
14339
|
+
ring: { family: brandFamily, shade: "400" }
|
|
14340
|
+
}
|
|
14341
|
+
};
|
|
14342
|
+
}
|
|
14343
|
+
function assignForegrounds(palettes, assignments, contrastMode) {
|
|
14344
|
+
if (contrastMode === "deterministic") {
|
|
14345
|
+
for (const mode of ["light", "dark"]) {
|
|
14346
|
+
for (const pair of FOREGROUND_PAIRS) {
|
|
14347
|
+
const bg = assignments[mode][pair.background];
|
|
14348
|
+
assignments[mode][pair.foreground] = {
|
|
14349
|
+
family: bg.family,
|
|
14350
|
+
shade: DETERMINISTIC_FOREGROUND_SHADE[mode][pair.background]
|
|
14351
|
+
};
|
|
14352
|
+
}
|
|
14353
|
+
}
|
|
14354
|
+
return;
|
|
14355
|
+
}
|
|
14356
|
+
for (const mode of ["light", "dark"]) {
|
|
14357
|
+
for (const pair of FOREGROUND_PAIRS) {
|
|
14358
|
+
const background = assignments[mode][pair.background];
|
|
14359
|
+
const scale = palettes[background.family];
|
|
14360
|
+
if (!scale) continue;
|
|
14361
|
+
assignments[mode][pair.foreground] = {
|
|
14362
|
+
family: background.family,
|
|
14363
|
+
shade: pickDynamicForegroundShade(scale, background.shade)
|
|
14364
|
+
};
|
|
14365
|
+
}
|
|
14366
|
+
}
|
|
14367
|
+
}
|
|
14368
|
+
function resolveTokenThemes(palettes, brandFamily, neutralFamily, contrastMode) {
|
|
14369
|
+
const assignments = buildAssignments(brandFamily, neutralFamily);
|
|
14370
|
+
assignForegrounds(palettes, assignments, contrastMode);
|
|
14371
|
+
const result = {
|
|
14372
|
+
light: {},
|
|
14373
|
+
dark: {}
|
|
14374
|
+
};
|
|
14375
|
+
for (const mode of ["light", "dark"]) {
|
|
14376
|
+
for (const [role, ref] of Object.entries(assignments[mode])) {
|
|
14377
|
+
const scale = palettes[ref.family];
|
|
14378
|
+
if (!scale) {
|
|
14379
|
+
throw new Error(`Palette "${ref.family}" is missing required shades.`);
|
|
14380
|
+
}
|
|
14381
|
+
result[mode][role] = scale[ref.shade];
|
|
14382
|
+
}
|
|
14383
|
+
}
|
|
14384
|
+
return result;
|
|
14385
|
+
}
|
|
14386
|
+
function formatThemeBlock(theme) {
|
|
14387
|
+
return [
|
|
14388
|
+
` --background: oklch(${theme.background});`,
|
|
14389
|
+
` --foreground: oklch(${theme.foreground});`,
|
|
14390
|
+
` --card: oklch(${theme.card});`,
|
|
14391
|
+
` --card-foreground: oklch(${theme["card-foreground"]});`,
|
|
14392
|
+
` --popup: oklch(${theme.popup});`,
|
|
14393
|
+
` --popup-foreground: oklch(${theme["popup-foreground"]});`,
|
|
14394
|
+
` --primary: oklch(${theme.primary});`,
|
|
14395
|
+
` --primary-foreground: oklch(${theme["primary-foreground"]});`,
|
|
14396
|
+
` --secondary: oklch(${theme.secondary});`,
|
|
14397
|
+
` --secondary-foreground: oklch(${theme["secondary-foreground"]});`,
|
|
14398
|
+
` --muted: oklch(${theme.muted});`,
|
|
14399
|
+
` --muted-foreground: oklch(${theme["muted-foreground"]});`,
|
|
14400
|
+
` --accent: oklch(${theme.accent});`,
|
|
14401
|
+
` --accent-foreground: oklch(${theme["accent-foreground"]});`,
|
|
14402
|
+
` --destructive: oklch(${theme.destructive});`,
|
|
14403
|
+
` --destructive-foreground: oklch(${theme["destructive-foreground"]});`,
|
|
14404
|
+
` --success: oklch(${theme.success});`,
|
|
14405
|
+
` --success-foreground: oklch(${theme["success-foreground"]});`,
|
|
14406
|
+
` --warning: oklch(${theme.warning});`,
|
|
14407
|
+
` --warning-foreground: oklch(${theme["warning-foreground"]});`,
|
|
14408
|
+
` --info: oklch(${theme.info});`,
|
|
14409
|
+
` --info-foreground: oklch(${theme["info-foreground"]});`,
|
|
14410
|
+
` --border: oklch(${theme.border});`,
|
|
14411
|
+
` --input: oklch(${theme.input});`,
|
|
14412
|
+
` --ring: oklch(${theme.ring});`
|
|
14413
|
+
].join("\n");
|
|
14414
|
+
}
|
|
14415
|
+
function buildTokenBlock(assignments, result) {
|
|
14416
|
+
return [
|
|
14417
|
+
MARKER_START,
|
|
14418
|
+
`/* source=${result.source} palette=${result.paletteName} neutral=${result.neutralPalette} contrast=${result.contrastMode} */`,
|
|
14419
|
+
":root {",
|
|
14420
|
+
formatThemeBlock(assignments.light),
|
|
14421
|
+
"}",
|
|
14422
|
+
"",
|
|
14423
|
+
".dark {",
|
|
14424
|
+
formatThemeBlock(assignments.dark),
|
|
14425
|
+
"}",
|
|
14426
|
+
"",
|
|
14427
|
+
"@theme inline {",
|
|
14428
|
+
" --color-background: var(--background);",
|
|
14429
|
+
" --color-foreground: var(--foreground);",
|
|
14430
|
+
" --color-card: var(--card);",
|
|
14431
|
+
" --color-card-foreground: var(--card-foreground);",
|
|
14432
|
+
" --color-popup: var(--popup);",
|
|
14433
|
+
" --color-popup-foreground: var(--popup-foreground);",
|
|
14434
|
+
" --color-primary: var(--primary);",
|
|
14435
|
+
" --color-primary-foreground: var(--primary-foreground);",
|
|
14436
|
+
" --color-secondary: var(--secondary);",
|
|
14437
|
+
" --color-secondary-foreground: var(--secondary-foreground);",
|
|
14438
|
+
" --color-muted: var(--muted);",
|
|
14439
|
+
" --color-muted-foreground: var(--muted-foreground);",
|
|
14440
|
+
" --color-accent: var(--accent);",
|
|
14441
|
+
" --color-accent-foreground: var(--accent-foreground);",
|
|
14442
|
+
" --color-destructive: var(--destructive);",
|
|
14443
|
+
" --color-destructive-foreground: var(--destructive-foreground);",
|
|
14444
|
+
" --color-success: var(--success);",
|
|
14445
|
+
" --color-success-foreground: var(--success-foreground);",
|
|
14446
|
+
" --color-warning: var(--warning);",
|
|
14447
|
+
" --color-warning-foreground: var(--warning-foreground);",
|
|
14448
|
+
" --color-info: var(--info);",
|
|
14449
|
+
" --color-info-foreground: var(--info-foreground);",
|
|
14450
|
+
" --color-border: var(--border);",
|
|
14451
|
+
" --color-input: var(--input);",
|
|
14452
|
+
" --color-ring: var(--ring);",
|
|
14453
|
+
"}",
|
|
14454
|
+
MARKER_END
|
|
14455
|
+
].join("\n");
|
|
14456
|
+
}
|
|
14457
|
+
function upsertGeneratedBlock(current, generatedBlock) {
|
|
14458
|
+
const hasStart = current.includes(MARKER_START);
|
|
14459
|
+
const hasEnd = current.includes(MARKER_END);
|
|
14460
|
+
if (hasStart !== hasEnd) {
|
|
14461
|
+
throw new Error("Found an incomplete generated token block. Please fix it manually and retry.");
|
|
14462
|
+
}
|
|
14463
|
+
if (!hasStart) {
|
|
14464
|
+
const trimmed = current.trimEnd();
|
|
14465
|
+
return `${trimmed}
|
|
14466
|
+
|
|
14467
|
+
${generatedBlock}
|
|
14468
|
+
`;
|
|
14469
|
+
}
|
|
14470
|
+
const startIndex = current.indexOf(MARKER_START);
|
|
14471
|
+
const endIndex = current.indexOf(MARKER_END);
|
|
14472
|
+
if (startIndex === -1 || endIndex === -1 || endIndex < startIndex) {
|
|
14473
|
+
throw new Error("Could not safely update generated token block.");
|
|
14474
|
+
}
|
|
14475
|
+
const endMarkerIndex = endIndex + MARKER_END.length;
|
|
14476
|
+
const before = current.slice(0, startIndex).trimEnd();
|
|
14477
|
+
const after = current.slice(endMarkerIndex).trimStart();
|
|
14478
|
+
if (!before && !after) {
|
|
14479
|
+
return `${generatedBlock}
|
|
14480
|
+
`;
|
|
14481
|
+
}
|
|
14482
|
+
if (!after) {
|
|
14483
|
+
return `${before}
|
|
14484
|
+
|
|
14485
|
+
${generatedBlock}
|
|
14486
|
+
`;
|
|
14487
|
+
}
|
|
14488
|
+
if (!before) {
|
|
14489
|
+
return `${generatedBlock}
|
|
14490
|
+
|
|
14491
|
+
${after}`;
|
|
14492
|
+
}
|
|
14493
|
+
return `${before}
|
|
14494
|
+
|
|
14495
|
+
${generatedBlock}
|
|
14496
|
+
|
|
14497
|
+
${after}`;
|
|
14498
|
+
}
|
|
14499
|
+
function getDefaultBrandPaletteOptions() {
|
|
14500
|
+
return [...DEFAULT_BRAND_PALETTES];
|
|
14501
|
+
}
|
|
14502
|
+
function normalizeContrastMode(value) {
|
|
14503
|
+
const normalized = value ? value.trim().toLowerCase() : "deterministic";
|
|
14504
|
+
if (normalized === "deterministic" || normalized === "dynamic") {
|
|
14505
|
+
return normalized;
|
|
14506
|
+
}
|
|
14507
|
+
throw new Error(`Invalid contrast mode "${value}". Use deterministic or dynamic.`);
|
|
14508
|
+
}
|
|
14509
|
+
async function writePaletteTokens(options) {
|
|
14510
|
+
const cwd = options.cwd ?? process.cwd();
|
|
14511
|
+
const cssFilePath = path3.join(cwd, options.cssPath);
|
|
14512
|
+
const resolved = await resolvePaletteSource(options.refresh);
|
|
14513
|
+
const brand = resolveFamily(resolved.palettes, options.paletteName);
|
|
14514
|
+
const neutral = resolveFamily(resolved.palettes, options.neutralPalette);
|
|
14515
|
+
resolveFamily(resolved.palettes, "red");
|
|
14516
|
+
resolveFamily(resolved.palettes, "green");
|
|
14517
|
+
resolveFamily(resolved.palettes, "amber");
|
|
14518
|
+
const result = {
|
|
14519
|
+
source: resolved.source,
|
|
14520
|
+
paletteName: brand.family,
|
|
14521
|
+
neutralPalette: neutral.family,
|
|
14522
|
+
contrastMode: options.contrastMode
|
|
14523
|
+
};
|
|
14524
|
+
const assignments = resolveTokenThemes(
|
|
14525
|
+
resolved.palettes,
|
|
14526
|
+
brand.family,
|
|
14527
|
+
neutral.family,
|
|
14528
|
+
options.contrastMode
|
|
14529
|
+
);
|
|
14530
|
+
const generatedBlock = buildTokenBlock(assignments, result);
|
|
14531
|
+
const current = await fs4.pathExists(cssFilePath) ? await fs4.readFile(cssFilePath, "utf-8") : "";
|
|
14532
|
+
const updated = upsertGeneratedBlock(current, generatedBlock);
|
|
14533
|
+
await fs4.ensureDir(path3.dirname(cssFilePath));
|
|
14534
|
+
await fs4.writeFile(cssFilePath, updated);
|
|
14535
|
+
return result;
|
|
14536
|
+
}
|
|
14537
|
+
|
|
14538
|
+
// src/commands/create.ts
|
|
13972
14539
|
var BASE_DEPS = [
|
|
13973
14540
|
"@base-ui/react",
|
|
13974
14541
|
"class-variance-authority",
|
|
@@ -13977,44 +14544,229 @@ var BASE_DEPS = [
|
|
|
13977
14544
|
"tailwind-merge",
|
|
13978
14545
|
"tw-animate-css"
|
|
13979
14546
|
];
|
|
14547
|
+
async function ensureTailwindStyles(cwd, cssPath) {
|
|
14548
|
+
const template = '@import "tailwindcss";\n';
|
|
14549
|
+
const absPath = path4.join(cwd, cssPath);
|
|
14550
|
+
await fs5.ensureDir(path4.dirname(absPath));
|
|
14551
|
+
if (await fs5.pathExists(absPath)) {
|
|
14552
|
+
const current = await fs5.readFile(absPath, "utf-8");
|
|
14553
|
+
if (current.includes("tailwindcss") || current.includes("@tailwind")) return;
|
|
14554
|
+
await fs5.writeFile(absPath, `${current.trimEnd()}
|
|
14555
|
+
|
|
14556
|
+
${template}`);
|
|
14557
|
+
return;
|
|
14558
|
+
}
|
|
14559
|
+
await fs5.writeFile(absPath, template);
|
|
14560
|
+
}
|
|
14561
|
+
async function setupShapesFull(projectDir, options) {
|
|
14562
|
+
const setupSpin = spinner3();
|
|
14563
|
+
setupSpin.start("Configuring Shapes UI");
|
|
14564
|
+
const cssPath = options.cssPath ?? "src/index.css";
|
|
14565
|
+
const uiPath = options.uiPath ?? "./src/components/ui";
|
|
14566
|
+
const style = options.style ?? "default";
|
|
14567
|
+
const palette = options.palette ?? "blue";
|
|
14568
|
+
const contrastMode = options.contrastMode ?? "deterministic";
|
|
14569
|
+
const pkg = await readPackageJson(projectDir);
|
|
14570
|
+
const hasTailwindV4 = isTailwindV4Installed(pkg);
|
|
14571
|
+
const isVite = await isViteProject(projectDir);
|
|
14572
|
+
if (!hasTailwindV4) {
|
|
14573
|
+
const tailwindDeps = ["tailwindcss"];
|
|
14574
|
+
if (isVite) {
|
|
14575
|
+
tailwindDeps.push("@tailwindcss/vite");
|
|
14576
|
+
}
|
|
14577
|
+
await installDependencies(tailwindDeps, {
|
|
14578
|
+
dev: true,
|
|
14579
|
+
label: "Installing Tailwind dependencies",
|
|
14580
|
+
successMessage: "Tailwind dependencies installed",
|
|
14581
|
+
cwd: projectDir
|
|
14582
|
+
});
|
|
14583
|
+
}
|
|
14584
|
+
const latestPkg = await readPackageJson(projectDir);
|
|
14585
|
+
const missingBaseDeps = getMissingDeps(latestPkg, BASE_DEPS);
|
|
14586
|
+
await installDependencies(missingBaseDeps, {
|
|
14587
|
+
label: "Installing Shapes base dependencies",
|
|
14588
|
+
successMessage: "Shapes base dependencies installed",
|
|
14589
|
+
cwd: projectDir
|
|
14590
|
+
});
|
|
14591
|
+
await ensureTailwindStyles(projectDir, cssPath);
|
|
14592
|
+
const paletteResult = await writePaletteTokens({
|
|
14593
|
+
cwd: projectDir,
|
|
14594
|
+
cssPath,
|
|
14595
|
+
paletteName: palette,
|
|
14596
|
+
neutralPalette: "zinc",
|
|
14597
|
+
contrastMode
|
|
14598
|
+
});
|
|
14599
|
+
const config2 = {
|
|
14600
|
+
$schema: "https://shapes-ui.com/schema.json",
|
|
14601
|
+
style,
|
|
14602
|
+
palette: {
|
|
14603
|
+
name: paletteResult.paletteName,
|
|
14604
|
+
contrastMode: paletteResult.contrastMode
|
|
14605
|
+
},
|
|
14606
|
+
tailwind: { css: cssPath, baseColor: "zinc" },
|
|
14607
|
+
paths: { ui: uiPath, lib: "./src/lib" }
|
|
14608
|
+
};
|
|
14609
|
+
await fs5.writeJSON(path4.join(projectDir, "shapes.json"), config2, { spaces: 2 });
|
|
14610
|
+
await addAllComponents(config2, projectDir);
|
|
14611
|
+
setupSpin.stop("Shapes UI configured with all components");
|
|
14612
|
+
}
|
|
14613
|
+
function getCreateCommand(packageManager, projectName) {
|
|
14614
|
+
if (packageManager === "pnpm") {
|
|
14615
|
+
return ["pnpm", ["create", "vite", projectName, "--template", "react-ts"]];
|
|
14616
|
+
}
|
|
14617
|
+
if (packageManager === "yarn") {
|
|
14618
|
+
return ["yarn", ["create", "vite", projectName, "--template", "react-ts"]];
|
|
14619
|
+
}
|
|
14620
|
+
if (packageManager === "bun") {
|
|
14621
|
+
return ["bun", ["create", "vite", projectName, "--template", "react-ts"]];
|
|
14622
|
+
}
|
|
14623
|
+
return ["npm", ["create", "vite@latest", projectName, "--", "--template", "react-ts"]];
|
|
14624
|
+
}
|
|
14625
|
+
function getProjectInstallCommand(packageManager) {
|
|
14626
|
+
if (packageManager === "pnpm") {
|
|
14627
|
+
return ["pnpm", ["install"]];
|
|
14628
|
+
}
|
|
14629
|
+
if (packageManager === "yarn") {
|
|
14630
|
+
return ["yarn", ["install"]];
|
|
14631
|
+
}
|
|
14632
|
+
if (packageManager === "bun") {
|
|
14633
|
+
return ["bun", ["install"]];
|
|
14634
|
+
}
|
|
14635
|
+
return ["npm", ["install"]];
|
|
14636
|
+
}
|
|
14637
|
+
async function createCommand(projectNameArg, options = {}) {
|
|
14638
|
+
intro(pc.bgCyan(pc.black(" Create a Shapes UI app ")));
|
|
14639
|
+
const allowedStyles = /* @__PURE__ */ new Set(["default", "brutalist", "minimal"]);
|
|
14640
|
+
if (options.style && !allowedStyles.has(options.style)) {
|
|
14641
|
+
throw new Error(`Invalid style "${options.style}". Use one of: default, brutalist, minimal.`);
|
|
14642
|
+
}
|
|
14643
|
+
if (options.palette) {
|
|
14644
|
+
const normalizedPalette = options.palette.toLowerCase();
|
|
14645
|
+
const allowedPalettes = new Set(getDefaultBrandPaletteOptions());
|
|
14646
|
+
if (!allowedPalettes.has(normalizedPalette)) {
|
|
14647
|
+
throw new Error(
|
|
14648
|
+
`Invalid palette "${options.palette}". Use one of: ${getDefaultBrandPaletteOptions().join(", ")}.`
|
|
14649
|
+
);
|
|
14650
|
+
}
|
|
14651
|
+
options.palette = normalizedPalette;
|
|
14652
|
+
}
|
|
14653
|
+
if (options.contrastMode) {
|
|
14654
|
+
options.contrastMode = normalizeContrastMode(options.contrastMode);
|
|
14655
|
+
}
|
|
14656
|
+
if (options.uiPath !== void 0 && !options.uiPath.trim()) {
|
|
14657
|
+
throw new Error("Invalid ui path. Please provide a non-empty value.");
|
|
14658
|
+
}
|
|
14659
|
+
if (options.cssPath !== void 0 && !options.cssPath.trim()) {
|
|
14660
|
+
throw new Error("Invalid css path. Please provide a non-empty value.");
|
|
14661
|
+
}
|
|
14662
|
+
const projectName = projectNameArg && projectNameArg.trim().length > 0 ? projectNameArg.trim() : exitIfCancelled(
|
|
14663
|
+
await text({
|
|
14664
|
+
message: "Project name",
|
|
14665
|
+
initialValue: "my-shapes-app",
|
|
14666
|
+
validate(value) {
|
|
14667
|
+
if (!value || !value.trim()) return "Project name is required.";
|
|
14668
|
+
return void 0;
|
|
14669
|
+
}
|
|
14670
|
+
})
|
|
14671
|
+
).trim();
|
|
14672
|
+
const projectDir = path4.resolve(process.cwd(), projectName);
|
|
14673
|
+
const exists = await fs5.pathExists(projectDir);
|
|
14674
|
+
if (exists) {
|
|
14675
|
+
const overwrite = options.force ?? exitIfCancelled(
|
|
14676
|
+
await confirm({
|
|
14677
|
+
message: `${projectName} already exists. Overwrite it?`,
|
|
14678
|
+
initialValue: false
|
|
14679
|
+
})
|
|
14680
|
+
);
|
|
14681
|
+
if (!overwrite) {
|
|
14682
|
+
outro(pc.yellow("Create cancelled."));
|
|
14683
|
+
return;
|
|
14684
|
+
}
|
|
14685
|
+
await fs5.remove(projectDir);
|
|
14686
|
+
}
|
|
14687
|
+
const packageManager = await getPackageManager();
|
|
14688
|
+
const [createCommandName, createArgs] = getCreateCommand(packageManager, projectName);
|
|
14689
|
+
const createSpin = spinner3();
|
|
14690
|
+
createSpin.start(`Scaffolding ${projectName}`);
|
|
14691
|
+
await execa2(createCommandName, createArgs, { stdio: "ignore" });
|
|
14692
|
+
createSpin.stop(`Created ${projectName}`);
|
|
14693
|
+
note2(`Project scaffolded with ${packageManager} + Vite (React + TypeScript).`, "Create");
|
|
14694
|
+
const shouldInstallProjectDeps = options.install || options.full;
|
|
14695
|
+
if (shouldInstallProjectDeps) {
|
|
14696
|
+
const [installCommand, installArgs] = getProjectInstallCommand(packageManager);
|
|
14697
|
+
const installSpin = spinner3();
|
|
14698
|
+
installSpin.start("Installing project dependencies");
|
|
14699
|
+
await execa2(installCommand, installArgs, {
|
|
14700
|
+
cwd: projectDir,
|
|
14701
|
+
stdio: "ignore"
|
|
14702
|
+
});
|
|
14703
|
+
installSpin.stop("Dependencies installed");
|
|
14704
|
+
}
|
|
14705
|
+
if (options.full) {
|
|
14706
|
+
await setupShapesFull(projectDir, options);
|
|
14707
|
+
}
|
|
14708
|
+
const runShapesInit = `${packageManager === "npm" ? "npx" : packageManager === "pnpm" ? "pnpm dlx" : packageManager === "yarn" ? "yarn dlx" : "bunx"} shapes-ui init`;
|
|
14709
|
+
outro(
|
|
14710
|
+
`${pc.green(options.full ? "Project ready with Shapes UI." : "Project ready.")}
|
|
14711
|
+
|
|
14712
|
+
${pc.bold("Next steps:")}
|
|
14713
|
+
cd ${projectName}
|
|
14714
|
+
${shouldInstallProjectDeps ? "" : `${packageManager} install
|
|
14715
|
+
`}${options.full ? "" : `${runShapesInit}
|
|
14716
|
+
`} ${packageManager} run dev`
|
|
14717
|
+
);
|
|
14718
|
+
}
|
|
14719
|
+
|
|
14720
|
+
// src/commands/init.ts
|
|
14721
|
+
import path5 from "path";
|
|
14722
|
+
import { confirm as confirm2, intro as intro2, note as note3, outro as outro2, select, text as text2 } from "@clack/prompts";
|
|
14723
|
+
import figlet from "figlet";
|
|
14724
|
+
import fs6 from "fs-extra";
|
|
14725
|
+
import gradient from "gradient-string";
|
|
14726
|
+
import pc2 from "picocolors";
|
|
14727
|
+
var BASE_DEPS2 = [
|
|
14728
|
+
"@base-ui/react",
|
|
14729
|
+
"class-variance-authority",
|
|
14730
|
+
"clsx",
|
|
14731
|
+
"lucide-react",
|
|
14732
|
+
"tailwind-merge",
|
|
14733
|
+
"tw-animate-css"
|
|
14734
|
+
];
|
|
13980
14735
|
async function installDeps(deps, dev = false) {
|
|
13981
|
-
|
|
13982
|
-
|
|
13983
|
-
|
|
13984
|
-
|
|
13985
|
-
const [command, ...args] = await getInstallCommand(deps, dev);
|
|
13986
|
-
await execa2(command, args);
|
|
13987
|
-
spin.stop(pc.green("Dependencies installed"));
|
|
14736
|
+
await installDependencies(deps, {
|
|
14737
|
+
dev,
|
|
14738
|
+
successMessage: pc2.green("Dependencies installed")
|
|
14739
|
+
});
|
|
13988
14740
|
}
|
|
13989
|
-
async function
|
|
14741
|
+
async function ensureTailwindStyles2(cssPath) {
|
|
13990
14742
|
const template = '@import "tailwindcss";\n';
|
|
13991
|
-
const absPath =
|
|
13992
|
-
await
|
|
13993
|
-
if (await
|
|
13994
|
-
const current = await
|
|
14743
|
+
const absPath = path5.join(process.cwd(), cssPath);
|
|
14744
|
+
await fs6.ensureDir(path5.dirname(absPath));
|
|
14745
|
+
if (await fs6.pathExists(absPath)) {
|
|
14746
|
+
const current = await fs6.readFile(absPath, "utf-8");
|
|
13995
14747
|
if (current.includes("tailwindcss") || current.includes("@tailwind")) return;
|
|
13996
|
-
await
|
|
14748
|
+
await fs6.writeFile(absPath, `${current.trimEnd()}
|
|
13997
14749
|
|
|
13998
14750
|
${template}`);
|
|
13999
14751
|
return;
|
|
14000
14752
|
}
|
|
14001
|
-
await
|
|
14753
|
+
await fs6.writeFile(absPath, template);
|
|
14002
14754
|
}
|
|
14003
14755
|
function renderTitle() {
|
|
14004
|
-
const
|
|
14005
|
-
console.log(gradient.pastel.multiline(
|
|
14756
|
+
const text3 = figlet.textSync("Shapes UI", { font: "Standard" });
|
|
14757
|
+
console.log(gradient.pastel.multiline(text3));
|
|
14006
14758
|
}
|
|
14007
14759
|
async function initCommand() {
|
|
14008
14760
|
console.clear();
|
|
14009
14761
|
renderTitle();
|
|
14010
|
-
|
|
14011
|
-
const configPath =
|
|
14012
|
-
if (await
|
|
14762
|
+
intro2(pc2.bgCyan(pc2.black(" Welcome to Shapes UI ")));
|
|
14763
|
+
const configPath = path5.join(process.cwd(), "shapes.json");
|
|
14764
|
+
if (await fs6.pathExists(configPath)) {
|
|
14013
14765
|
const overwrite = exitIfCancelled(
|
|
14014
|
-
await
|
|
14766
|
+
await confirm2({ message: "shapes.json already exists. Overwrite it?" })
|
|
14015
14767
|
);
|
|
14016
14768
|
if (!overwrite) {
|
|
14017
|
-
|
|
14769
|
+
outro2(pc2.yellow("Init cancelled."));
|
|
14018
14770
|
return;
|
|
14019
14771
|
}
|
|
14020
14772
|
}
|
|
@@ -14023,12 +14775,33 @@ async function initCommand() {
|
|
|
14023
14775
|
message: "Which style do you want to use?",
|
|
14024
14776
|
options: [
|
|
14025
14777
|
{ label: "Default", value: "default" },
|
|
14026
|
-
{ label: "Brutalist", value: "brutalist" }
|
|
14778
|
+
{ label: "Brutalist", value: "brutalist" },
|
|
14779
|
+
{ label: "Minimal", value: "minimal" }
|
|
14027
14780
|
]
|
|
14028
14781
|
})
|
|
14029
14782
|
);
|
|
14783
|
+
const palette = exitIfCancelled(
|
|
14784
|
+
await select({
|
|
14785
|
+
message: "Pick a brand palette",
|
|
14786
|
+
options: getDefaultBrandPaletteOptions().map((name) => ({
|
|
14787
|
+
label: name[0].toUpperCase() + name.slice(1),
|
|
14788
|
+
value: name
|
|
14789
|
+
})),
|
|
14790
|
+
initialValue: "blue"
|
|
14791
|
+
})
|
|
14792
|
+
);
|
|
14793
|
+
const contrastMode = exitIfCancelled(
|
|
14794
|
+
await select({
|
|
14795
|
+
message: "Choose foreground contrast strategy",
|
|
14796
|
+
options: [
|
|
14797
|
+
{ label: "Deterministic shades", value: "deterministic" },
|
|
14798
|
+
{ label: "Dynamic contrast", value: "dynamic" }
|
|
14799
|
+
],
|
|
14800
|
+
initialValue: "deterministic"
|
|
14801
|
+
})
|
|
14802
|
+
);
|
|
14030
14803
|
const uiPath = exitIfCancelled(
|
|
14031
|
-
await
|
|
14804
|
+
await text2({
|
|
14032
14805
|
message: "Where should we install components?",
|
|
14033
14806
|
initialValue: "./src/components/ui"
|
|
14034
14807
|
})
|
|
@@ -14037,10 +14810,10 @@ async function initCommand() {
|
|
|
14037
14810
|
const hasTailwindV4 = isTailwindV4Installed(pkg);
|
|
14038
14811
|
const isVite = await isViteProject();
|
|
14039
14812
|
const hasExistingCss = exitIfCancelled(
|
|
14040
|
-
await
|
|
14813
|
+
await confirm2({ message: "Do you already have a CSS file?" })
|
|
14041
14814
|
);
|
|
14042
14815
|
const cssPath = hasExistingCss ? exitIfCancelled(
|
|
14043
|
-
await
|
|
14816
|
+
await text2({
|
|
14044
14817
|
message: "Path to your CSS file",
|
|
14045
14818
|
initialValue: "src/styles/globals.css"
|
|
14046
14819
|
})
|
|
@@ -14052,18 +14825,28 @@ async function initCommand() {
|
|
|
14052
14825
|
}
|
|
14053
14826
|
await installDeps(tailwindDeps, true);
|
|
14054
14827
|
}
|
|
14055
|
-
const missingBaseDeps = getMissingDeps(pkg,
|
|
14828
|
+
const missingBaseDeps = getMissingDeps(pkg, BASE_DEPS2);
|
|
14056
14829
|
await installDeps(missingBaseDeps, false);
|
|
14057
|
-
await
|
|
14830
|
+
await ensureTailwindStyles2(cssPath);
|
|
14831
|
+
const paletteResult = await writePaletteTokens({
|
|
14832
|
+
cssPath,
|
|
14833
|
+
paletteName: palette,
|
|
14834
|
+
neutralPalette: "zinc",
|
|
14835
|
+
contrastMode
|
|
14836
|
+
});
|
|
14058
14837
|
const config2 = {
|
|
14059
14838
|
$schema: "https://shapes-ui.com/schema.json",
|
|
14060
14839
|
style,
|
|
14840
|
+
palette: {
|
|
14841
|
+
name: paletteResult.paletteName,
|
|
14842
|
+
contrastMode: paletteResult.contrastMode
|
|
14843
|
+
},
|
|
14061
14844
|
tailwind: { css: cssPath, baseColor: "zinc" },
|
|
14062
14845
|
paths: { ui: uiPath, lib: "./src/lib" }
|
|
14063
14846
|
};
|
|
14064
|
-
await
|
|
14065
|
-
|
|
14066
|
-
const addNow = exitIfCancelled(await
|
|
14847
|
+
await fs6.writeJSON("shapes.json", config2, { spaces: 2 });
|
|
14848
|
+
note3("Created shapes.json", "Configuration");
|
|
14849
|
+
const addNow = exitIfCancelled(await confirm2({ message: "Add components now?" }));
|
|
14067
14850
|
if (addNow) {
|
|
14068
14851
|
const selected = await pickComponents();
|
|
14069
14852
|
if (selected.length > 0) {
|
|
@@ -14072,19 +14855,82 @@ async function initCommand() {
|
|
|
14072
14855
|
}
|
|
14073
14856
|
}
|
|
14074
14857
|
}
|
|
14075
|
-
|
|
14858
|
+
outro2(pc2.green("Shapes UI is ready."));
|
|
14859
|
+
}
|
|
14860
|
+
|
|
14861
|
+
// src/commands/palette.ts
|
|
14862
|
+
import path6 from "path";
|
|
14863
|
+
import { intro as intro3, note as note4, outro as outro3 } from "@clack/prompts";
|
|
14864
|
+
import fs7 from "fs-extra";
|
|
14865
|
+
import pc3 from "picocolors";
|
|
14866
|
+
async function paletteSetCommand(name, options = {}) {
|
|
14867
|
+
intro3(pc3.bgCyan(pc3.black(" Update Shapes palette ")));
|
|
14868
|
+
const config2 = await getConfig();
|
|
14869
|
+
if (!config2) {
|
|
14870
|
+
throw new Error("Could not find shapes.json. Run `shapes-ui init` first.");
|
|
14871
|
+
}
|
|
14872
|
+
const contrastMode = normalizeContrastMode(options.contrastMode ?? config2.palette?.contrastMode);
|
|
14873
|
+
const cssPath = options.cssPath ?? config2.tailwind.css;
|
|
14874
|
+
const neutralPalette = config2.tailwind.baseColor;
|
|
14875
|
+
const result = await writePaletteTokens({
|
|
14876
|
+
cssPath,
|
|
14877
|
+
paletteName: name,
|
|
14878
|
+
neutralPalette,
|
|
14879
|
+
contrastMode,
|
|
14880
|
+
refresh: options.refresh
|
|
14881
|
+
});
|
|
14882
|
+
const updatedConfig = {
|
|
14883
|
+
...config2,
|
|
14884
|
+
palette: {
|
|
14885
|
+
name: result.paletteName,
|
|
14886
|
+
contrastMode: result.contrastMode
|
|
14887
|
+
},
|
|
14888
|
+
tailwind: {
|
|
14889
|
+
...config2.tailwind,
|
|
14890
|
+
css: cssPath
|
|
14891
|
+
}
|
|
14892
|
+
};
|
|
14893
|
+
await fs7.writeJSON(path6.join(process.cwd(), "shapes.json"), updatedConfig, { spaces: 2 });
|
|
14894
|
+
note4(
|
|
14895
|
+
`palette=${result.paletteName} neutral=${result.neutralPalette} contrast=${result.contrastMode} source=${result.source}`,
|
|
14896
|
+
"Palette updated"
|
|
14897
|
+
);
|
|
14898
|
+
outro3(pc3.green("Shapes UI palette updated."));
|
|
14076
14899
|
}
|
|
14077
14900
|
|
|
14078
14901
|
// src/commands/cli.ts
|
|
14079
14902
|
var program = new Command();
|
|
14080
|
-
program.name("shapes").description("Shapes UI CLI").version("0.0.1");
|
|
14903
|
+
program.name("shapes-ui").description("Shapes UI CLI").version("0.0.1");
|
|
14081
14904
|
program.command("init").description("Configure Shapes UI for your project").action(initCommand);
|
|
14082
|
-
program.command("
|
|
14905
|
+
program.command("create [project-name]").description("Create a new Vite React TypeScript app ready for Shapes UI").option("-i, --install", "Install project dependencies").option("--full", "Configure Shapes UI and install all components").option("--style <style>", "Shapes style for --full (default|brutalist|minimal)").option("--palette <name>", "Brand palette for --full (e.g. blue, emerald, rose)").option("--contrast-mode <mode>", "Foreground contrast mode for --full (deterministic|dynamic)").option("--ui-path <path>", "UI components path for --full (e.g. ./src/components/ui)").option("--css-path <path>", "Tailwind CSS file path for --full (e.g. src/index.css)").option("-f, --force", "Overwrite target directory if it already exists").action(async (projectName, options) => {
|
|
14906
|
+
await createCommand(projectName, {
|
|
14907
|
+
install: options.install,
|
|
14908
|
+
full: options.full,
|
|
14909
|
+
style: options.style,
|
|
14910
|
+
palette: options.palette,
|
|
14911
|
+
contrastMode: options.contrastMode,
|
|
14912
|
+
uiPath: options.uiPath,
|
|
14913
|
+
cssPath: options.cssPath,
|
|
14914
|
+
force: options.force
|
|
14915
|
+
});
|
|
14916
|
+
});
|
|
14917
|
+
program.command("add [components...]").description("Add components to your project").option("-a, --all", "Add all available components").action(async (components, options) => {
|
|
14083
14918
|
const config2 = await getConfig();
|
|
14084
14919
|
if (!config2) {
|
|
14085
14920
|
console.error("Please run 'init' first.");
|
|
14086
14921
|
return;
|
|
14087
14922
|
}
|
|
14923
|
+
if (options.all) {
|
|
14924
|
+
await addAllComponents(config2);
|
|
14925
|
+
return;
|
|
14926
|
+
}
|
|
14088
14927
|
await addCommand(components, config2);
|
|
14089
14928
|
});
|
|
14929
|
+
program.command("palette").description("Manage color palettes").command("set <name>").description("Set brand palette and regenerate semantic tokens").option("--css-path <path>", "Override Tailwind CSS file path").option("--contrast-mode <mode>", "Foreground contrast mode (deterministic|dynamic)").option("--refresh", "Refresh Tailwind palette data from docs").action(async (name, options) => {
|
|
14930
|
+
await paletteSetCommand(name, {
|
|
14931
|
+
cssPath: options.cssPath,
|
|
14932
|
+
contrastMode: options.contrastMode,
|
|
14933
|
+
refresh: options.refresh
|
|
14934
|
+
});
|
|
14935
|
+
});
|
|
14090
14936
|
program.parse();
|