@seyuna/cli 1.0.0-canary.2 → 1.0.0-canary.21
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 -0
- package/README.md +1 -0
- package/esm/_dnt.polyfills.d.ts +101 -0
- package/esm/_dnt.polyfills.d.ts.map +1 -0
- package/esm/_dnt.polyfills.js +127 -0
- package/esm/_dnt.shims.d.ts +6 -0
- package/esm/_dnt.shims.d.ts.map +1 -0
- package/esm/_dnt.shims.js +61 -0
- package/esm/deno.d.ts +27 -0
- package/esm/deno.d.ts.map +1 -0
- package/esm/deno.js +30 -0
- package/esm/package.json +3 -0
- package/esm/src/config/init.d.ts +8 -0
- package/esm/src/config/init.d.ts.map +1 -0
- package/esm/src/config/init.js +68 -0
- package/esm/src/config/types.d.ts +25 -0
- package/esm/src/config/types.d.ts.map +1 -0
- package/esm/src/config/types.js +18 -0
- package/esm/src/helpers/cli.d.ts +45 -0
- package/esm/src/helpers/cli.d.ts.map +1 -0
- package/esm/src/helpers/cli.js +72 -0
- package/esm/src/helpers/fs.d.ts +35 -0
- package/esm/src/helpers/fs.d.ts.map +1 -0
- package/esm/src/helpers/fs.js +83 -0
- package/esm/src/helpers/styles.d.ts +54 -0
- package/esm/src/helpers/styles.d.ts.map +1 -0
- package/esm/src/helpers/styles.js +71 -0
- package/esm/src/main.d.ts +11 -0
- package/esm/src/main.d.ts.map +1 -0
- package/esm/src/main.js +110 -0
- package/esm/src/ui/compile.d.ts +21 -0
- package/esm/src/ui/compile.d.ts.map +1 -0
- package/esm/src/ui/compile.js +193 -0
- package/esm/src/ui/default.d.ts +8 -0
- package/esm/src/ui/default.d.ts.map +1 -0
- package/esm/src/ui/default.js +65 -0
- package/esm/src/ui/global.css.d.ts +11 -0
- package/esm/src/ui/global.css.d.ts.map +1 -0
- package/esm/src/ui/global.css.js +104 -0
- package/esm/src/ui/types.d.ts +77 -0
- package/esm/src/ui/types.d.ts.map +1 -0
- package/esm/src/ui/types.js +41 -0
- package/package.json +32 -18
- package/bin/seyuna.js +0 -10
- package/install.js +0 -42
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Config } from "../config/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Constructs an absolute or relative path from a filename and an output directory.
|
|
4
|
+
*
|
|
5
|
+
* @param fileName - The name of the file (e.g., "styles.css")
|
|
6
|
+
* @param outputDir - The target directory (e.g., "dist")
|
|
7
|
+
* @throws Error if fileName or outputDir are empty strings
|
|
8
|
+
* @returns The joined path string
|
|
9
|
+
*/
|
|
10
|
+
export declare function createPathFromFileName(fileName: string, outputDir: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Reads the text content of a file at the specified path.
|
|
13
|
+
*
|
|
14
|
+
* @param path - Path to the file to be read
|
|
15
|
+
* @throws Error with a descriptive message if the file is not found or cannot be read
|
|
16
|
+
* @returns The file content as a string
|
|
17
|
+
*/
|
|
18
|
+
export declare function readFile(path: string): Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Saves content to a file, ensuring the parent directory exists.
|
|
21
|
+
*
|
|
22
|
+
* @param path - The target file path
|
|
23
|
+
* @param content - The content to write (string or Uint8Array)
|
|
24
|
+
* @returns A promise that resolves when the file is written
|
|
25
|
+
*/
|
|
26
|
+
export declare function saveFile(path: string, content: string | Uint8Array): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Loads and parses the 'seyuna.json' configuration file from the current directory.
|
|
29
|
+
* Merges the user configuration with the default UI settings.
|
|
30
|
+
*
|
|
31
|
+
* @throws Error if 'seyuna.json' is missing or contains invalid JSON
|
|
32
|
+
* @returns The merged configuration object
|
|
33
|
+
*/
|
|
34
|
+
export declare function loadSeyunaUserConfig(): Promise<Config>;
|
|
35
|
+
//# sourceMappingURL=fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../../src/src/helpers/fs.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAIjD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,MAAM,CAQR;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAS5D;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,UAAU,GAC3B,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC,CAuB5D"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
+
import { dirname, join } from "@jsr/std__path";
|
|
3
|
+
import { ensureDir } from "@jsr/std__fs";
|
|
4
|
+
import { mergeConfig } from "../config/types.js";
|
|
5
|
+
import { UI_CONFIGURATION } from "../ui/default.js";
|
|
6
|
+
/**
|
|
7
|
+
* Constructs an absolute or relative path from a filename and an output directory.
|
|
8
|
+
*
|
|
9
|
+
* @param fileName - The name of the file (e.g., "styles.css")
|
|
10
|
+
* @param outputDir - The target directory (e.g., "dist")
|
|
11
|
+
* @throws Error if fileName or outputDir are empty strings
|
|
12
|
+
* @returns The joined path string
|
|
13
|
+
*/
|
|
14
|
+
export function createPathFromFileName(fileName, outputDir) {
|
|
15
|
+
if (!fileName.trim()) {
|
|
16
|
+
throw new Error("File name cannot be empty");
|
|
17
|
+
}
|
|
18
|
+
if (!outputDir.trim()) {
|
|
19
|
+
throw new Error("Output directory cannot be empty");
|
|
20
|
+
}
|
|
21
|
+
return join(outputDir, fileName);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Reads the text content of a file at the specified path.
|
|
25
|
+
*
|
|
26
|
+
* @param path - Path to the file to be read
|
|
27
|
+
* @throws Error with a descriptive message if the file is not found or cannot be read
|
|
28
|
+
* @returns The file content as a string
|
|
29
|
+
*/
|
|
30
|
+
export async function readFile(path) {
|
|
31
|
+
try {
|
|
32
|
+
return await dntShim.Deno.readTextFile(path);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error instanceof dntShim.Deno.errors.NotFound) {
|
|
36
|
+
throw new Error(`File not found at path: ${path}`);
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`Failed to read file at ${path}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Saves content to a file, ensuring the parent directory exists.
|
|
43
|
+
*
|
|
44
|
+
* @param path - The target file path
|
|
45
|
+
* @param content - The content to write (string or Uint8Array)
|
|
46
|
+
* @returns A promise that resolves when the file is written
|
|
47
|
+
*/
|
|
48
|
+
export async function saveFile(path, content) {
|
|
49
|
+
const dir = dirname(path);
|
|
50
|
+
await ensureDir(dir);
|
|
51
|
+
const data = typeof content === "string"
|
|
52
|
+
? new TextEncoder().encode(content)
|
|
53
|
+
: content;
|
|
54
|
+
await dntShim.Deno.writeFile(path, data);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Loads and parses the 'seyuna.json' configuration file from the current directory.
|
|
58
|
+
* Merges the user configuration with the default UI settings.
|
|
59
|
+
*
|
|
60
|
+
* @throws Error if 'seyuna.json' is missing or contains invalid JSON
|
|
61
|
+
* @returns The merged configuration object
|
|
62
|
+
*/
|
|
63
|
+
export async function loadSeyunaUserConfig() {
|
|
64
|
+
try {
|
|
65
|
+
const content = await readFile("seyuna.json");
|
|
66
|
+
const userConfig = JSON.parse(content);
|
|
67
|
+
/** @type {Config} Default fallback configuration */
|
|
68
|
+
const defaultConfig = {
|
|
69
|
+
license: undefined,
|
|
70
|
+
ui: UI_CONFIGURATION,
|
|
71
|
+
};
|
|
72
|
+
return mergeConfig(defaultConfig, userConfig);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (error instanceof Error && error.message.includes("File not found")) {
|
|
76
|
+
throw new Error("Could not find 'seyuna.json' in the current directory. Please run 'seyuna ui config --init' to generate it.");
|
|
77
|
+
}
|
|
78
|
+
if (error instanceof SyntaxError) {
|
|
79
|
+
throw new Error(`Failed to parse 'seyuna.json': ${error.message}`);
|
|
80
|
+
}
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A function that applies a color or style to a string.
|
|
3
|
+
*/
|
|
4
|
+
export type ColorFunction = (text: string) => string;
|
|
5
|
+
/**
|
|
6
|
+
* Standard brand colors and styles for the Seyuna CLI.
|
|
7
|
+
* Provides a consistent visual identity across all command outputs.
|
|
8
|
+
*/
|
|
9
|
+
export declare const Brand: {
|
|
10
|
+
/** Vibrant Spring Green - Primary brand color */
|
|
11
|
+
readonly primary: (text: string) => string;
|
|
12
|
+
/** Cyan - Secondary brand color */
|
|
13
|
+
readonly secondary: (text: string) => string;
|
|
14
|
+
/** Magenta - Accent color for highlights */
|
|
15
|
+
readonly accent: (text: string) => string;
|
|
16
|
+
/** Bold Green - Indicates successful operations */
|
|
17
|
+
readonly success: (text: string) => string;
|
|
18
|
+
/** Bold Red - Indicates errors or critical failures */
|
|
19
|
+
readonly error: (text: string) => string;
|
|
20
|
+
/** Bold Yellow - Indicates warnings or non-critical issues */
|
|
21
|
+
readonly warning: (text: string) => string;
|
|
22
|
+
/** Gray - For less important or decorative text */
|
|
23
|
+
readonly muted: (text: string) => string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Interpolates between two hex colors to create a gradient effect on text.
|
|
27
|
+
*
|
|
28
|
+
* @param text - The string to apply the gradient to
|
|
29
|
+
* @param startRgb - Start color in hex format (e.g., 0x00FF87)
|
|
30
|
+
* @param endRgb - End color in hex format (e.g., 0x60EFFF)
|
|
31
|
+
* @returns The text with ANSI color codes applied per character
|
|
32
|
+
*/
|
|
33
|
+
export declare function gradient(text: string, startRgb: number, endRgb: number): string;
|
|
34
|
+
/**
|
|
35
|
+
* Standard Seyuna gradient (Spring Green to Cyan).
|
|
36
|
+
* Used for logos and primary brand headings.
|
|
37
|
+
*/
|
|
38
|
+
export declare const seyunaGradient: ColorFunction;
|
|
39
|
+
/**
|
|
40
|
+
* Branded Unicode symbols for consistent status reporting.
|
|
41
|
+
*/
|
|
42
|
+
export declare const Symbols: {
|
|
43
|
+
/** Info icon (Cyan) */
|
|
44
|
+
readonly info: string;
|
|
45
|
+
/** Success icon (Green) */
|
|
46
|
+
readonly success: string;
|
|
47
|
+
/** Warning icon (Yellow) */
|
|
48
|
+
readonly warning: string;
|
|
49
|
+
/** Error icon (Red) */
|
|
50
|
+
readonly error: string;
|
|
51
|
+
/** Decorative arrow (Muted) */
|
|
52
|
+
readonly arrow: string;
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../src/src/helpers/styles.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAErD;;;GAGG;AACH,eAAO,MAAM,KAAK;IAChB,iDAAiD;6BACjC,MAAM;IAEtB,mCAAmC;+BACjB,MAAM;IAExB,4CAA4C;4BAC7B,MAAM;IAErB,mDAAmD;6BACnC,MAAM;IAEtB,uDAAuD;2BACzC,MAAM;IAEpB,8DAA8D;6BAC9C,MAAM;IAEtB,mDAAmD;2BACrC,MAAM;CAC4B,CAAC;AAEnD;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAyB/E;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,aACO,CAAC;AAErC;;GAEG;AACH,eAAO,MAAM,OAAO;IAClB,uBAAuB;;IAGvB,2BAA2B;;IAG3B,4BAA4B;;IAG5B,uBAAuB;;IAGvB,+BAA+B;;CAEU,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as colors from "@jsr/std__fmt/colors";
|
|
2
|
+
/**
|
|
3
|
+
* Standard brand colors and styles for the Seyuna CLI.
|
|
4
|
+
* Provides a consistent visual identity across all command outputs.
|
|
5
|
+
*/
|
|
6
|
+
export const Brand = {
|
|
7
|
+
/** Vibrant Spring Green - Primary brand color */
|
|
8
|
+
primary: (text) => colors.rgb24(text, 0x00FF87),
|
|
9
|
+
/** Cyan - Secondary brand color */
|
|
10
|
+
secondary: (text) => colors.rgb24(text, 0x60EFFF),
|
|
11
|
+
/** Magenta - Accent color for highlights */
|
|
12
|
+
accent: (text) => colors.rgb24(text, 0xFF00E5),
|
|
13
|
+
/** Bold Green - Indicates successful operations */
|
|
14
|
+
success: (text) => colors.bold(colors.green(text)),
|
|
15
|
+
/** Bold Red - Indicates errors or critical failures */
|
|
16
|
+
error: (text) => colors.bold(colors.red(text)),
|
|
17
|
+
/** Bold Yellow - Indicates warnings or non-critical issues */
|
|
18
|
+
warning: (text) => colors.bold(colors.yellow(text)),
|
|
19
|
+
/** Gray - For less important or decorative text */
|
|
20
|
+
muted: (text) => colors.gray(text),
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Interpolates between two hex colors to create a gradient effect on text.
|
|
24
|
+
*
|
|
25
|
+
* @param text - The string to apply the gradient to
|
|
26
|
+
* @param startRgb - Start color in hex format (e.g., 0x00FF87)
|
|
27
|
+
* @param endRgb - End color in hex format (e.g., 0x60EFFF)
|
|
28
|
+
* @returns The text with ANSI color codes applied per character
|
|
29
|
+
*/
|
|
30
|
+
export function gradient(text, startRgb, endRgb) {
|
|
31
|
+
const start = {
|
|
32
|
+
r: (startRgb >> 16) & 0xFF,
|
|
33
|
+
g: (startRgb >> 8) & 0xFF,
|
|
34
|
+
b: startRgb & 0xFF,
|
|
35
|
+
};
|
|
36
|
+
const end = {
|
|
37
|
+
r: (endRgb >> 16) & 0xFF,
|
|
38
|
+
g: (endRgb >> 8) & 0xFF,
|
|
39
|
+
b: endRgb & 0xFF,
|
|
40
|
+
};
|
|
41
|
+
const characters = Array.from(text);
|
|
42
|
+
const length = characters.length;
|
|
43
|
+
return characters.map((char, i) => {
|
|
44
|
+
// If text is 1 char long, use start color
|
|
45
|
+
const factor = length > 1 ? i / (length - 1) : 0;
|
|
46
|
+
const r = Math.round(start.r + factor * (end.r - start.r));
|
|
47
|
+
const g = Math.round(start.g + factor * (end.g - start.g));
|
|
48
|
+
const b = Math.round(start.b + factor * (end.b - start.b));
|
|
49
|
+
return colors.rgb24(char, (r << 16) | (g << 8) | b);
|
|
50
|
+
}).join("");
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Standard Seyuna gradient (Spring Green to Cyan).
|
|
54
|
+
* Used for logos and primary brand headings.
|
|
55
|
+
*/
|
|
56
|
+
export const seyunaGradient = (text) => gradient(text, 0x00FF87, 0x60EFFF);
|
|
57
|
+
/**
|
|
58
|
+
* Branded Unicode symbols for consistent status reporting.
|
|
59
|
+
*/
|
|
60
|
+
export const Symbols = {
|
|
61
|
+
/** Info icon (Cyan) */
|
|
62
|
+
info: Brand.secondary("ℹ"),
|
|
63
|
+
/** Success icon (Green) */
|
|
64
|
+
success: Brand.success("✔"),
|
|
65
|
+
/** Warning icon (Yellow) */
|
|
66
|
+
warning: Brand.warning("⚠"),
|
|
67
|
+
/** Error icon (Red) */
|
|
68
|
+
error: Brand.error("✖"),
|
|
69
|
+
/** Decorative arrow (Muted) */
|
|
70
|
+
arrow: Brand.muted("›"),
|
|
71
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seyuna CLI - Entrypoint
|
|
3
|
+
*
|
|
4
|
+
* This is the main orchestrator for the Seyuna Command Line Interface.
|
|
5
|
+
* It defines the command hierarchy and provides the branded "Premium"
|
|
6
|
+
* help screens.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import "../_dnt.polyfills.js";
|
|
11
|
+
//# sourceMappingURL=main.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/src/main.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,sBAAsB,CAAC"}
|
package/esm/src/main.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Seyuna CLI - Entrypoint
|
|
4
|
+
*
|
|
5
|
+
* This is the main orchestrator for the Seyuna Command Line Interface.
|
|
6
|
+
* It defines the command hierarchy and provides the branded "Premium"
|
|
7
|
+
* help screens.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import "../_dnt.polyfills.js";
|
|
12
|
+
import * as dntShim from "../_dnt.shims.js";
|
|
13
|
+
import { Command } from "@jsr/cliffy__command";
|
|
14
|
+
import * as colors from "@jsr/std__fmt/colors";
|
|
15
|
+
import { initConfig } from "./config/init.js";
|
|
16
|
+
import { compile } from "./ui/compile.js";
|
|
17
|
+
import { Brand, seyunaGradient } from "./helpers/styles.js";
|
|
18
|
+
// Import project name and version from deno.json for single-source-of-truth.
|
|
19
|
+
import denoConfig from "../deno.js";
|
|
20
|
+
const VERSION = denoConfig.version;
|
|
21
|
+
/**
|
|
22
|
+
* High-fidelity ASCII logo for the CLI.
|
|
23
|
+
* Rendered using the primary brand gradient.
|
|
24
|
+
*/
|
|
25
|
+
const seyunaLogo = seyunaGradient(`
|
|
26
|
+
|
|
27
|
+
_____ _____ __ __ _____ _____ _____
|
|
28
|
+
| __| __| | | | | | | _ |
|
|
29
|
+
|__ | __|_ _| | | | | | |
|
|
30
|
+
|_____|_____| |_| |_____|_|___|__|__|
|
|
31
|
+
|
|
32
|
+
`);
|
|
33
|
+
/**
|
|
34
|
+
* 'ui' Command Definition.
|
|
35
|
+
* Handles style compilation, real-time watching, and configuration.
|
|
36
|
+
*/
|
|
37
|
+
const uiCmd = new Command()
|
|
38
|
+
.option("-c, --compile", "Run a one-time compilation of your styles.")
|
|
39
|
+
.option("-w, --watch", "Watch for changes and re-compile automatically.")
|
|
40
|
+
.action(async (options) => {
|
|
41
|
+
if (options.compile || options.watch) {
|
|
42
|
+
await compile({ watch: options.watch });
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.log(Brand.warning("Please provide an option or subcommand. See --help for more info."));
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
/**
|
|
49
|
+
* 'ui config' Subcommand.
|
|
50
|
+
* Handles project initialization.
|
|
51
|
+
*/
|
|
52
|
+
.command("config")
|
|
53
|
+
.option("-i, --init", "Initialize a new 'seyuna.json' configuration.")
|
|
54
|
+
.action(async (options) => {
|
|
55
|
+
if (options.init) {
|
|
56
|
+
await initConfig();
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.log(Brand.warning("Please provide an option. See --help for more info."));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* Root 'seyuna' Command.
|
|
64
|
+
*/
|
|
65
|
+
const cmd = new Command()
|
|
66
|
+
.name("seyuna")
|
|
67
|
+
.version(VERSION)
|
|
68
|
+
.action(() => {
|
|
69
|
+
// Show help by default if no subcommand is provided.
|
|
70
|
+
cmd.showHelp();
|
|
71
|
+
})
|
|
72
|
+
.command("ui", uiCmd)
|
|
73
|
+
.command("generate-json-schema")
|
|
74
|
+
.hidden() // Hidden command for future expansion
|
|
75
|
+
.action(() => {
|
|
76
|
+
console.log(Brand.muted("JSON schema generation is planned for a future release."));
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* Traverses the command tree and prepends the branded logo to every
|
|
80
|
+
* generated help screen. This ensures a consistent premium brand experience.
|
|
81
|
+
*
|
|
82
|
+
* @param command - The Cliffy Command instance to apply the logo to.
|
|
83
|
+
*/
|
|
84
|
+
// deno-lint-ignore no-explicit-any
|
|
85
|
+
const applyBrandedHelp = (command) => {
|
|
86
|
+
const originalGetHelp = command.getHelp;
|
|
87
|
+
command.getHelp = function () {
|
|
88
|
+
return seyunaLogo + originalGetHelp.call(this);
|
|
89
|
+
};
|
|
90
|
+
// Recursively apply to all sub-commands
|
|
91
|
+
command.getCommands().forEach((c) => applyBrandedHelp(c));
|
|
92
|
+
};
|
|
93
|
+
// Initialize branding
|
|
94
|
+
// @ts-ignore: Cliffy Command types are highly generic and conflict after adding subcommands
|
|
95
|
+
applyBrandedHelp(cmd);
|
|
96
|
+
/**
|
|
97
|
+
* CLI Execution Loop.
|
|
98
|
+
* Handles argument parsing and top-level error reporting.
|
|
99
|
+
*/
|
|
100
|
+
if (globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).main) {
|
|
101
|
+
try {
|
|
102
|
+
await cmd.parse(dntShim.Deno.args);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
if (error instanceof Error) {
|
|
106
|
+
console.error(`${colors.bold(colors.red("Error:"))} ${error.message}`);
|
|
107
|
+
}
|
|
108
|
+
dntShim.Deno.exit(1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Config } from "../config/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Main entrypoint for the UI compilation process.
|
|
4
|
+
* Orchestrates loading configuration, generating CSS, and optionally
|
|
5
|
+
* starting a file watcher for real-time development.
|
|
6
|
+
*
|
|
7
|
+
* @param options - Compilation options, including 'watch' mode
|
|
8
|
+
* @returns The loaded project configuration
|
|
9
|
+
*/
|
|
10
|
+
export declare function compile(options: {
|
|
11
|
+
watch?: boolean;
|
|
12
|
+
}): Promise<Config>;
|
|
13
|
+
/**
|
|
14
|
+
* The core engine that translates project tokens into functional CSS files.
|
|
15
|
+
* Generates both 'seyuna-global.css' (reset + variables) and
|
|
16
|
+
* 'postcss-variables.css' (design token manifest for PostCSS).
|
|
17
|
+
*
|
|
18
|
+
* @param config - The project configuration object
|
|
19
|
+
*/
|
|
20
|
+
export declare function compileCss(config: Config): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=compile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/src/ui/compile.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAYjD;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAc3E;AAkCD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB9D"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
+
import { GLOBAL_CSS } from "./global.css.js";
|
|
3
|
+
import { createPathFromFileName, loadSeyunaUserConfig, saveFile, } from "../helpers/fs.js";
|
|
4
|
+
import { SeyunaSpinner } from "../helpers/cli.js";
|
|
5
|
+
import { delay } from "@jsr/std__async";
|
|
6
|
+
import { Brand } from "../helpers/styles.js";
|
|
7
|
+
/**
|
|
8
|
+
* Main entrypoint for the UI compilation process.
|
|
9
|
+
* Orchestrates loading configuration, generating CSS, and optionally
|
|
10
|
+
* starting a file watcher for real-time development.
|
|
11
|
+
*
|
|
12
|
+
* @param options - Compilation options, including 'watch' mode
|
|
13
|
+
* @returns The loaded project configuration
|
|
14
|
+
*/
|
|
15
|
+
export async function compile(options) {
|
|
16
|
+
try {
|
|
17
|
+
const config = await loadSeyunaUserConfig();
|
|
18
|
+
await compileCss(config);
|
|
19
|
+
if (options.watch) {
|
|
20
|
+
console.log(`\n${Brand.secondary("Watching for changes...")}`);
|
|
21
|
+
await watchConfigAndRecompile("seyuna.json");
|
|
22
|
+
}
|
|
23
|
+
return config;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Starts an optimized file watcher on the configuration manifest.
|
|
31
|
+
* Provides debounced recompilation to handle rapid file system events.
|
|
32
|
+
*
|
|
33
|
+
* @param file - The path to the configuration file to watch
|
|
34
|
+
*/
|
|
35
|
+
async function watchConfigAndRecompile(file) {
|
|
36
|
+
const watcher = dntShim.Deno.watchFs(file);
|
|
37
|
+
let debounceTimer;
|
|
38
|
+
for await (const event of watcher) {
|
|
39
|
+
// Only trigger on actual content modifications
|
|
40
|
+
if (event.kind === "modify") {
|
|
41
|
+
if (debounceTimer)
|
|
42
|
+
clearTimeout(debounceTimer);
|
|
43
|
+
debounceTimer = setTimeout(async () => {
|
|
44
|
+
// Short delay to ensure the OS has finished writing the file
|
|
45
|
+
await delay(300);
|
|
46
|
+
try {
|
|
47
|
+
const config = await loadSeyunaUserConfig();
|
|
48
|
+
await compileCss(config);
|
|
49
|
+
const time = new Date().toLocaleTimeString();
|
|
50
|
+
console.log(`${Brand.muted(time)} ${Brand.success("Recompiled successfully")}`);
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
console.error(`${Brand.error("Watch Error:")} ${e instanceof Error ? e.message : "Unknown error"}`);
|
|
54
|
+
}
|
|
55
|
+
}, 50);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The core engine that translates project tokens into functional CSS files.
|
|
61
|
+
* Generates both 'seyuna-global.css' (reset + variables) and
|
|
62
|
+
* 'postcss-variables.css' (design token manifest for PostCSS).
|
|
63
|
+
*
|
|
64
|
+
* @param config - The project configuration object
|
|
65
|
+
*/
|
|
66
|
+
export async function compileCss(config) {
|
|
67
|
+
const spinner = new SeyunaSpinner("Compiling your UI styles").start();
|
|
68
|
+
try {
|
|
69
|
+
const ui = getUiConfig(config);
|
|
70
|
+
if (!ui.output_dir) {
|
|
71
|
+
throw new Error("Output directory ('output_dir') must be specified in the UI configuration.");
|
|
72
|
+
}
|
|
73
|
+
spinner.progress("Building token manifest");
|
|
74
|
+
const globalCss = buildGlobalCss(config);
|
|
75
|
+
const postcssVariables = buildPostcssVariables(config);
|
|
76
|
+
const globalPath = createPathFromFileName("seyuna-global.css", ui.output_dir);
|
|
77
|
+
const varsPath = createPathFromFileName("postcss-variables.css", ui.output_dir);
|
|
78
|
+
spinner.progress(`Persisting styles to ${ui.output_dir}`);
|
|
79
|
+
await saveFile(globalPath, globalCss);
|
|
80
|
+
await saveFile(varsPath, postcssVariables);
|
|
81
|
+
spinner.done("Styles compiled successfully!");
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
spinner.error(`Compilation failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Safely extracts the UI block from the root configuration.
|
|
90
|
+
*/
|
|
91
|
+
function getUiConfig(config) {
|
|
92
|
+
if (!config.ui) {
|
|
93
|
+
throw new Error("Missing 'ui' configuration block in 'seyuna.json'.");
|
|
94
|
+
}
|
|
95
|
+
return config.ui;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Combines dynamic token variables with the global reset template.
|
|
99
|
+
*/
|
|
100
|
+
function buildGlobalCss(config) {
|
|
101
|
+
return [buildCssVariables(config), GLOBAL_CSS].join("\n");
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Generates a full CSS variable sheet including base tokens,
|
|
105
|
+
* theme modes, and system scheme adaptivity.
|
|
106
|
+
*/
|
|
107
|
+
function buildCssVariables(config) {
|
|
108
|
+
const ui = getUiConfig(config);
|
|
109
|
+
const out = [":root {"];
|
|
110
|
+
// Hue Tokens (e.g., --alpha-hue)
|
|
111
|
+
for (const [name, val] of Object.entries(ui.theme.hues)) {
|
|
112
|
+
out.push(` --${name}-hue: ${val};`);
|
|
113
|
+
}
|
|
114
|
+
// Global Semantic Colors
|
|
115
|
+
for (const [name, color] of Object.entries(ui.theme.colors)) {
|
|
116
|
+
out.push(` --${name}-lightness: ${color.lightness};`);
|
|
117
|
+
out.push(` --${name}-chroma: ${color.chroma};`);
|
|
118
|
+
out.push(` --${name}-hue: ${color.hue};`);
|
|
119
|
+
}
|
|
120
|
+
out.push("}\n");
|
|
121
|
+
const modes = ["light", "dark"];
|
|
122
|
+
// Explicit Theme Mode Overrides ([data-mode="light"])
|
|
123
|
+
for (const mode of modes) {
|
|
124
|
+
out.push(`[data-mode="${mode}"] {`);
|
|
125
|
+
out.push(buildModeBlock(ui, mode));
|
|
126
|
+
// Mode-specific semantic color overrides
|
|
127
|
+
for (const [name, color] of Object.entries(ui.theme[mode].colors)) {
|
|
128
|
+
out.push(` --${name}-lightness: ${color.lightness};`);
|
|
129
|
+
out.push(` --${name}-chroma: ${color.chroma};`);
|
|
130
|
+
out.push(` --${name}-hue: ${color.hue};`);
|
|
131
|
+
}
|
|
132
|
+
out.push("}\n");
|
|
133
|
+
}
|
|
134
|
+
// System Adatpivity (Auto switching via @media)
|
|
135
|
+
for (const mode of modes) {
|
|
136
|
+
out.push(`@media (prefers-color-scheme: ${mode}) {`);
|
|
137
|
+
out.push(' [data-mode="system"] {');
|
|
138
|
+
out.push(indent(buildModeBlock(ui, mode), 2));
|
|
139
|
+
for (const [name, color] of Object.entries(ui.theme[mode].colors)) {
|
|
140
|
+
out.push(` --${name}-lightness: ${color.lightness};`);
|
|
141
|
+
out.push(` --${name}-chroma: ${color.chroma};`);
|
|
142
|
+
out.push(` --${name}-hue: ${color.hue};`);
|
|
143
|
+
}
|
|
144
|
+
out.push(" }");
|
|
145
|
+
out.push("}\n");
|
|
146
|
+
}
|
|
147
|
+
return out.join("\n");
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Generates a SASS/PostCSS compatible SCSS manifest.
|
|
151
|
+
* Used for deep integration with traditional build tools.
|
|
152
|
+
*/
|
|
153
|
+
function buildPostcssVariables(config) {
|
|
154
|
+
const ui = getUiConfig(config);
|
|
155
|
+
const fixed = Object.keys(ui.theme.colors).map((c) => `'${c}'`).join(", ");
|
|
156
|
+
const hues = Object.keys(ui.theme.hues).map((n) => `'${n}'`).join(", ");
|
|
157
|
+
return [
|
|
158
|
+
`$fixed_colors: (${fixed});`,
|
|
159
|
+
`$standard_colors: (${hues});`,
|
|
160
|
+
"$xs: 20rem;",
|
|
161
|
+
"$sm: 40rem;",
|
|
162
|
+
"$md: 48rem;",
|
|
163
|
+
"$lg: 64rem;",
|
|
164
|
+
"$xl: 80rem;",
|
|
165
|
+
"\n",
|
|
166
|
+
].join("\n");
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Builds a block of core CSS variables (background, text) for a specific mode.
|
|
170
|
+
*/
|
|
171
|
+
function buildModeBlock(ui, mode) {
|
|
172
|
+
const p = ui.theme[mode];
|
|
173
|
+
return [
|
|
174
|
+
` --background: oklch(${p.background.lightness} ${p.background.chroma} ${p.background.hue});`,
|
|
175
|
+
` --text: oklch(${p.text.lightness} ${p.text.chroma} ${p.text.hue});`,
|
|
176
|
+
` --chroma: ${p.chroma};`,
|
|
177
|
+
` --lightness: ${p.lightness};`,
|
|
178
|
+
].join("\n");
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Helper to indent string lines for pretty-printed CSS output.
|
|
182
|
+
*
|
|
183
|
+
* @param s - The string to indent
|
|
184
|
+
* @param level - Number of double-space indents to apply
|
|
185
|
+
* @returns The formatted and indented string
|
|
186
|
+
*/
|
|
187
|
+
function indent(s, level) {
|
|
188
|
+
const pad = " ".repeat(level);
|
|
189
|
+
return s.split(/\r?\n/)
|
|
190
|
+
.filter((line) => line.trim().length > 0)
|
|
191
|
+
.map((line) => `${pad}${line.trim()}\n`)
|
|
192
|
+
.join("");
|
|
193
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { UI } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The default out-of-the-box UI configuration for Seyuna projects.
|
|
4
|
+
* This provides a robust set of design tokens including a full
|
|
5
|
+
* Greek-lettered hue scale and foundational semantic colors.
|
|
6
|
+
*/
|
|
7
|
+
export declare const UI_CONFIGURATION: UI;
|
|
8
|
+
//# sourceMappingURL=default.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default.d.ts","sourceRoot":"","sources":["../../../src/src/ui/default.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAErC;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAgE9B,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default out-of-the-box UI configuration for Seyuna projects.
|
|
3
|
+
* This provides a robust set of design tokens including a full
|
|
4
|
+
* Greek-lettered hue scale and foundational semantic colors.
|
|
5
|
+
*/
|
|
6
|
+
export const UI_CONFIGURATION = {
|
|
7
|
+
theme: {
|
|
8
|
+
/**
|
|
9
|
+
* Global hue scale. Uses Greek letters to provide semantically neutral
|
|
10
|
+
* references for the 360-degree color wheel.
|
|
11
|
+
*/
|
|
12
|
+
hues: {
|
|
13
|
+
"alpha": 0,
|
|
14
|
+
"beta": 15,
|
|
15
|
+
"gamma": 30,
|
|
16
|
+
"delta": 45,
|
|
17
|
+
"epsilon": 60,
|
|
18
|
+
"zeta": 75,
|
|
19
|
+
"eta": 90,
|
|
20
|
+
"theta": 105,
|
|
21
|
+
"iota": 120,
|
|
22
|
+
"kappa": 135,
|
|
23
|
+
"lambda": 150,
|
|
24
|
+
"mu": 165,
|
|
25
|
+
"nu": 180,
|
|
26
|
+
"xi": 195,
|
|
27
|
+
"omicron": 210,
|
|
28
|
+
"pi": 225,
|
|
29
|
+
"rho": 240,
|
|
30
|
+
"sigma": 255,
|
|
31
|
+
"tau": 270,
|
|
32
|
+
"upsilon": 285,
|
|
33
|
+
"phi": 300,
|
|
34
|
+
"chi": 315,
|
|
35
|
+
"psi": 330,
|
|
36
|
+
"omega": 345,
|
|
37
|
+
},
|
|
38
|
+
/** Base semantic colors shared across modes */
|
|
39
|
+
colors: {
|
|
40
|
+
"white": { lightness: 1.0, chroma: 0.0, hue: 0 },
|
|
41
|
+
"black": { lightness: 0.0, chroma: 0.0, hue: 0 },
|
|
42
|
+
"primary": { lightness: 0.66, chroma: 0.26, hue: 240 },
|
|
43
|
+
},
|
|
44
|
+
/** Default light mode palette */
|
|
45
|
+
light: {
|
|
46
|
+
chroma: 0.26,
|
|
47
|
+
lightness: 0.66,
|
|
48
|
+
background: { hue: 0, chroma: 0.0, lightness: 1.0 },
|
|
49
|
+
text: { hue: 0, chroma: 0.0, lightness: 0.0 },
|
|
50
|
+
colors: {},
|
|
51
|
+
},
|
|
52
|
+
/** Default dark mode palette */
|
|
53
|
+
dark: {
|
|
54
|
+
chroma: 0.26,
|
|
55
|
+
lightness: 0.66,
|
|
56
|
+
background: { hue: 0, chroma: 0.0, lightness: 0.0 },
|
|
57
|
+
text: { hue: 0, chroma: 0.0, lightness: 1.0 },
|
|
58
|
+
colors: {},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
/** Default to following the system's preferred color scheme */
|
|
62
|
+
mode: "system",
|
|
63
|
+
/** Standard output directory for generated CSS assets */
|
|
64
|
+
output_dir: "src/styles",
|
|
65
|
+
};
|