beathers 5.2.2 → 5.3.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/CHANGELOG +113 -0
- package/dist/css/beathers-icons.min.css +1 -1
- package/dist/css/beathers-icons.min.css.map +1 -1
- package/dist/css/beathers.min.css +2 -2
- package/dist/css/beathers.min.css.map +1 -1
- package/dist/data/colors.d.ts +9 -0
- package/dist/data/colors.js +54 -0
- package/dist/data/font.d.ts +3 -0
- package/dist/data/font.js +32 -0
- package/dist/data/index.d.ts +2 -0
- package/dist/data/index.js +2 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -1
- package/dist/scripts/cli.js +7 -220
- package/dist/scripts/commands/build.d.ts +1 -0
- package/dist/scripts/commands/build.js +128 -0
- package/dist/scripts/commands/colors.d.ts +4 -0
- package/dist/scripts/commands/colors.js +140 -0
- package/dist/scripts/commands/fonts.d.ts +3 -0
- package/dist/scripts/commands/fonts.js +124 -0
- package/dist/scripts/commands/help.d.ts +1 -0
- package/dist/scripts/commands/help.js +42 -0
- package/dist/scripts/commands/index.d.ts +13 -0
- package/dist/scripts/commands/index.js +95 -0
- package/dist/scripts/commands/init.d.ts +1 -0
- package/dist/scripts/commands/init.js +129 -0
- package/dist/scripts/commands/list.d.ts +2 -0
- package/dist/scripts/commands/list.js +29 -0
- package/dist/scripts/commands/version.d.ts +1 -0
- package/dist/scripts/commands/version.js +13 -0
- package/dist/scripts/{BuildScssVariables.d.ts → helpers/BuildScssVariables.d.ts} +1 -1
- package/dist/scripts/{BuildScssVariables.js → helpers/BuildScssVariables.js} +4 -4
- package/dist/scripts/{LoadUserConfigs.d.ts → helpers/LoadUserConfigs.d.ts} +1 -1
- package/dist/scripts/{Merge.d.ts → helpers/Merge.d.ts} +1 -1
- package/dist/scripts/{ReadDefaultValues.d.ts → helpers/ReadDefaultValues.d.ts} +1 -1
- package/dist/scripts/{ReadDefaultValues.js → helpers/ReadDefaultValues.js} +6 -2
- package/dist/scripts/helpers/index.d.ts +5 -0
- package/dist/scripts/helpers/index.js +5 -0
- package/dist/scripts/types.d.ts +41 -4
- package/dist/scripts/types.js +1 -0
- package/package.json +83 -80
- package/readme.md +28 -0
- package/src/scss/_variables.scss +1 -305
- package/src/scss/beathers-icons.min.scss +245 -245
- package/src/scss/beathers.min.scss +2 -4
- package/src/scss/functions/_colors.scss +79 -68
- package/src/scss/functions/_mediaQueries.scss +22 -12
- package/src/scss/functions/_others.scss +31 -22
- package/src/scss/functions/_typographic.scss +11 -2
- package/src/scss/functions/_validations.scss +38 -43
- package/src/scss/settings/_configs.scss +1 -72
- package/src/scss/settings/_defaults.scss +139 -212
- package/src/scss/style/_colors.scss +39 -23
- package/src/scss/style/_grid.scss +23 -25
- package/src/scss/style/_resets.scss +119 -0
- package/src/scss/style/_shaping.scss +142 -89
- package/src/scss/style/_typographic.scss +79 -36
- package/dist/scripts/BuildTheme.d.ts +0 -1
- package/dist/scripts/BuildTheme.js +0 -75
- package/src/scss/settings/_resets.scss +0 -103
- /package/dist/scripts/{CallNewVariables.d.ts → helpers/CallNewVariables.d.ts} +0 -0
- /package/dist/scripts/{CallNewVariables.js → helpers/CallNewVariables.js} +0 -0
- /package/dist/scripts/{LoadUserConfigs.js → helpers/LoadUserConfigs.js} +0 -0
- /package/dist/scripts/{Merge.js → helpers/Merge.js} +0 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { findConfigFile, loadConfig, promptInput, promptSelection, promptUser, saveConfig } from '@commands';
|
|
3
|
+
import { importedFont, localFont } from '@data';
|
|
4
|
+
export async function AddFont() {
|
|
5
|
+
const configFile = await findConfigFile();
|
|
6
|
+
if (!configFile) {
|
|
7
|
+
console.error('❌ No config file found. Run "\x1b[34mbeathers init\x1b[0m" first.');
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const question = (q, locale) => {
|
|
11
|
+
const lang = locale.toUpperCase();
|
|
12
|
+
const questions = {
|
|
13
|
+
title: `\x1b[36m📝 Enter "${lang} variant" title:\x1b[0m `,
|
|
14
|
+
unicode: `\x1b[36m🔤 Enter "${lang} variant" unicode range (optional):\x1b[0m `,
|
|
15
|
+
isLocal: `\x1b[33m🔤 Is "${lang} variant" a local font?\x1b[0m\n\x1b[32m[Y]\x1b[0m Yes \x1b[31m[N]\x1b[0m No: `,
|
|
16
|
+
url: `\x1b[36m🌐 Enter "${lang} variant" URL (must start with http:// or https://):\x1b[0m `,
|
|
17
|
+
format: `\x1b[36m📄 Choose "${lang} variant" format:\x1b[0m`,
|
|
18
|
+
};
|
|
19
|
+
return questions[q];
|
|
20
|
+
};
|
|
21
|
+
try {
|
|
22
|
+
const fontName = await promptInput('\x1b[36m📝 Enter font name:\x1b[0m ');
|
|
23
|
+
if (!fontName) {
|
|
24
|
+
console.error('❌ Font name is \x1b[31mrequired\x1b[0m.');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const weightsInput = await promptInput('\x1b[36m⚖️ Enter font weights (comma-separated, e.g., light,regular,bold) (optional):\x1b[0m ');
|
|
28
|
+
const weights = weightsInput?.split(',').map((w) => w.trim());
|
|
29
|
+
const stylesInput = await promptInput('\x1b[36m🎨 Enter font styles (comma-separated, e.g., normal,italic) (optional):\x1b[0m ');
|
|
30
|
+
const styles = stylesInput?.split(',').map((s) => s.trim());
|
|
31
|
+
const localesInput = await promptInput('\x1b[36m🌐 Enter font variant locales (comma-separated, e.g., en,ar):\x1b[0m ');
|
|
32
|
+
const locales = localesInput?.split(',').map((w) => w.trim());
|
|
33
|
+
const variants = {};
|
|
34
|
+
for (const l of locales) {
|
|
35
|
+
let url, format;
|
|
36
|
+
const title = await promptInput(question('title', l));
|
|
37
|
+
const unicode = await promptInput(question('unicode', l));
|
|
38
|
+
const isLocal = await promptUser(question('isLocal', l));
|
|
39
|
+
if (!isLocal)
|
|
40
|
+
while (true) {
|
|
41
|
+
url = await promptInput(question('url', l));
|
|
42
|
+
if (url && /^https?:\/\//.test(url))
|
|
43
|
+
break;
|
|
44
|
+
console.error('❌ Invalid URL format. URL must start with \x1b[36mhttp://\x1b[0m or \x1b[36mhttps://\x1b[0m');
|
|
45
|
+
}
|
|
46
|
+
else
|
|
47
|
+
format = await promptSelection(question('format', l), ['woff2', 'woff']);
|
|
48
|
+
variants[l] = {
|
|
49
|
+
title: title ?? fontName,
|
|
50
|
+
...(unicode && { unicode }),
|
|
51
|
+
...(format && { format }),
|
|
52
|
+
...(isLocal === false && { isLocal }),
|
|
53
|
+
...(!isLocal && url && { url: url }),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const font = {
|
|
57
|
+
...(weights.length > 0 && {
|
|
58
|
+
weights: weights.filter((w) => ['thin', 'extra-light', 'light', 'regular', 'medium', 'semibold', 'bold', 'extra-bold', 'black'].includes(w)),
|
|
59
|
+
}),
|
|
60
|
+
...(styles.length > 0 && {
|
|
61
|
+
styles: styles.filter((s) => ['normal', 'italic', 'oblique'].includes(s)),
|
|
62
|
+
}),
|
|
63
|
+
variants,
|
|
64
|
+
};
|
|
65
|
+
const config = await loadConfig(configFile);
|
|
66
|
+
config.typography ??= {};
|
|
67
|
+
config.typography.fonts ??= {};
|
|
68
|
+
config.typography.fonts[fontName] = font;
|
|
69
|
+
await saveConfig(configFile, config);
|
|
70
|
+
console.log(`✅ Successfully added font \x1b[32m"${fontName}"\x1b[0m!`);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
console.error('❌ Error adding font:', error);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export async function RemoveFont() {
|
|
77
|
+
const configFile = await findConfigFile();
|
|
78
|
+
if (!configFile) {
|
|
79
|
+
console.error('❌ No config file found. Run "\x1b[34mbeathers init\x1b[0m" first.');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const fontName = await promptInput('\x1b[36m🗑️ Enter font name to remove:\x1b[0m\n\x1b[33mThis will delete all weights, styles, and variants of the selected font.\x1b[0m\n> ');
|
|
83
|
+
if (!fontName) {
|
|
84
|
+
console.error('❌ Font name is \x1b[31mrequired\x1b[0m.');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const config = await loadConfig(configFile);
|
|
89
|
+
if (!config.typography?.fonts?.[fontName]) {
|
|
90
|
+
console.error(`❌ Font "\x1b[31m${fontName}\x1b[0m" not found in config.`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
delete config.typography.fonts[fontName];
|
|
94
|
+
await saveConfig(configFile, config);
|
|
95
|
+
console.log(`✅ Successfully removed font \x1b[32m"${fontName}"\x1b[0m!`);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
console.error('❌ Error removing font:', error);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export async function ImportFont() {
|
|
102
|
+
const configFile = await findConfigFile();
|
|
103
|
+
if (!configFile) {
|
|
104
|
+
console.error('❌ No config file found. Run "\x1b[34mbeathers init\x1b[0m" first.');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const isLocal = await promptUser('\x1b[33m🔤 Do you want a local font?\x1b[0m\n\x1b[32m[Y]\x1b[0m Yes \x1b[31m[N]\x1b[0m No: ');
|
|
108
|
+
const fontName = await promptInput('\x1b[36m📝 Enter font name:\x1b[0m ');
|
|
109
|
+
if (!fontName) {
|
|
110
|
+
console.error('❌ Font name is \x1b[31mrequired\x1b[0m.');
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const config = await loadConfig(configFile);
|
|
115
|
+
config.typography ??= {};
|
|
116
|
+
config.typography.fonts ??= {};
|
|
117
|
+
config.typography.fonts[fontName] = isLocal ? localFont : importedFont;
|
|
118
|
+
await saveConfig(configFile, config);
|
|
119
|
+
console.log(`✅ Successfully imported sample font \x1b[32m"${fontName}"\x1b[0m!`);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.error('❌ Error importing font sample:', error);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function Help(): void;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
const commands = [
|
|
3
|
+
{ cmd: '--help', description: 'Show available commands' },
|
|
4
|
+
{ cmd: '-v', description: 'Show beathers version' },
|
|
5
|
+
{ divider: true },
|
|
6
|
+
{ cmd: 'init', description: 'Initialize beathers configuration file' },
|
|
7
|
+
{ cmd: 'build', description: 'Build theme from configuration file' },
|
|
8
|
+
{ divider: true },
|
|
9
|
+
{ cmd: 'add-font', description: 'Add a new font to the configuration file' },
|
|
10
|
+
{ cmd: 'remove-font', description: 'Remove a font from the configuration file' },
|
|
11
|
+
{ cmd: 'import-font-sample', description: 'Import sample font to configuration file' },
|
|
12
|
+
{ divider: true },
|
|
13
|
+
{ cmd: 'add-colors', description: 'Add a new colors to the configuration file' },
|
|
14
|
+
{ cmd: 'remove-color', description: 'Remove a color from configuration file' },
|
|
15
|
+
{ cmd: 'import-color-pack', description: 'Import a color pack to configuration file' },
|
|
16
|
+
{ cmd: 'import-color', description: 'Import a specific color to configuration file' },
|
|
17
|
+
];
|
|
18
|
+
export function Help() {
|
|
19
|
+
console.log('\n🎨 Beathers CLI - Design System Builder\n');
|
|
20
|
+
const table = [
|
|
21
|
+
['Command', 'Description', 'Examples'],
|
|
22
|
+
['-------', '-----------', '--------'],
|
|
23
|
+
];
|
|
24
|
+
commands.forEach(({ cmd, description, divider }) => {
|
|
25
|
+
const example = `npx beathers ${cmd}`;
|
|
26
|
+
if (cmd && description)
|
|
27
|
+
table.push([cmd, description, example]);
|
|
28
|
+
if (cmd === '-v')
|
|
29
|
+
table.push(['', '', 'npx beathers --version']);
|
|
30
|
+
if (divider)
|
|
31
|
+
table.push(['', '', '']);
|
|
32
|
+
});
|
|
33
|
+
const maxLengths = table[0].map((_, colIndex) => Math.max(...table.map((row) => row[colIndex].length)));
|
|
34
|
+
table.forEach((row) => {
|
|
35
|
+
const formattedRow = row.map((cell, colIndex) => cell.padEnd(maxLengths[colIndex])).join(' ');
|
|
36
|
+
console.log(formattedRow);
|
|
37
|
+
});
|
|
38
|
+
console.log('\nFlags:');
|
|
39
|
+
console.log(" --local Build with user's custom output path (use with build command)");
|
|
40
|
+
console.log(' Example: npx beathers build --local');
|
|
41
|
+
console.log();
|
|
42
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Theme } from '@types';
|
|
2
|
+
export declare function promptUser(question: string): Promise<boolean>;
|
|
3
|
+
export declare function promptInput(question: string): Promise<string>;
|
|
4
|
+
export declare function promptSelection<T extends string>(question: string, options: T[]): Promise<T>;
|
|
5
|
+
export declare function findConfigFile(): Promise<string | null>;
|
|
6
|
+
export declare function loadConfig(filePath: string): Promise<Theme>;
|
|
7
|
+
export declare function saveConfig(filePath: string, config: Theme): Promise<void>;
|
|
8
|
+
export * from './build.js';
|
|
9
|
+
export * from './colors.js';
|
|
10
|
+
export * from './fonts.js';
|
|
11
|
+
export * from './help.js';
|
|
12
|
+
export * from './init.js';
|
|
13
|
+
export * from './version.js';
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
// Functions
|
|
5
|
+
export async function promptUser(question) {
|
|
6
|
+
const readline = await import('readline');
|
|
7
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
8
|
+
return new Promise((resolve) => {
|
|
9
|
+
rl.question(question, (answer) => {
|
|
10
|
+
rl.close();
|
|
11
|
+
resolve(answer.toLowerCase().startsWith('y'));
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export async function promptInput(question) {
|
|
16
|
+
const readline = await import('readline');
|
|
17
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
rl.question(question, (answer) => {
|
|
20
|
+
rl.close();
|
|
21
|
+
resolve(answer.trim());
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export async function promptSelection(question, options) {
|
|
26
|
+
const readline = await import('readline');
|
|
27
|
+
return new Promise((resolve) => {
|
|
28
|
+
const ask = () => {
|
|
29
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
30
|
+
console.log(question);
|
|
31
|
+
options.forEach((option, index) => console.log(` ${index + 1}. ${option}`));
|
|
32
|
+
rl.question('Enter your choice (number): ', (answer) => {
|
|
33
|
+
rl.close();
|
|
34
|
+
const choice = parseInt(answer.trim()) - 1;
|
|
35
|
+
if (choice >= 0 && choice < options.length)
|
|
36
|
+
resolve(options[choice]);
|
|
37
|
+
else {
|
|
38
|
+
console.log('❌ Invalid choice. Please try again.');
|
|
39
|
+
ask();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
ask();
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export async function findConfigFile() {
|
|
47
|
+
const userConfigFiles = ['beathers.configs.ts', 'beathers.configs.js', 'beathers.configs.json'];
|
|
48
|
+
for (const filename of userConfigFiles) {
|
|
49
|
+
const fullPath = path.join(process.cwd(), filename);
|
|
50
|
+
if (await fs.pathExists(fullPath))
|
|
51
|
+
return fullPath;
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
export async function loadConfig(filePath) {
|
|
56
|
+
const extension = path.extname(filePath);
|
|
57
|
+
if (extension === '.json') {
|
|
58
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
59
|
+
return JSON.parse(content);
|
|
60
|
+
}
|
|
61
|
+
else if (['.js', '.ts'].includes(extension)) {
|
|
62
|
+
let content = await fs.readFile(filePath, 'utf-8');
|
|
63
|
+
content = content.replace(/import.*from.*['"].*['"];?\n/g, '');
|
|
64
|
+
content = content.replace(/export default\s+/, '');
|
|
65
|
+
content = content.replace(/satisfies Theme\s*$/, '');
|
|
66
|
+
try {
|
|
67
|
+
const config = eval(`(${content})`);
|
|
68
|
+
return config;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
throw new Error(`Failed to parse config file: ${error}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
throw new Error(`Unsupported config file format: ${extension}`);
|
|
75
|
+
}
|
|
76
|
+
export async function saveConfig(filePath, config) {
|
|
77
|
+
const extension = path.extname(filePath);
|
|
78
|
+
if (extension === '.json')
|
|
79
|
+
await fs.writeFile(filePath, JSON.stringify(config, null, 2));
|
|
80
|
+
else if (extension === '.js') {
|
|
81
|
+
const content = `export default ${JSON.stringify(config, null, 2)}`;
|
|
82
|
+
await fs.writeFile(filePath, content);
|
|
83
|
+
}
|
|
84
|
+
else if (extension === '.ts') {
|
|
85
|
+
const content = `import type { Theme } from 'beathers'\n\nexport default ${JSON.stringify(config, null, 2)} satisfies Theme`;
|
|
86
|
+
await fs.writeFile(filePath, content);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Commands
|
|
90
|
+
export * from './build.js';
|
|
91
|
+
export * from './colors.js';
|
|
92
|
+
export * from './fonts.js';
|
|
93
|
+
export * from './help.js';
|
|
94
|
+
export * from './init.js';
|
|
95
|
+
export * from './version.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function Init(): Promise<void>;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { ReadDefaultValues } from '@helpers';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { promptSelection, promptUser } from '@commands';
|
|
7
|
+
async function getDefaultValues() {
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
const projectRoot = path.resolve(__dirname, '..', '..');
|
|
11
|
+
return (await ReadDefaultValues([
|
|
12
|
+
path.join(projectRoot, 'scss', 'settings', '_defaults.scss'),
|
|
13
|
+
path.join(projectRoot, 'scss', 'settings', '_configs.scss'),
|
|
14
|
+
path.join(projectRoot, 'scss', 'settings', '_index.scss'),
|
|
15
|
+
], [
|
|
16
|
+
'colors',
|
|
17
|
+
'fonts',
|
|
18
|
+
'fontMainPath',
|
|
19
|
+
'fontFormat',
|
|
20
|
+
'fontWeights',
|
|
21
|
+
'fontStyles',
|
|
22
|
+
'textTruncate',
|
|
23
|
+
'defaultFontFamilies',
|
|
24
|
+
'fontSizes',
|
|
25
|
+
'axisDivisions',
|
|
26
|
+
'breakpoints',
|
|
27
|
+
'wrappers',
|
|
28
|
+
'opacities',
|
|
29
|
+
'blurValues',
|
|
30
|
+
'insetValues',
|
|
31
|
+
'guttersValues',
|
|
32
|
+
'bordersValue',
|
|
33
|
+
'radiuses',
|
|
34
|
+
'useMediaQueries',
|
|
35
|
+
'useIcons',
|
|
36
|
+
'useFontFamilies',
|
|
37
|
+
'useFontSizes',
|
|
38
|
+
'useFontShapes',
|
|
39
|
+
'useTextAligns',
|
|
40
|
+
'useTextTruncate',
|
|
41
|
+
'useColors',
|
|
42
|
+
'useColorsOpacities',
|
|
43
|
+
'useColorsLightMode',
|
|
44
|
+
'useColorsDarkMode',
|
|
45
|
+
'useCurrentColors',
|
|
46
|
+
'useRootColors',
|
|
47
|
+
'useGrid',
|
|
48
|
+
'useFlex',
|
|
49
|
+
'useTransitions',
|
|
50
|
+
'useWrappers',
|
|
51
|
+
'useShadows',
|
|
52
|
+
'useDisplays',
|
|
53
|
+
'useOverflows',
|
|
54
|
+
'useOpacities',
|
|
55
|
+
'useBlur',
|
|
56
|
+
'useObjectFits',
|
|
57
|
+
'usePositions',
|
|
58
|
+
'useInsets',
|
|
59
|
+
'useSizes',
|
|
60
|
+
'useGutters',
|
|
61
|
+
'useBorders',
|
|
62
|
+
'useTextBorders',
|
|
63
|
+
'useRadius',
|
|
64
|
+
]));
|
|
65
|
+
}
|
|
66
|
+
export async function Init() {
|
|
67
|
+
const format = await promptSelection('\x1b[36m📁 Choose config format:\x1b[0m', ['json', 'js', 'ts']);
|
|
68
|
+
const formatMap = { json: 'beathers.configs.json', js: 'beathers.configs.js', ts: 'beathers.configs.ts' };
|
|
69
|
+
const fileName = formatMap[format];
|
|
70
|
+
const filePath = path.join(process.cwd(), fileName);
|
|
71
|
+
if (await fs.pathExists(filePath)) {
|
|
72
|
+
const shouldOverride = await promptUser(`\x1b[33m⚠️ ${fileName} already exists. Do you want to override it?\x1b[0m\n\x1b[32m[Y]\x1b[0m Yes \x1b[31m[N]\x1b[0m No: `);
|
|
73
|
+
if (!shouldOverride) {
|
|
74
|
+
console.log('❌ Operation canceled.');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const includeStarterValues = await promptUser('\x1b[36m📝 Would you like to include starter configuration values?\x1b[0m\n\x1b[32m[Y]\x1b[0m Yes \x1b[31m[N]\x1b[0m No: ');
|
|
79
|
+
const emptyTemplate = {
|
|
80
|
+
colors: {},
|
|
81
|
+
typography: {
|
|
82
|
+
defaultFontFamilies: [],
|
|
83
|
+
fontMainPath: '',
|
|
84
|
+
fontFormat: '',
|
|
85
|
+
fontWeights: [],
|
|
86
|
+
fontStyles: [],
|
|
87
|
+
fontSizes: {},
|
|
88
|
+
textTruncate: 0,
|
|
89
|
+
fonts: {},
|
|
90
|
+
},
|
|
91
|
+
settings: {
|
|
92
|
+
axisDivisions: 0,
|
|
93
|
+
opacities: [],
|
|
94
|
+
blurValues: [],
|
|
95
|
+
insetValues: [],
|
|
96
|
+
bordersValue: 0,
|
|
97
|
+
radiuses: [],
|
|
98
|
+
breakpoints: {},
|
|
99
|
+
wrappers: {},
|
|
100
|
+
guttersValues: {},
|
|
101
|
+
},
|
|
102
|
+
roles: {},
|
|
103
|
+
};
|
|
104
|
+
let content = '';
|
|
105
|
+
if (format === 'json') {
|
|
106
|
+
const data = includeStarterValues ? await getDefaultValues() : emptyTemplate;
|
|
107
|
+
content = JSON.stringify(data, null, 2);
|
|
108
|
+
}
|
|
109
|
+
else if (format === 'js') {
|
|
110
|
+
if (includeStarterValues) {
|
|
111
|
+
const defaultValues = await getDefaultValues();
|
|
112
|
+
content = `export default ${JSON.stringify(defaultValues, null, 2)}`;
|
|
113
|
+
}
|
|
114
|
+
else
|
|
115
|
+
content = `export default ${JSON.stringify(emptyTemplate, null, 2)}`;
|
|
116
|
+
}
|
|
117
|
+
else if (format === 'ts') {
|
|
118
|
+
const importLine = "import type { Theme } from 'beathers'\n\n";
|
|
119
|
+
if (includeStarterValues) {
|
|
120
|
+
const defaultValues = await getDefaultValues();
|
|
121
|
+
content = `${importLine}export default ${JSON.stringify(defaultValues, null, 2)} satisfies Theme`;
|
|
122
|
+
}
|
|
123
|
+
else
|
|
124
|
+
content = `${importLine}export default ${JSON.stringify(emptyTemplate, null, 2)} satisfies Theme`;
|
|
125
|
+
}
|
|
126
|
+
await fs.writeFile(filePath, content);
|
|
127
|
+
const starterText = includeStarterValues ? ' with starter values' : '';
|
|
128
|
+
console.log(`✅ Successfully created \x1b[32m${fileName}\x1b[0m${starterText}`);
|
|
129
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare function Commands(args: any): Record<string, () => void | Promise<void>>;
|
|
2
|
+
export type CommandKey = '--help' | '-v' | '--version' | 'init' | 'build' | 'add-font' | 'remove-font' | 'import-font-sample' | 'add-colors' | 'remove-color' | 'import-color-pack' | 'import-color';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { AddColors, AddFont, Build, Help, ImportColor, ImportColorPack, ImportFont, Init, RemoveColor, RemoveFont, Version, } from '@commands';
|
|
3
|
+
const commands = {
|
|
4
|
+
'--help': () => Help(),
|
|
5
|
+
'-v': () => Version(),
|
|
6
|
+
'--version': () => Version(),
|
|
7
|
+
init: async () => await Init(),
|
|
8
|
+
build: async () => await Build(),
|
|
9
|
+
'--local': async () => await Build(),
|
|
10
|
+
'add-font': async () => await AddFont(),
|
|
11
|
+
'remove-font': async () => await RemoveFont(),
|
|
12
|
+
'import-font-sample': async () => await ImportFont(),
|
|
13
|
+
'add-colors': async () => await AddColors(),
|
|
14
|
+
'remove-color': async () => await RemoveColor(),
|
|
15
|
+
'import-color-pack': async () => await ImportColorPack(),
|
|
16
|
+
'import-color': async () => await ImportColor(),
|
|
17
|
+
};
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
+
export function Commands(args) {
|
|
20
|
+
const list = {
|
|
21
|
+
...commands,
|
|
22
|
+
default: () => {
|
|
23
|
+
console.error(`❌ Command not found: "${args[0]}"`);
|
|
24
|
+
console.log('💡 Run "\x1b[34mbeathers --help\x1b[0m" to see all available commands.');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
return list;
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function Version(): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
export function Version() {
|
|
5
|
+
const packagePath = path.join(process.cwd(), 'package.json');
|
|
6
|
+
try {
|
|
7
|
+
const packageInfo = fs.readJsonSync(packagePath);
|
|
8
|
+
console.log(`📦 \x1b[34mbeathers\x1b[0m v${packageInfo.version}`);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
console.log('📦 \x1b[34mbeathers\x1b[0m CLI');
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Theme } from '
|
|
1
|
+
import { Theme } from '@types';
|
|
2
2
|
export declare function BuildScssVariables(theme: Theme): string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function BuildScssVariables(theme) {
|
|
2
2
|
const { colors, roles, settings, typography } = theme;
|
|
3
|
-
let scss = '// Generated by
|
|
3
|
+
let scss = '// Generated by Beathers builder\n // Do not edit this file directly\n\n';
|
|
4
4
|
if (colors) {
|
|
5
5
|
scss += '\n\n// --- Colors ---\n';
|
|
6
6
|
scss += '$colors: (\n';
|
|
@@ -32,8 +32,8 @@ export function BuildScssVariables(theme) {
|
|
|
32
32
|
}
|
|
33
33
|
scss += ');\n';
|
|
34
34
|
}
|
|
35
|
-
if (typography?.textTruncate)
|
|
36
|
-
scss += `$textTruncate: ${typography.textTruncate};\n`;
|
|
35
|
+
if (typography?.textTruncate?.length)
|
|
36
|
+
scss += `$textTruncate: ${typography.textTruncate.join(', ')};\n`;
|
|
37
37
|
if (typography?.fonts) {
|
|
38
38
|
scss += '$fonts: (\n';
|
|
39
39
|
for (const [name, font] of Object.entries(typography.fonts)) {
|
|
@@ -76,7 +76,7 @@ export function BuildScssVariables(theme) {
|
|
|
76
76
|
if (settings?.insetValues)
|
|
77
77
|
scss += `$insetValues: (${settings.insetValues.join(', ')});\n`;
|
|
78
78
|
if (settings?.bordersValue)
|
|
79
|
-
scss += `$bordersValue: ${settings.bordersValue};\n`;
|
|
79
|
+
scss += `$bordersValue: (${settings.bordersValue.join(', ')});\n`;
|
|
80
80
|
if (settings?.radiuses)
|
|
81
81
|
scss += `$radiuses: (${settings.radiuses.join(', ')});\n`;
|
|
82
82
|
if (settings?.breakpoints) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Theme } from '
|
|
1
|
+
import { Theme } from '@types';
|
|
2
2
|
export declare function LoadUserConfigs(projectPath?: string): Promise<Theme | null>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Theme } from '
|
|
1
|
+
import { Theme } from '@types';
|
|
2
2
|
export declare function DeepMerge(defaults: Partial<Theme>, configs: Partial<Theme> | null): Theme;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Theme } from '
|
|
1
|
+
import { Theme } from '@types';
|
|
2
2
|
export declare function ReadDefaultValues(files: string[], VariableNames: string[]): Promise<Partial<Theme>>;
|
|
@@ -53,8 +53,10 @@ function buildColors(value) {
|
|
|
53
53
|
const raw = value
|
|
54
54
|
.replace(/\(/g, '{')
|
|
55
55
|
.replace(/\)/g, '}')
|
|
56
|
+
.replace(/'/g, '"')
|
|
56
57
|
.replace(/#([0-9a-fA-F]{3,6})/g, '"#$1"')
|
|
57
|
-
.replace(/,\s*}/g, '}')
|
|
58
|
+
.replace(/,\s*}/g, '}')
|
|
59
|
+
.replace(/\n\s*/g, '');
|
|
58
60
|
const parsed = JSON.parse(raw);
|
|
59
61
|
return parsed;
|
|
60
62
|
}
|
|
@@ -95,14 +97,16 @@ export async function ReadDefaultValues(files, VariableNames) {
|
|
|
95
97
|
else if ([
|
|
96
98
|
'fontWeights',
|
|
97
99
|
'fontStyles',
|
|
100
|
+
'textTruncate',
|
|
98
101
|
'opacities',
|
|
99
102
|
'blurValues',
|
|
100
103
|
'radiuses',
|
|
101
104
|
'defaultFontFamilies',
|
|
102
105
|
'insetValues',
|
|
106
|
+
'bordersValue',
|
|
103
107
|
].includes(name))
|
|
104
108
|
result = buildArray(value);
|
|
105
|
-
else if (['
|
|
109
|
+
else if (['axisDivisions'].includes(name))
|
|
106
110
|
result = cleanNumber(value);
|
|
107
111
|
else
|
|
108
112
|
result = cleanString(value);
|
package/dist/scripts/types.d.ts
CHANGED
|
@@ -1,52 +1,89 @@
|
|
|
1
|
+
/** CSS size unit values supporting px, rem, em, viewport units, and percentages */
|
|
1
2
|
type SizeUnit = `${number}px` | `${number}rem` | `${number}em` | `${number}vw` | `${number}vh` | `${number}%`;
|
|
3
|
+
/** Color configuration object with optional light and dark theme hex values */
|
|
2
4
|
type ColorType = Record<string, {
|
|
3
|
-
light
|
|
4
|
-
dark
|
|
5
|
+
light?: `#${string}`;
|
|
6
|
+
dark?: `#${string}`;
|
|
5
7
|
}>;
|
|
8
|
+
/** Available font weight values from thin to black */
|
|
6
9
|
type FontWeight = 'thin' | 'extra-light' | 'light' | 'regular' | 'medium' | 'semibold' | 'bold' | 'extra-bold' | 'black';
|
|
10
|
+
/** Font style options for normal, italic, or oblique text */
|
|
7
11
|
type FontStyle = 'normal' | 'italic' | 'oblique';
|
|
8
12
|
interface FontVariant {
|
|
13
|
+
/** Display name for the font variant */
|
|
9
14
|
title: string;
|
|
15
|
+
/** Unicode range for the font variant */
|
|
10
16
|
unicode?: string;
|
|
17
|
+
/** Font file format. */
|
|
11
18
|
format?: 'woff' | 'woff2';
|
|
19
|
+
/** Whether the font is locally installed. @default true */
|
|
12
20
|
isLocal?: boolean;
|
|
21
|
+
/** Remote URL for downloading the font */
|
|
13
22
|
url?: `https://${string}` | `http://${string}`;
|
|
14
23
|
}
|
|
24
|
+
/** Font configuration with weights, styles, and variants */
|
|
15
25
|
type FontType = {
|
|
26
|
+
/** Available font weights for this font family */
|
|
16
27
|
weights?: FontWeight[];
|
|
28
|
+
/** Available font styles for this font family */
|
|
17
29
|
styles?: FontStyle[];
|
|
30
|
+
/** Named font variants with specific configurations */
|
|
18
31
|
variants?: Record<string, FontVariant>;
|
|
19
32
|
};
|
|
20
33
|
interface Typography {
|
|
34
|
+
/** Default font families to use as fallbacks */
|
|
21
35
|
defaultFontFamilies?: string[];
|
|
36
|
+
/** Base path for font files */
|
|
22
37
|
fontMainPath?: string;
|
|
38
|
+
/** Default font format for all fonts. */
|
|
23
39
|
fontFormat?: 'woff' | 'woff2';
|
|
40
|
+
/** Global font weights available across all fonts */
|
|
24
41
|
fontWeights?: FontWeight[];
|
|
42
|
+
/** Global font styles available across all fonts */
|
|
25
43
|
fontStyles?: FontStyle[];
|
|
44
|
+
/** Named font sizes mapped to CSS size units */
|
|
26
45
|
fontSizes?: Record<string, SizeUnit>;
|
|
27
|
-
|
|
46
|
+
/** Line counts for text truncation utilities */
|
|
47
|
+
textTruncate?: number[];
|
|
48
|
+
/** Font family configurations */
|
|
28
49
|
fonts?: Record<string, FontType>;
|
|
29
50
|
}
|
|
30
51
|
interface Settings {
|
|
52
|
+
/** Number of divisions for grid axis calculations. @default 12 */
|
|
31
53
|
axisDivisions?: number;
|
|
54
|
+
/** Opacity values for transparency utilities (0-100 range) */
|
|
32
55
|
opacities?: number[];
|
|
56
|
+
/** Blur values in pixels for filter utilities */
|
|
33
57
|
blurValues?: number[];
|
|
58
|
+
/** Inset values for positioning utilities */
|
|
34
59
|
insetValues?: number[];
|
|
35
|
-
|
|
60
|
+
/** Border width values in pixels */
|
|
61
|
+
bordersValue?: number[];
|
|
62
|
+
/** Border radius values in pixels */
|
|
36
63
|
radiuses?: number[];
|
|
64
|
+
/** Responsive breakpoints for media queries */
|
|
37
65
|
breakpoints?: Record<'null' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl', 0 | SizeUnit>;
|
|
66
|
+
/** Container wrapper configurations for different breakpoints */
|
|
38
67
|
wrappers?: Record<'null' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl', {
|
|
39
68
|
width: SizeUnit;
|
|
40
69
|
padding?: SizeUnit;
|
|
41
70
|
}>;
|
|
71
|
+
/** Gutter values for spacing utilities */
|
|
42
72
|
guttersValues?: Record<'auto' | number, 'auto' | SizeUnit>;
|
|
43
73
|
}
|
|
74
|
+
/** Available feature keys for enabling/disabling CSS utilities */
|
|
44
75
|
type RoleKeys = 'useMediaQueries' | 'useIcons' | 'useFontFamilies' | 'useFontSizes' | 'useFontShapes' | 'useTextAligns' | 'useTextTruncate' | 'useColors' | 'useColorsOpacities' | 'useColorsLightMode' | 'useColorsDarkMode' | 'useCurrentColors' | 'useRootColors' | 'useGrid' | 'useFlex' | 'useTransitions' | 'useWrappers' | 'useShadows' | 'useDisplays' | 'useOverflows' | 'useOpacities' | 'useBlur' | 'useObjectFits' | 'usePositions' | 'useInsets' | 'useSizes' | 'useGutters' | 'useBorders' | 'useTextBorders' | 'useRadius';
|
|
76
|
+
/** Feature toggles for enabling/disabling CSS utility generation. @default all true */
|
|
45
77
|
type Roles = Partial<Record<RoleKeys, boolean>>;
|
|
78
|
+
/** Main theme configuration object containing all design system settings */
|
|
46
79
|
interface Theme {
|
|
80
|
+
/** Color palette definitions with light/dark theme support */
|
|
47
81
|
colors?: ColorType;
|
|
82
|
+
/** Typography settings including fonts, sizes, and weights */
|
|
48
83
|
typography?: Typography;
|
|
84
|
+
/** Framework settings for grid, spacing, and responsive behavior */
|
|
49
85
|
settings?: Settings;
|
|
86
|
+
/** Feature flags for controlling which CSS utilities are generated */
|
|
50
87
|
roles?: Roles;
|
|
51
88
|
}
|
|
52
89
|
export type { SizeUnit, ColorType, FontWeight, FontStyle, FontVariant, FontType, Typography, Settings, RoleKeys, Roles, Theme, };
|
package/dist/scripts/types.js
CHANGED