arekui 1.0.0 → 1.0.2
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/LICENSE +21 -21
- package/README.md +198 -198
- package/arekui.css +3279 -3279
- package/arekui.d.ts +328 -328
- package/arekui.js +450 -450
- package/package.json +59 -57
- package/scripts/build-custom.js +318 -318
- package/src/arekui.css +55 -55
- package/src/base/neo-overrides.css +317 -317
- package/src/base/reset.css +67 -67
- package/src/base/tokens.css +304 -304
- package/src/components/accordion.css +34 -34
- package/src/components/alert.css +26 -26
- package/src/components/badge.css +33 -33
- package/src/components/breadcrumb.css +33 -33
- package/src/components/button.css +103 -103
- package/src/components/card.css +24 -24
- package/src/components/carousel.css +14 -14
- package/src/components/chat.css +78 -78
- package/src/components/drawer.css +53 -53
- package/src/components/file-upload.css +51 -51
- package/src/components/footer.css +26 -26
- package/src/components/forms.css +69 -69
- package/src/components/hero.css +22 -22
- package/src/components/join.css +14 -14
- package/src/components/link.css +24 -24
- package/src/components/menu.css +56 -56
- package/src/components/misc.css +57 -57
- package/src/components/modal.css +32 -32
- package/src/components/navbar.css +37 -37
- package/src/components/pagination.css +46 -46
- package/src/components/popover.css +70 -70
- package/src/components/progress.css +19 -19
- package/src/components/prose.css +80 -80
- package/src/components/rating.css +37 -37
- package/src/components/scroll-top.css +36 -36
- package/src/components/skeleton.css +54 -54
- package/src/components/swap.css +45 -45
- package/src/components/table.css +22 -22
- package/src/components/tabs.css +24 -24
- package/src/components/tag.css +101 -101
- package/src/components/textured.css +34 -34
- package/src/components/timeline.css +34 -34
- package/src/components/toast.css +134 -134
- package/src/components/tooltip.css +24 -24
- package/src/utilities/borders.css +152 -152
- package/src/utilities/colors.css +73 -73
- package/src/utilities/hover.css +33 -33
- package/src/utilities/layout.css +100 -100
- package/src/utilities/neo-utilities.css +95 -95
- package/src/utilities/responsive.css +128 -128
- package/src/utilities/sizing.css +91 -91
- package/src/utilities/spacing.css +130 -130
- package/src/utilities/typography.css +94 -94
package/scripts/build-custom.js
CHANGED
|
@@ -1,318 +1,318 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Arekui Build — scans your source and outputs only what you use.
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* npx arekui-build # reads arekui.config.js
|
|
8
|
-
* npx arekui-build -i ./src -o ./assets # overrides with flags
|
|
9
|
-
* npx arekui-build --sourcemap
|
|
10
|
-
* npx arekui-build --full # include everything
|
|
11
|
-
*
|
|
12
|
-
* Config file (arekui.config.js or arekui.config.json):
|
|
13
|
-
* module.exports = {
|
|
14
|
-
* input: "./src", // directory to scan
|
|
15
|
-
* output: "./assets", // output directory
|
|
16
|
-
* name: "arekui", // output filename (without .min.css)
|
|
17
|
-
* sourcemap: false,
|
|
18
|
-
* full: false, // true = ignore scan, include all
|
|
19
|
-
* };
|
|
20
|
-
*
|
|
21
|
-
* CLI flags override config file values.
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
const fs = require("fs");
|
|
25
|
-
const path = require("path");
|
|
26
|
-
const { bundle } = require("lightningcss");
|
|
27
|
-
|
|
28
|
-
// ── Load config file ───────────────────────────────────────────────────────
|
|
29
|
-
function loadConfig() {
|
|
30
|
-
const candidates = ["arekui.config.js", "arekui.config.json"];
|
|
31
|
-
for (const file of candidates) {
|
|
32
|
-
const full = path.resolve(file);
|
|
33
|
-
if (fs.existsSync(full)) {
|
|
34
|
-
try {
|
|
35
|
-
console.log(`\x1b[90m config: ${file}\x1b[0m`);
|
|
36
|
-
return file.endsWith(".json")
|
|
37
|
-
? JSON.parse(fs.readFileSync(full, "utf-8"))
|
|
38
|
-
: require(full);
|
|
39
|
-
} catch (e) {
|
|
40
|
-
console.error(`\x1b[31m✗\x1b[0m Failed to load ${file}: ${e.message}`);
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return {};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// ── CLI args (override config) ─────────────────────────────────────────────
|
|
49
|
-
function getArg(flags) {
|
|
50
|
-
const idx = process.argv.findIndex((a) => flags.includes(a));
|
|
51
|
-
return idx === -1 ? null : process.argv[idx + 1];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const config = loadConfig();
|
|
55
|
-
|
|
56
|
-
const input = getArg(["-i", "--input"]) || config.input || ".";
|
|
57
|
-
const output = getArg(["-o", "--output"]) || config.output || "assets";
|
|
58
|
-
const name = getArg(["-n", "--name"]) || config.name || "arekui";
|
|
59
|
-
const sourcemap =
|
|
60
|
-
process.argv.includes("--sourcemap") || config.sourcemap === true;
|
|
61
|
-
const full = process.argv.includes("--full") || config.full === true;
|
|
62
|
-
|
|
63
|
-
const srcDir = path.resolve(input);
|
|
64
|
-
const outDir = path.resolve(output);
|
|
65
|
-
|
|
66
|
-
// ── Component → CSS class mapping ──────────────────────────────────────────
|
|
67
|
-
const COMPONENT_CLASSES = {
|
|
68
|
-
accordion: ["ar-accordion", "ar-collapse"],
|
|
69
|
-
alert: ["ar-alert"],
|
|
70
|
-
badge: ["ar-badge"],
|
|
71
|
-
breadcrumb: ["ar-breadcrumb"],
|
|
72
|
-
button: ["ar-btn"],
|
|
73
|
-
card: ["ar-card", "ar-card-body", "ar-card-title", "ar-card-figure"],
|
|
74
|
-
carousel: ["ar-carousel", "ar-carousel-item"],
|
|
75
|
-
chat: ["ar-chat", "ar-chat-bubble"],
|
|
76
|
-
drawer: ["ar-drawer"],
|
|
77
|
-
"file-upload": ["ar-file-upload"],
|
|
78
|
-
footer: ["ar-footer"],
|
|
79
|
-
forms: [
|
|
80
|
-
"ar-input",
|
|
81
|
-
"ar-textarea",
|
|
82
|
-
"ar-select",
|
|
83
|
-
"ar-checkbox",
|
|
84
|
-
"ar-radio",
|
|
85
|
-
"ar-toggle",
|
|
86
|
-
"ar-range",
|
|
87
|
-
"ar-label",
|
|
88
|
-
"ar-fieldset",
|
|
89
|
-
],
|
|
90
|
-
hero: ["ar-hero"],
|
|
91
|
-
join: ["ar-join"],
|
|
92
|
-
link: ["ar-link"],
|
|
93
|
-
menu: ["ar-menu", "ar-dropdown"],
|
|
94
|
-
misc: ["ar-divider", "ar-stepper", "ar-step", "ar-avatar"],
|
|
95
|
-
modal: ["ar-modal"],
|
|
96
|
-
navbar: ["ar-navbar"],
|
|
97
|
-
pagination: ["ar-pagination"],
|
|
98
|
-
popover: ["ar-popover"],
|
|
99
|
-
progress: ["ar-progress"],
|
|
100
|
-
prose: ["ar-prose"],
|
|
101
|
-
rating: ["ar-rating"],
|
|
102
|
-
"scroll-top": ["ar-scroll-top"],
|
|
103
|
-
skeleton: ["ar-skeleton"],
|
|
104
|
-
swap: ["ar-swap"],
|
|
105
|
-
table: ["ar-table"],
|
|
106
|
-
tabs: ["ar-tabs", "ar-tab"],
|
|
107
|
-
tag: ["ar-tag"],
|
|
108
|
-
textured: ["ar-bg-img"],
|
|
109
|
-
timeline: ["ar-timeline"],
|
|
110
|
-
toast: ["ar-toast"],
|
|
111
|
-
tooltip: ["ar-tooltip"],
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
const UTILITY_PATTERNS = {
|
|
115
|
-
spacing: [
|
|
116
|
-
/^ar-p/,
|
|
117
|
-
/^ar-px/,
|
|
118
|
-
/^ar-py/,
|
|
119
|
-
/^ar-m/,
|
|
120
|
-
/^ar-mt/,
|
|
121
|
-
/^ar-mb/,
|
|
122
|
-
/^ar-my/,
|
|
123
|
-
/^ar-mx/,
|
|
124
|
-
/^ar-gap/,
|
|
125
|
-
],
|
|
126
|
-
layout: [
|
|
127
|
-
/^ar-flex/,
|
|
128
|
-
/^ar-inline-flex/,
|
|
129
|
-
/^ar-flex-col/,
|
|
130
|
-
/^ar-flex-wrap/,
|
|
131
|
-
/^ar-items-/,
|
|
132
|
-
/^ar-justify-/,
|
|
133
|
-
/^ar-grid/,
|
|
134
|
-
/^ar-block/,
|
|
135
|
-
/^ar-hidden/,
|
|
136
|
-
],
|
|
137
|
-
typography: [/^ar-text-/, /^ar-font-/, /^ar-leading-/, /^ar-tracking-/],
|
|
138
|
-
sizing: [
|
|
139
|
-
/^ar-w-/,
|
|
140
|
-
/^ar-h-/,
|
|
141
|
-
/^ar-min-h-/,
|
|
142
|
-
/^ar-max-w-/,
|
|
143
|
-
/^ar-aspect-video/,
|
|
144
|
-
/^ar-object-cover/,
|
|
145
|
-
],
|
|
146
|
-
colors: [
|
|
147
|
-
/^ar-bg-base/,
|
|
148
|
-
/^ar-bg-neutral/,
|
|
149
|
-
/^ar-bg-primary/,
|
|
150
|
-
/^ar-bg-secondary/,
|
|
151
|
-
/^ar-bg-accent/,
|
|
152
|
-
/^ar-text-base/,
|
|
153
|
-
/^ar-text-gray/,
|
|
154
|
-
],
|
|
155
|
-
borders: [/^ar-border/, /^ar-rounded/, /^ar-shadow-/],
|
|
156
|
-
hover: [/^ar-hover-/],
|
|
157
|
-
responsive: [/^ar-md:/, /^ar-lg:/],
|
|
158
|
-
"neo-utilities": [/^ar-neo-/],
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
// ── Scan source files ──────────────────────────────────────────────────────
|
|
162
|
-
function findSourceFiles(dir) {
|
|
163
|
-
const exts = [".html", ".jsx", ".vue", ".svelte", ".tsx", ".ts", ".js"];
|
|
164
|
-
const files = [];
|
|
165
|
-
|
|
166
|
-
function walk(d) {
|
|
167
|
-
for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
|
|
168
|
-
const full = path.join(d, entry.name);
|
|
169
|
-
if (
|
|
170
|
-
entry.isDirectory() &&
|
|
171
|
-
!entry.name.startsWith(".") &&
|
|
172
|
-
entry.name !== "node_modules"
|
|
173
|
-
) {
|
|
174
|
-
walk(full);
|
|
175
|
-
} else if (entry.isFile() && exts.includes(path.extname(entry.name))) {
|
|
176
|
-
files.push(full);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
walk(dir);
|
|
181
|
-
return files;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function scan(dir) {
|
|
185
|
-
const files = findSourceFiles(dir);
|
|
186
|
-
const content = files.map((f) => fs.readFileSync(f, "utf-8")).join("\n");
|
|
187
|
-
const tokens = new Set();
|
|
188
|
-
let m;
|
|
189
|
-
const re = /ar-[\w-]+/g;
|
|
190
|
-
while ((m = re.exec(content)) !== null) tokens.add(m[0]);
|
|
191
|
-
return tokens;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
function detectComponents(classes) {
|
|
195
|
-
const found = new Set();
|
|
196
|
-
for (const [comp, patterns] of Object.entries(COMPONENT_CLASSES)) {
|
|
197
|
-
for (const cls of classes) {
|
|
198
|
-
if (patterns.some((p) => cls === p || cls.startsWith(p + "-"))) {
|
|
199
|
-
found.add(comp);
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
return [...found];
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function detectUtilities(classes) {
|
|
208
|
-
const found = new Set();
|
|
209
|
-
for (const [util, regexes] of Object.entries(UTILITY_PATTERNS)) {
|
|
210
|
-
for (const cls of classes) {
|
|
211
|
-
if (regexes.some((r) => r.test(cls))) {
|
|
212
|
-
found.add(util);
|
|
213
|
-
break;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return [...found];
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// ── Build CSS ──────────────────────────────────────────────────────────────
|
|
221
|
-
const COMPONENT_FILES = {
|
|
222
|
-
accordion: "accordion",
|
|
223
|
-
alert: "alert",
|
|
224
|
-
badge: "badge",
|
|
225
|
-
breadcrumb: "breadcrumb",
|
|
226
|
-
button: "button",
|
|
227
|
-
card: "card",
|
|
228
|
-
carousel: "carousel",
|
|
229
|
-
chat: "chat",
|
|
230
|
-
drawer: "drawer",
|
|
231
|
-
"file-upload": "file-upload",
|
|
232
|
-
footer: "footer",
|
|
233
|
-
forms: "forms",
|
|
234
|
-
hero: "hero",
|
|
235
|
-
join: "join",
|
|
236
|
-
link: "link",
|
|
237
|
-
menu: "menu",
|
|
238
|
-
misc: "misc",
|
|
239
|
-
modal: "modal",
|
|
240
|
-
navbar: "navbar",
|
|
241
|
-
pagination: "pagination",
|
|
242
|
-
popover: "popover",
|
|
243
|
-
progress: "progress",
|
|
244
|
-
prose: "prose",
|
|
245
|
-
rating: "rating",
|
|
246
|
-
"scroll-top": "scroll-top",
|
|
247
|
-
skeleton: "skeleton",
|
|
248
|
-
swap: "swap",
|
|
249
|
-
table: "table",
|
|
250
|
-
tabs: "tabs",
|
|
251
|
-
tag: "tag",
|
|
252
|
-
textured: "textured",
|
|
253
|
-
timeline: "timeline",
|
|
254
|
-
toast: "toast",
|
|
255
|
-
tooltip: "tooltip",
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
function buildCSS(components, utilities) {
|
|
259
|
-
const imports = [
|
|
260
|
-
`@import "./base/tokens.css" layer(base);`,
|
|
261
|
-
`@import "./base/reset.css" layer(base);`,
|
|
262
|
-
`@import "./base/neo-overrides.css" layer(base);`,
|
|
263
|
-
];
|
|
264
|
-
|
|
265
|
-
for (const c of components) {
|
|
266
|
-
imports.push(
|
|
267
|
-
`@import "./components/${COMPONENT_FILES[c] || c}.css" layer(components);`,
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
for (const u of utilities) {
|
|
271
|
-
imports.push(`@import "./utilities/${u}.css" layer(utilities);`);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return `@layer base, components, utilities;\n\n${imports.join("\n")}\n`;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// ── Main ───────────────────────────────────────────────────────────────────
|
|
278
|
-
const orchestrator = path.join(__dirname, "..", "src", "arekui.css");
|
|
279
|
-
const tmpFile = path.join(path.dirname(orchestrator), "__build.css");
|
|
280
|
-
|
|
281
|
-
try {
|
|
282
|
-
let components, utilities;
|
|
283
|
-
|
|
284
|
-
if (full) {
|
|
285
|
-
components = Object.keys(COMPONENT_FILES);
|
|
286
|
-
utilities = Object.keys(UTILITY_PATTERNS);
|
|
287
|
-
console.log(`\x1b[36m📦\x1b[0m Including all components`);
|
|
288
|
-
} else {
|
|
289
|
-
console.log(`\x1b[36m⏳\x1b[0m Scanning ${srcDir}...`);
|
|
290
|
-
const classes = scan(srcDir);
|
|
291
|
-
components = detectComponents(classes);
|
|
292
|
-
utilities = detectUtilities(classes);
|
|
293
|
-
console.log(` Found ${classes.size} ar-* tokens`);
|
|
294
|
-
console.log(` Components: ${components.join(", ") || "(none)"}`);
|
|
295
|
-
console.log(` Utilities: ${utilities.join(", ") || "(none)"}`);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
fs.writeFileSync(tmpFile, buildCSS(components, utilities), "utf-8");
|
|
299
|
-
fs.mkdirSync(outDir, { recursive: true });
|
|
300
|
-
|
|
301
|
-
const result = bundle({
|
|
302
|
-
filename: tmpFile,
|
|
303
|
-
minify: true,
|
|
304
|
-
sourceMap: sourcemap,
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
const outFile = path.join(outDir, `${name}.min.css`);
|
|
308
|
-
fs.writeFileSync(outFile, result.code);
|
|
309
|
-
if (sourcemap && result.map) fs.writeFileSync(outFile + ".map", result.map);
|
|
310
|
-
|
|
311
|
-
console.log(`\n\x1b[32m✓\x1b[0m Built → ${outFile}`);
|
|
312
|
-
console.log(
|
|
313
|
-
` ${components.length} components, ${utilities.length} utilities`,
|
|
314
|
-
);
|
|
315
|
-
console.log(` ${(result.code.length / 1024).toFixed(1)}KB`);
|
|
316
|
-
} finally {
|
|
317
|
-
if (fs.existsSync(tmpFile)) fs.unlinkSync(tmpFile);
|
|
318
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Arekui Build — scans your source and outputs only what you use.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx arekui-build # reads arekui.config.js
|
|
8
|
+
* npx arekui-build -i ./src -o ./assets # overrides with flags
|
|
9
|
+
* npx arekui-build --sourcemap
|
|
10
|
+
* npx arekui-build --full # include everything
|
|
11
|
+
*
|
|
12
|
+
* Config file (arekui.config.js or arekui.config.json):
|
|
13
|
+
* module.exports = {
|
|
14
|
+
* input: "./src", // directory to scan
|
|
15
|
+
* output: "./assets", // output directory
|
|
16
|
+
* name: "arekui", // output filename (without .min.css)
|
|
17
|
+
* sourcemap: false,
|
|
18
|
+
* full: false, // true = ignore scan, include all
|
|
19
|
+
* };
|
|
20
|
+
*
|
|
21
|
+
* CLI flags override config file values.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const fs = require("fs");
|
|
25
|
+
const path = require("path");
|
|
26
|
+
const { bundle } = require("lightningcss");
|
|
27
|
+
|
|
28
|
+
// ── Load config file ───────────────────────────────────────────────────────
|
|
29
|
+
function loadConfig() {
|
|
30
|
+
const candidates = ["arekui.config.js", "arekui.config.json"];
|
|
31
|
+
for (const file of candidates) {
|
|
32
|
+
const full = path.resolve(file);
|
|
33
|
+
if (fs.existsSync(full)) {
|
|
34
|
+
try {
|
|
35
|
+
console.log(`\x1b[90m config: ${file}\x1b[0m`);
|
|
36
|
+
return file.endsWith(".json")
|
|
37
|
+
? JSON.parse(fs.readFileSync(full, "utf-8"))
|
|
38
|
+
: require(full);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
console.error(`\x1b[31m✗\x1b[0m Failed to load ${file}: ${e.message}`);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── CLI args (override config) ─────────────────────────────────────────────
|
|
49
|
+
function getArg(flags) {
|
|
50
|
+
const idx = process.argv.findIndex((a) => flags.includes(a));
|
|
51
|
+
return idx === -1 ? null : process.argv[idx + 1];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const config = loadConfig();
|
|
55
|
+
|
|
56
|
+
const input = getArg(["-i", "--input"]) || config.input || ".";
|
|
57
|
+
const output = getArg(["-o", "--output"]) || config.output || "assets";
|
|
58
|
+
const name = getArg(["-n", "--name"]) || config.name || "arekui";
|
|
59
|
+
const sourcemap =
|
|
60
|
+
process.argv.includes("--sourcemap") || config.sourcemap === true;
|
|
61
|
+
const full = process.argv.includes("--full") || config.full === true;
|
|
62
|
+
|
|
63
|
+
const srcDir = path.resolve(input);
|
|
64
|
+
const outDir = path.resolve(output);
|
|
65
|
+
|
|
66
|
+
// ── Component → CSS class mapping ──────────────────────────────────────────
|
|
67
|
+
const COMPONENT_CLASSES = {
|
|
68
|
+
accordion: ["ar-accordion", "ar-collapse"],
|
|
69
|
+
alert: ["ar-alert"],
|
|
70
|
+
badge: ["ar-badge"],
|
|
71
|
+
breadcrumb: ["ar-breadcrumb"],
|
|
72
|
+
button: ["ar-btn"],
|
|
73
|
+
card: ["ar-card", "ar-card-body", "ar-card-title", "ar-card-figure"],
|
|
74
|
+
carousel: ["ar-carousel", "ar-carousel-item"],
|
|
75
|
+
chat: ["ar-chat", "ar-chat-bubble"],
|
|
76
|
+
drawer: ["ar-drawer"],
|
|
77
|
+
"file-upload": ["ar-file-upload"],
|
|
78
|
+
footer: ["ar-footer"],
|
|
79
|
+
forms: [
|
|
80
|
+
"ar-input",
|
|
81
|
+
"ar-textarea",
|
|
82
|
+
"ar-select",
|
|
83
|
+
"ar-checkbox",
|
|
84
|
+
"ar-radio",
|
|
85
|
+
"ar-toggle",
|
|
86
|
+
"ar-range",
|
|
87
|
+
"ar-label",
|
|
88
|
+
"ar-fieldset",
|
|
89
|
+
],
|
|
90
|
+
hero: ["ar-hero"],
|
|
91
|
+
join: ["ar-join"],
|
|
92
|
+
link: ["ar-link"],
|
|
93
|
+
menu: ["ar-menu", "ar-dropdown"],
|
|
94
|
+
misc: ["ar-divider", "ar-stepper", "ar-step", "ar-avatar"],
|
|
95
|
+
modal: ["ar-modal"],
|
|
96
|
+
navbar: ["ar-navbar"],
|
|
97
|
+
pagination: ["ar-pagination"],
|
|
98
|
+
popover: ["ar-popover"],
|
|
99
|
+
progress: ["ar-progress"],
|
|
100
|
+
prose: ["ar-prose"],
|
|
101
|
+
rating: ["ar-rating"],
|
|
102
|
+
"scroll-top": ["ar-scroll-top"],
|
|
103
|
+
skeleton: ["ar-skeleton"],
|
|
104
|
+
swap: ["ar-swap"],
|
|
105
|
+
table: ["ar-table"],
|
|
106
|
+
tabs: ["ar-tabs", "ar-tab"],
|
|
107
|
+
tag: ["ar-tag"],
|
|
108
|
+
textured: ["ar-bg-img"],
|
|
109
|
+
timeline: ["ar-timeline"],
|
|
110
|
+
toast: ["ar-toast"],
|
|
111
|
+
tooltip: ["ar-tooltip"],
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const UTILITY_PATTERNS = {
|
|
115
|
+
spacing: [
|
|
116
|
+
/^ar-p/,
|
|
117
|
+
/^ar-px/,
|
|
118
|
+
/^ar-py/,
|
|
119
|
+
/^ar-m/,
|
|
120
|
+
/^ar-mt/,
|
|
121
|
+
/^ar-mb/,
|
|
122
|
+
/^ar-my/,
|
|
123
|
+
/^ar-mx/,
|
|
124
|
+
/^ar-gap/,
|
|
125
|
+
],
|
|
126
|
+
layout: [
|
|
127
|
+
/^ar-flex/,
|
|
128
|
+
/^ar-inline-flex/,
|
|
129
|
+
/^ar-flex-col/,
|
|
130
|
+
/^ar-flex-wrap/,
|
|
131
|
+
/^ar-items-/,
|
|
132
|
+
/^ar-justify-/,
|
|
133
|
+
/^ar-grid/,
|
|
134
|
+
/^ar-block/,
|
|
135
|
+
/^ar-hidden/,
|
|
136
|
+
],
|
|
137
|
+
typography: [/^ar-text-/, /^ar-font-/, /^ar-leading-/, /^ar-tracking-/],
|
|
138
|
+
sizing: [
|
|
139
|
+
/^ar-w-/,
|
|
140
|
+
/^ar-h-/,
|
|
141
|
+
/^ar-min-h-/,
|
|
142
|
+
/^ar-max-w-/,
|
|
143
|
+
/^ar-aspect-video/,
|
|
144
|
+
/^ar-object-cover/,
|
|
145
|
+
],
|
|
146
|
+
colors: [
|
|
147
|
+
/^ar-bg-base/,
|
|
148
|
+
/^ar-bg-neutral/,
|
|
149
|
+
/^ar-bg-primary/,
|
|
150
|
+
/^ar-bg-secondary/,
|
|
151
|
+
/^ar-bg-accent/,
|
|
152
|
+
/^ar-text-base/,
|
|
153
|
+
/^ar-text-gray/,
|
|
154
|
+
],
|
|
155
|
+
borders: [/^ar-border/, /^ar-rounded/, /^ar-shadow-/],
|
|
156
|
+
hover: [/^ar-hover-/],
|
|
157
|
+
responsive: [/^ar-md:/, /^ar-lg:/],
|
|
158
|
+
"neo-utilities": [/^ar-neo-/],
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// ── Scan source files ──────────────────────────────────────────────────────
|
|
162
|
+
function findSourceFiles(dir) {
|
|
163
|
+
const exts = [".html", ".jsx", ".vue", ".svelte", ".tsx", ".ts", ".js"];
|
|
164
|
+
const files = [];
|
|
165
|
+
|
|
166
|
+
function walk(d) {
|
|
167
|
+
for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
|
|
168
|
+
const full = path.join(d, entry.name);
|
|
169
|
+
if (
|
|
170
|
+
entry.isDirectory() &&
|
|
171
|
+
!entry.name.startsWith(".") &&
|
|
172
|
+
entry.name !== "node_modules"
|
|
173
|
+
) {
|
|
174
|
+
walk(full);
|
|
175
|
+
} else if (entry.isFile() && exts.includes(path.extname(entry.name))) {
|
|
176
|
+
files.push(full);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
walk(dir);
|
|
181
|
+
return files;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function scan(dir) {
|
|
185
|
+
const files = findSourceFiles(dir);
|
|
186
|
+
const content = files.map((f) => fs.readFileSync(f, "utf-8")).join("\n");
|
|
187
|
+
const tokens = new Set();
|
|
188
|
+
let m;
|
|
189
|
+
const re = /ar-[\w-]+/g;
|
|
190
|
+
while ((m = re.exec(content)) !== null) tokens.add(m[0]);
|
|
191
|
+
return tokens;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function detectComponents(classes) {
|
|
195
|
+
const found = new Set();
|
|
196
|
+
for (const [comp, patterns] of Object.entries(COMPONENT_CLASSES)) {
|
|
197
|
+
for (const cls of classes) {
|
|
198
|
+
if (patterns.some((p) => cls === p || cls.startsWith(p + "-"))) {
|
|
199
|
+
found.add(comp);
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return [...found];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function detectUtilities(classes) {
|
|
208
|
+
const found = new Set();
|
|
209
|
+
for (const [util, regexes] of Object.entries(UTILITY_PATTERNS)) {
|
|
210
|
+
for (const cls of classes) {
|
|
211
|
+
if (regexes.some((r) => r.test(cls))) {
|
|
212
|
+
found.add(util);
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return [...found];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ── Build CSS ──────────────────────────────────────────────────────────────
|
|
221
|
+
const COMPONENT_FILES = {
|
|
222
|
+
accordion: "accordion",
|
|
223
|
+
alert: "alert",
|
|
224
|
+
badge: "badge",
|
|
225
|
+
breadcrumb: "breadcrumb",
|
|
226
|
+
button: "button",
|
|
227
|
+
card: "card",
|
|
228
|
+
carousel: "carousel",
|
|
229
|
+
chat: "chat",
|
|
230
|
+
drawer: "drawer",
|
|
231
|
+
"file-upload": "file-upload",
|
|
232
|
+
footer: "footer",
|
|
233
|
+
forms: "forms",
|
|
234
|
+
hero: "hero",
|
|
235
|
+
join: "join",
|
|
236
|
+
link: "link",
|
|
237
|
+
menu: "menu",
|
|
238
|
+
misc: "misc",
|
|
239
|
+
modal: "modal",
|
|
240
|
+
navbar: "navbar",
|
|
241
|
+
pagination: "pagination",
|
|
242
|
+
popover: "popover",
|
|
243
|
+
progress: "progress",
|
|
244
|
+
prose: "prose",
|
|
245
|
+
rating: "rating",
|
|
246
|
+
"scroll-top": "scroll-top",
|
|
247
|
+
skeleton: "skeleton",
|
|
248
|
+
swap: "swap",
|
|
249
|
+
table: "table",
|
|
250
|
+
tabs: "tabs",
|
|
251
|
+
tag: "tag",
|
|
252
|
+
textured: "textured",
|
|
253
|
+
timeline: "timeline",
|
|
254
|
+
toast: "toast",
|
|
255
|
+
tooltip: "tooltip",
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
function buildCSS(components, utilities) {
|
|
259
|
+
const imports = [
|
|
260
|
+
`@import "./base/tokens.css" layer(base);`,
|
|
261
|
+
`@import "./base/reset.css" layer(base);`,
|
|
262
|
+
`@import "./base/neo-overrides.css" layer(base);`,
|
|
263
|
+
];
|
|
264
|
+
|
|
265
|
+
for (const c of components) {
|
|
266
|
+
imports.push(
|
|
267
|
+
`@import "./components/${COMPONENT_FILES[c] || c}.css" layer(components);`,
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
for (const u of utilities) {
|
|
271
|
+
imports.push(`@import "./utilities/${u}.css" layer(utilities);`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return `@layer base, components, utilities;\n\n${imports.join("\n")}\n`;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// ── Main ───────────────────────────────────────────────────────────────────
|
|
278
|
+
const orchestrator = path.join(__dirname, "..", "src", "arekui.css");
|
|
279
|
+
const tmpFile = path.join(path.dirname(orchestrator), "__build.css");
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
let components, utilities;
|
|
283
|
+
|
|
284
|
+
if (full) {
|
|
285
|
+
components = Object.keys(COMPONENT_FILES);
|
|
286
|
+
utilities = Object.keys(UTILITY_PATTERNS);
|
|
287
|
+
console.log(`\x1b[36m📦\x1b[0m Including all components`);
|
|
288
|
+
} else {
|
|
289
|
+
console.log(`\x1b[36m⏳\x1b[0m Scanning ${srcDir}...`);
|
|
290
|
+
const classes = scan(srcDir);
|
|
291
|
+
components = detectComponents(classes);
|
|
292
|
+
utilities = detectUtilities(classes);
|
|
293
|
+
console.log(` Found ${classes.size} ar-* tokens`);
|
|
294
|
+
console.log(` Components: ${components.join(", ") || "(none)"}`);
|
|
295
|
+
console.log(` Utilities: ${utilities.join(", ") || "(none)"}`);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
fs.writeFileSync(tmpFile, buildCSS(components, utilities), "utf-8");
|
|
299
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
300
|
+
|
|
301
|
+
const result = bundle({
|
|
302
|
+
filename: tmpFile,
|
|
303
|
+
minify: true,
|
|
304
|
+
sourceMap: sourcemap,
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const outFile = path.join(outDir, `${name}.min.css`);
|
|
308
|
+
fs.writeFileSync(outFile, result.code);
|
|
309
|
+
if (sourcemap && result.map) fs.writeFileSync(outFile + ".map", result.map);
|
|
310
|
+
|
|
311
|
+
console.log(`\n\x1b[32m✓\x1b[0m Built → ${outFile}`);
|
|
312
|
+
console.log(
|
|
313
|
+
` ${components.length} components, ${utilities.length} utilities`,
|
|
314
|
+
);
|
|
315
|
+
console.log(` ${(result.code.length / 1024).toFixed(1)}KB`);
|
|
316
|
+
} finally {
|
|
317
|
+
if (fs.existsSync(tmpFile)) fs.unlinkSync(tmpFile);
|
|
318
|
+
}
|