@apex-stack/core 0.3.1 → 0.4.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.
@@ -70,10 +70,14 @@ var addCommand = defineCommand({
70
70
  log(` ${color.green("+")} Added ${color.bold(`components/${entry.name}.alpine`)}`);
71
71
  log(`
72
72
  Use it: ${color.cyan(`<${entry.name} />`)} ${color.gray("in any page/component.")}`);
73
- log(
74
- ` ${color.gray("It inherits your theme via --ax-* tokens (see")} ${color.cyan("@apex-stack/theme")}${color.gray(").")}
75
- `
76
- );
73
+ const appCss = ["app.css", "styles/app.css", "src/app.css"].map((p) => join(root, p)).find(existsSync);
74
+ const themed = appCss ? readFileSync(appCss, "utf8").includes("@theme") : false;
75
+ if (!themed) {
76
+ log(
77
+ ` ${color.gray("Tip: run")} ${color.cyan("apex theme")} ${color.gray("to set up Tailwind + the theme so it styles up (apps from")} ${color.cyan("apex new")} ${color.gray("already have it).")}`
78
+ );
79
+ }
80
+ log("");
77
81
  }
78
82
  });
79
83
  export {
package/dist/cli.js CHANGED
@@ -134,6 +134,7 @@ var COMMANDS = [
134
134
  ["start", "Run a production server build"],
135
135
  ["make", "Generate a page, component, route, store, middleware\u2026"],
136
136
  ["add", "Add a themeable component (button, card, badge\u2026)"],
137
+ ["theme", "Write/update your theme tokens (colors, radius, fonts)"],
137
138
  ["upgrade", "Adopt new scaffold defaults (non-destructive)"],
138
139
  ["migrate", "Apply pending database migrations"],
139
140
  ["mcp", "Inspect the MCP server \u2014 list or call tools"]
@@ -150,7 +151,8 @@ var main = defineCommand2({
150
151
  build: () => import("./build-VHS6KZBK.js").then((m) => m.buildCommand),
151
152
  start: () => import("./start-3O3E43PT.js").then((m) => m.startCommand),
152
153
  make: () => import("./make-VAYO5GWA.js").then((m) => m.makeCommand),
153
- add: () => import("./add-2SBHPLEH.js").then((m) => m.addCommand),
154
+ add: () => import("./add-Z7JSLBOT.js").then((m) => m.addCommand),
155
+ theme: () => import("./theme-UUOIV44V.js").then((m) => m.themeCommand),
154
156
  upgrade: () => import("./upgrade-WC5F5FKY.js").then((m) => m.upgradeCommand),
155
157
  migrate: () => import("./migrate-X6LIHMIE.js").then((m) => m.migrateCommand),
156
158
  mcp: () => import("./mcp-CH7L4GF3.js").then((m) => m.mcpCommand)
@@ -0,0 +1,163 @@
1
+ import {
2
+ banner,
3
+ color
4
+ } from "./chunk-QIXJSQLW.js";
5
+
6
+ // src/commands/theme.ts
7
+ import { existsSync, readFileSync, writeFileSync } from "fs";
8
+ import { join, resolve } from "path";
9
+
10
+ // ../theme/dist/index.js
11
+ var SANS = 'ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"';
12
+ var defaultTheme = {
13
+ radius: "0.25rem",
14
+ fonts: {
15
+ body: `"Instrument Sans", ${SANS}`,
16
+ title: `"Montserrat", ${SANS}`
17
+ },
18
+ colors: {
19
+ // Light
20
+ surface: "#ffffff",
21
+ "surface-alt": "#fafafa",
22
+ "on-surface": "#525252",
23
+ "on-surface-strong": "#171717",
24
+ primary: "#000000",
25
+ "on-primary": "#f5f5f5",
26
+ secondary: "#262626",
27
+ "on-secondary": "#ffffff",
28
+ outline: "#d4d4d4",
29
+ "outline-strong": "#262626",
30
+ // Dark
31
+ "surface-dark": "#0a0a0a",
32
+ "surface-dark-alt": "#171717",
33
+ "on-surface-dark": "#d4d4d4",
34
+ "on-surface-dark-strong": "#ffffff",
35
+ "primary-dark": "#ffffff",
36
+ "on-primary-dark": "#000000",
37
+ "secondary-dark": "#d4d4d4",
38
+ "on-secondary-dark": "#000000",
39
+ "outline-dark": "#404040",
40
+ "outline-dark-strong": "#d4d4d4",
41
+ // Shared (scheme-independent status colors)
42
+ info: "#0ea5e9",
43
+ "on-info": "#ffffff",
44
+ success: "#22c55e",
45
+ "on-success": "#ffffff",
46
+ warning: "#f59e0b",
47
+ "on-warning": "#ffffff",
48
+ danger: "#ef4444",
49
+ "on-danger": "#ffffff"
50
+ }
51
+ };
52
+ function defineTheme(input = {}) {
53
+ return {
54
+ radius: input.radius ?? defaultTheme.radius,
55
+ fonts: { ...defaultTheme.fonts, ...input.fonts ?? {} },
56
+ colors: { ...defaultTheme.colors, ...input.colors ?? {} }
57
+ };
58
+ }
59
+ var darkVariant = "@custom-variant dark (&:where(.dark, .dark *));";
60
+ function renderThemeCss(theme = defaultTheme) {
61
+ const lines = [
62
+ ` --font-body: ${theme.fonts.body};`,
63
+ ` --font-title: ${theme.fonts.title};`
64
+ ];
65
+ for (const [key, value] of Object.entries(theme.colors)) {
66
+ lines.push(` --color-${key}: ${value};`);
67
+ }
68
+ lines.push(` --radius-radius: ${theme.radius};`);
69
+ return `@theme {
70
+ ${lines.join("\n")}
71
+ }`;
72
+ }
73
+ var defaultThemeCss = `${darkVariant}
74
+
75
+ ${renderThemeCss(defaultTheme)}`;
76
+
77
+ // src/commands/theme.ts
78
+ import { defineCommand } from "citty";
79
+ var START = "/* apex-theme:start */";
80
+ var END = "/* apex-theme:end */";
81
+ function findAppCss(root) {
82
+ return ["app.css", "styles/app.css", "src/app.css"].map((p) => join(root, p)).find(existsSync) ?? null;
83
+ }
84
+ function applyBlock(css, block) {
85
+ const re = new RegExp(
86
+ `${START.replace(/[/*]/g, "\\$&")}[\\s\\S]*?${END.replace(/[/*]/g, "\\$&")}`
87
+ );
88
+ if (re.test(css)) return css.replace(re, block);
89
+ if (/@import\s+['"]tailwindcss['"];?/.test(css)) {
90
+ return css.replace(/(@import\s+['"]tailwindcss['"];?\s*)/, `$1
91
+ ${block}
92
+ `);
93
+ }
94
+ return `${block}
95
+
96
+ ${css}`;
97
+ }
98
+ var themeCommand = defineCommand({
99
+ meta: {
100
+ name: "theme",
101
+ description: "Write/update the theme tokens (colors, radius, fonts) in your CSS"
102
+ },
103
+ args: {
104
+ root: { type: "string", description: "Project root", default: "." },
105
+ out: { type: "string", description: "Target stylesheet (defaults to your app.css)" },
106
+ primary: { type: "string", description: "Primary color (light), e.g. #4f46e5" },
107
+ "primary-dark": { type: "string", description: "Primary color (dark)" },
108
+ secondary: { type: "string", description: "Secondary color (light)" },
109
+ radius: { type: "string", description: "Border radius, e.g. 0.5rem" },
110
+ "font-body": { type: "string", description: "Body font stack" },
111
+ "font-title": { type: "string", description: "Title font stack" }
112
+ },
113
+ run({ args }) {
114
+ const root = resolve(process.cwd(), String(args.root));
115
+ const log = console.log;
116
+ process.stdout.write(banner());
117
+ const colors = {};
118
+ if (args.primary) colors.primary = String(args.primary);
119
+ if (args["primary-dark"]) colors["primary-dark"] = String(args["primary-dark"]);
120
+ if (args.secondary) colors.secondary = String(args.secondary);
121
+ const input = {};
122
+ if (Object.keys(colors).length) input.colors = colors;
123
+ if (args.radius) input.radius = String(args.radius);
124
+ if (args["font-body"] || args["font-title"]) {
125
+ input.fonts = {};
126
+ if (args["font-body"]) input.fonts.body = String(args["font-body"]);
127
+ if (args["font-title"]) input.fonts.title = String(args["font-title"]);
128
+ }
129
+ const customized = Object.keys(input).length > 0;
130
+ const block = `${START}
131
+ ${customized ? `${darkVariant}
132
+
133
+ ${renderThemeCss(defineTheme(input))}` : defaultThemeCss}
134
+ ${END}`;
135
+ const target = args.out ? resolve(root, String(args.out)) : findAppCss(root);
136
+ if (!target) {
137
+ const created = join(root, "app.css");
138
+ writeFileSync(created, `@import 'tailwindcss';
139
+ @source './**/*.alpine';
140
+
141
+ ${block}
142
+ `);
143
+ log(` ${color.green("+")} Created ${color.bold("app.css")} with Tailwind + the theme.`);
144
+ } else {
145
+ const before = readFileSync(target, "utf8");
146
+ writeFileSync(target, applyBlock(before, block));
147
+ const rel = target.replace(`${root}/`, "");
148
+ log(` ${color.green("\u2713")} Updated theme tokens in ${color.bold(rel)}`);
149
+ }
150
+ if (customized) {
151
+ log(
152
+ ` ${color.gray("Applied:")} ${Object.entries({ ...colors, radius: args.radius }).filter(([, v]) => v).map(([k, v]) => `${k}=${v}`).join(" ")}`
153
+ );
154
+ }
155
+ log(
156
+ ` ${color.gray("Every component inherits it \u2014 restart the dev server if it is running.")}
157
+ `
158
+ );
159
+ }
160
+ });
161
+ export {
162
+ themeCommand
163
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apex-stack/core",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "The full-stack meta-framework for Alpine.js — CLI and runtime",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -48,7 +48,8 @@
48
48
  "vite": "^6.0.7",
49
49
  "zod": "^4.4.3",
50
50
  "@apex-stack/kit": "0.2.0",
51
- "@apex-stack/vite": "0.1.6"
51
+ "@apex-stack/vite": "0.1.6",
52
+ "@apex-stack/theme": "0.3.0"
52
53
  },
53
54
  "peerDependencies": {
54
55
  "alpinejs": "^3.14.0"
@@ -0,0 +1,42 @@
1
+ @import "tailwindcss";
2
+ @source './**/*.alpine';
3
+
4
+ /* apex-theme:start */
5
+ @custom-variant dark (&:where(.dark, .dark *));
6
+
7
+ @theme {
8
+ --font-body: "Instrument Sans", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
9
+ "Segoe UI Emoji";
10
+ --font-title: "Montserrat", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
11
+ "Segoe UI Emoji";
12
+ --color-surface: #ffffff;
13
+ --color-surface-alt: #fafafa;
14
+ --color-on-surface: #525252;
15
+ --color-on-surface-strong: #171717;
16
+ --color-primary: #000000;
17
+ --color-on-primary: #f5f5f5;
18
+ --color-secondary: #262626;
19
+ --color-on-secondary: #ffffff;
20
+ --color-outline: #d4d4d4;
21
+ --color-outline-strong: #262626;
22
+ --color-surface-dark: #0a0a0a;
23
+ --color-surface-dark-alt: #171717;
24
+ --color-on-surface-dark: #d4d4d4;
25
+ --color-on-surface-dark-strong: #ffffff;
26
+ --color-primary-dark: #ffffff;
27
+ --color-on-primary-dark: #000000;
28
+ --color-secondary-dark: #d4d4d4;
29
+ --color-on-secondary-dark: #000000;
30
+ --color-outline-dark: #404040;
31
+ --color-outline-dark-strong: #d4d4d4;
32
+ --color-info: #0ea5e9;
33
+ --color-on-info: #ffffff;
34
+ --color-success: #22c55e;
35
+ --color-on-success: #ffffff;
36
+ --color-warning: #f59e0b;
37
+ --color-on-warning: #ffffff;
38
+ --color-danger: #ef4444;
39
+ --color-on-danger: #ffffff;
40
+ --radius-radius: 0.25rem;
41
+ }
42
+ /* apex-theme:end */
@@ -17,6 +17,8 @@
17
17
  "zod": "^4.0.0"
18
18
  },
19
19
  "devDependencies": {
20
+ "@tailwindcss/vite": "^4.0.0",
21
+ "tailwindcss": "^4.0.0",
20
22
  "typescript": "^5.6.0",
21
23
  "vitest": "^3.0.0"
22
24
  }