@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
|
-
|
|
74
|
-
|
|
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-
|
|
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
|
+
"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 */
|