jasmincss 1.0.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/README.md +524 -0
- package/bin/jasmin.js +45 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +14568 -0
- package/dist/index.mjs +14524 -0
- package/dist/jasmin.css +63308 -0
- package/dist/jasmin.min.css +1 -0
- package/dist/plugins/nextjs.js +14777 -0
- package/dist/plugins/nextjs.mjs +14747 -0
- package/dist/plugins/vite.js +14889 -0
- package/dist/plugins/vite.mjs +14860 -0
- package/package.json +101 -0
- package/src/cli/add.js +83 -0
- package/src/cli/init.js +210 -0
- package/src/cli/run.js +142 -0
- package/src/components/accordion.js +309 -0
- package/src/components/alerts.js +357 -0
- package/src/components/avatars.js +331 -0
- package/src/components/badges.js +353 -0
- package/src/components/buttons.js +412 -0
- package/src/components/cards.js +342 -0
- package/src/components/carousel.js +495 -0
- package/src/components/chips.js +440 -0
- package/src/components/command-palette.js +434 -0
- package/src/components/datepicker.js +517 -0
- package/src/components/dropdown.js +411 -0
- package/src/components/forms.js +516 -0
- package/src/components/index.js +81 -0
- package/src/components/modals.js +349 -0
- package/src/components/navigation.js +463 -0
- package/src/components/offcanvas.js +390 -0
- package/src/components/popover.js +427 -0
- package/src/components/progress.js +396 -0
- package/src/components/rating.js +394 -0
- package/src/components/skeleton.js +408 -0
- package/src/components/spinner.js +453 -0
- package/src/components/stepper.js +389 -0
- package/src/components/tables.js +304 -0
- package/src/components/timeline.js +452 -0
- package/src/components/timepicker.js +529 -0
- package/src/components/tooltips.js +345 -0
- package/src/components/upload.js +490 -0
- package/src/config/defaults.js +263 -0
- package/src/config/loader.js +109 -0
- package/src/core/base.js +241 -0
- package/src/core/compiler.js +135 -0
- package/src/core/utilities/accessibility.js +290 -0
- package/src/core/utilities/animations.js +205 -0
- package/src/core/utilities/background.js +109 -0
- package/src/core/utilities/colors.js +234 -0
- package/src/core/utilities/columns.js +161 -0
- package/src/core/utilities/effects.js +261 -0
- package/src/core/utilities/filters.js +135 -0
- package/src/core/utilities/icons.js +806 -0
- package/src/core/utilities/index.js +239 -0
- package/src/core/utilities/layout.js +321 -0
- package/src/core/utilities/scroll.js +205 -0
- package/src/core/utilities/spacing.js +120 -0
- package/src/core/utilities/svg.js +191 -0
- package/src/core/utilities/transforms.js +116 -0
- package/src/core/utilities/typography.js +188 -0
- package/src/index.js +7 -0
- package/src/js/components/accordion.js +154 -0
- package/src/js/components/alert.js +198 -0
- package/src/js/components/carousel.js +226 -0
- package/src/js/components/dropdown.js +166 -0
- package/src/js/components/modal.js +169 -0
- package/src/js/components/offcanvas.js +175 -0
- package/src/js/components/popover.js +221 -0
- package/src/js/components/tabs.js +163 -0
- package/src/js/components/tooltip.js +200 -0
- package/src/js/index.js +79 -0
- package/src/js/types/config.d.ts +228 -0
- package/src/js/types/index.d.ts +439 -0
- package/src/plugins/nextjs.js +100 -0
- package/src/plugins/vite.js +133 -0
package/package.json
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jasmincss",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A modern, future-proof CSS framework with design philosophy",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.mjs",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"jasmin": "./bin/jasmin.js"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/index.mjs",
|
|
15
|
+
"require": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./js": {
|
|
19
|
+
"import": "./src/js/index.js",
|
|
20
|
+
"types": "./src/js/types/index.d.ts"
|
|
21
|
+
},
|
|
22
|
+
"./config": {
|
|
23
|
+
"types": "./src/js/types/config.d.ts"
|
|
24
|
+
},
|
|
25
|
+
"./css": "./dist/jasmin.css",
|
|
26
|
+
"./css/min": "./dist/jasmin.min.css",
|
|
27
|
+
"./dist/jasmin.css": "./dist/jasmin.css",
|
|
28
|
+
"./dist/jasmin.min.css": "./dist/jasmin.min.css",
|
|
29
|
+
"./plugins/next": "./dist/plugin/nextjs.js",
|
|
30
|
+
"./plugins/vite": "./dist/plugin/vite.js",
|
|
31
|
+
"./plugin/nextjs": "./dist/plugin/nextjs.js",
|
|
32
|
+
"./plugin/vite": "./dist/plugin/vite.js"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"bin",
|
|
37
|
+
"src"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "node scripts/build.js",
|
|
41
|
+
"build:css": "node scripts/build-css.js",
|
|
42
|
+
"dev": "node scripts/dev.js",
|
|
43
|
+
"test": "node --test tests/**/*.test.js",
|
|
44
|
+
"test:browser": "npx playwright test --config=tests/browser/playwright.config.js",
|
|
45
|
+
"test:a11y": "npx playwright test tests/accessibility/",
|
|
46
|
+
"test:perf": "node tests/performance/benchmark.js",
|
|
47
|
+
"test:all": "npm run test && npm run test:browser && npm run test:a11y",
|
|
48
|
+
"docs:dev": "vitepress dev docs",
|
|
49
|
+
"docs:build": "vitepress build docs",
|
|
50
|
+
"docs:preview": "vitepress preview docs",
|
|
51
|
+
"prepublishOnly": "npm run build"
|
|
52
|
+
},
|
|
53
|
+
"keywords": [
|
|
54
|
+
"css",
|
|
55
|
+
"framework",
|
|
56
|
+
"utility-first",
|
|
57
|
+
"components",
|
|
58
|
+
"tailwind",
|
|
59
|
+
"design-system",
|
|
60
|
+
"jasmin",
|
|
61
|
+
"nextjs",
|
|
62
|
+
"react",
|
|
63
|
+
"vue"
|
|
64
|
+
],
|
|
65
|
+
"author": "",
|
|
66
|
+
"license": "MIT",
|
|
67
|
+
"repository": {
|
|
68
|
+
"type": "git",
|
|
69
|
+
"url": "https://github.com/jasmaine/JasminCSS"
|
|
70
|
+
},
|
|
71
|
+
"engines": {
|
|
72
|
+
"node": ">=18.0.0"
|
|
73
|
+
},
|
|
74
|
+
"dependencies": {
|
|
75
|
+
"chokidar": "^3.5.3",
|
|
76
|
+
"commander": "^11.1.0",
|
|
77
|
+
"cssnano": "^6.0.2",
|
|
78
|
+
"fast-glob": "^3.3.2",
|
|
79
|
+
"inquirer": "^9.2.12",
|
|
80
|
+
"picocolors": "^1.0.0",
|
|
81
|
+
"postcss": "^8.4.32"
|
|
82
|
+
},
|
|
83
|
+
"devDependencies": {
|
|
84
|
+
"@playwright/test": "^1.40.0",
|
|
85
|
+
"esbuild": "^0.19.10",
|
|
86
|
+
"serve": "^14.2.0",
|
|
87
|
+
"vitepress": "^1.6.4"
|
|
88
|
+
},
|
|
89
|
+
"peerDependencies": {
|
|
90
|
+
"next": ">=13.0.0",
|
|
91
|
+
"vite": ">=5.0.0"
|
|
92
|
+
},
|
|
93
|
+
"peerDependenciesMeta": {
|
|
94
|
+
"next": {
|
|
95
|
+
"optional": true
|
|
96
|
+
},
|
|
97
|
+
"vite": {
|
|
98
|
+
"optional": true
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
package/src/cli/add.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import pc from 'picocolors';
|
|
4
|
+
import { components } from '../components/index.js';
|
|
5
|
+
|
|
6
|
+
const availableComponents = {
|
|
7
|
+
buttons: 'Interactive button styles with variants',
|
|
8
|
+
cards: 'Card containers with various layouts',
|
|
9
|
+
forms: 'Form inputs, selects, checkboxes, radios',
|
|
10
|
+
navigation: 'Navbars, sidebars, breadcrumbs',
|
|
11
|
+
modals: 'Modal dialogs and overlays',
|
|
12
|
+
tables: 'Data tables with sorting indicators',
|
|
13
|
+
alerts: 'Alert and notification banners',
|
|
14
|
+
badges: 'Status badges and tags',
|
|
15
|
+
avatars: 'User avatar components',
|
|
16
|
+
tooltips: 'Hover tooltips and popovers',
|
|
17
|
+
progress: 'Progress bars and spinners',
|
|
18
|
+
skeleton: 'Loading skeleton placeholders',
|
|
19
|
+
accordion: 'Collapsible accordion panels',
|
|
20
|
+
tabs: 'Tab navigation components',
|
|
21
|
+
dropdown: 'Dropdown menus',
|
|
22
|
+
pagination: 'Page navigation',
|
|
23
|
+
breadcrumb: 'Breadcrumb navigation',
|
|
24
|
+
toast: 'Toast notifications',
|
|
25
|
+
drawer: 'Side drawer panels',
|
|
26
|
+
hero: 'Hero section layouts'
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export async function addCommand(component, options) {
|
|
30
|
+
if (options.list || component === 'list') {
|
|
31
|
+
console.log(pc.cyan('\n🌸 Available JasminCSS Components\n'));
|
|
32
|
+
|
|
33
|
+
Object.entries(availableComponents).forEach(([name, description]) => {
|
|
34
|
+
console.log(pc.white(` ${name.padEnd(15)}`), pc.dim(description));
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
console.log(pc.dim('\nUsage: jasmin add <component>\n'));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!availableComponents[component]) {
|
|
42
|
+
console.log(pc.red(`Unknown component: ${component}`));
|
|
43
|
+
console.log(pc.dim('Run "jasmin add --list" to see available components'));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const cwd = process.cwd();
|
|
48
|
+
const configPath = path.join(cwd, 'jasmin.config.js');
|
|
49
|
+
|
|
50
|
+
if (!fs.existsSync(configPath)) {
|
|
51
|
+
console.log(pc.yellow('No jasmin.config.js found. Run "jasmin init" first.'));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Read and update config
|
|
56
|
+
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
57
|
+
|
|
58
|
+
// Simple regex to find and update components array
|
|
59
|
+
const componentRegex = /components:\s*\[([\s\S]*?)\]/;
|
|
60
|
+
const match = configContent.match(componentRegex);
|
|
61
|
+
|
|
62
|
+
if (match) {
|
|
63
|
+
const existingComponents = match[1]
|
|
64
|
+
.split(',')
|
|
65
|
+
.map(c => c.trim().replace(/['"]/g, ''))
|
|
66
|
+
.filter(Boolean);
|
|
67
|
+
|
|
68
|
+
if (existingComponents.includes(component)) {
|
|
69
|
+
console.log(pc.yellow(`Component "${component}" is already included.`));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
existingComponents.push(component);
|
|
74
|
+
const newComponentsArray = existingComponents.map(c => `'${c}'`).join(', ');
|
|
75
|
+
const newConfigContent = configContent.replace(componentRegex, `components: [${newComponentsArray}]`);
|
|
76
|
+
|
|
77
|
+
fs.writeFileSync(configPath, newConfigContent);
|
|
78
|
+
console.log(pc.green(`✓ Added "${component}" component to jasmin.config.js`));
|
|
79
|
+
console.log(pc.dim('Run "jasmin run build" to regenerate CSS'));
|
|
80
|
+
} else {
|
|
81
|
+
console.log(pc.yellow('Could not update config. Please add the component manually.'));
|
|
82
|
+
}
|
|
83
|
+
}
|
package/src/cli/init.js
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import pc from 'picocolors';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
import { defaultConfig, templates } from '../config/defaults.js';
|
|
6
|
+
|
|
7
|
+
export async function initCommand(options) {
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
const configPath = path.join(cwd, 'jasmin.config.js');
|
|
10
|
+
|
|
11
|
+
console.log(pc.cyan('🌸 Welcome to JasminCSS Setup\n'));
|
|
12
|
+
|
|
13
|
+
if (fs.existsSync(configPath) && !options.yes) {
|
|
14
|
+
const { overwrite } = await inquirer.prompt([{
|
|
15
|
+
type: 'confirm',
|
|
16
|
+
name: 'overwrite',
|
|
17
|
+
message: 'jasmin.config.js already exists. Overwrite?',
|
|
18
|
+
default: false
|
|
19
|
+
}]);
|
|
20
|
+
|
|
21
|
+
if (!overwrite) {
|
|
22
|
+
console.log(pc.yellow('Setup cancelled.'));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let config = { ...defaultConfig };
|
|
28
|
+
|
|
29
|
+
if (options.yes) {
|
|
30
|
+
// Use defaults
|
|
31
|
+
console.log(pc.dim('Using default configuration...'));
|
|
32
|
+
} else if (options.template && templates[options.template]) {
|
|
33
|
+
// Use template
|
|
34
|
+
config = { ...config, ...templates[options.template] };
|
|
35
|
+
console.log(pc.green(`Using ${options.template} template`));
|
|
36
|
+
} else {
|
|
37
|
+
// Interactive setup
|
|
38
|
+
const answers = await inquirer.prompt([
|
|
39
|
+
{
|
|
40
|
+
type: 'input',
|
|
41
|
+
name: 'projectName',
|
|
42
|
+
message: 'Project name:',
|
|
43
|
+
default: path.basename(cwd)
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: 'list',
|
|
47
|
+
name: 'template',
|
|
48
|
+
message: 'Choose a design template:',
|
|
49
|
+
choices: [
|
|
50
|
+
{ name: 'Futuristic - Bold, modern, tech-forward', value: 'futuristic' },
|
|
51
|
+
{ name: 'Minimal - Clean, elegant, understated', value: 'minimal' },
|
|
52
|
+
{ name: 'Corporate - Professional, trustworthy', value: 'corporate' },
|
|
53
|
+
{ name: 'Creative - Vibrant, expressive, artistic', value: 'creative' },
|
|
54
|
+
{ name: 'Custom - Define your own', value: 'custom' }
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
if (answers.template === 'custom') {
|
|
60
|
+
const brandingAnswers = await inquirer.prompt([
|
|
61
|
+
{
|
|
62
|
+
type: 'input',
|
|
63
|
+
name: 'primaryColor',
|
|
64
|
+
message: 'Primary brand color (hex):',
|
|
65
|
+
default: '#6366f1',
|
|
66
|
+
validate: (input) => /^#[0-9A-Fa-f]{6}$/.test(input) || 'Please enter a valid hex color'
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
type: 'input',
|
|
70
|
+
name: 'secondaryColor',
|
|
71
|
+
message: 'Secondary brand color (hex):',
|
|
72
|
+
default: '#ec4899',
|
|
73
|
+
validate: (input) => /^#[0-9A-Fa-f]{6}$/.test(input) || 'Please enter a valid hex color'
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
type: 'input',
|
|
77
|
+
name: 'accentColor',
|
|
78
|
+
message: 'Accent color (hex):',
|
|
79
|
+
default: '#14b8a6',
|
|
80
|
+
validate: (input) => /^#[0-9A-Fa-f]{6}$/.test(input) || 'Please enter a valid hex color'
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
type: 'list',
|
|
84
|
+
name: 'fontFamily',
|
|
85
|
+
message: 'Primary font family:',
|
|
86
|
+
choices: [
|
|
87
|
+
{ name: 'Inter (Modern sans-serif)', value: 'Inter' },
|
|
88
|
+
{ name: 'Space Grotesk (Futuristic)', value: 'Space Grotesk' },
|
|
89
|
+
{ name: 'DM Sans (Friendly)', value: 'DM Sans' },
|
|
90
|
+
{ name: 'Outfit (Geometric)', value: 'Outfit' },
|
|
91
|
+
{ name: 'System fonts', value: 'system-ui' }
|
|
92
|
+
]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
type: 'list',
|
|
96
|
+
name: 'borderRadius',
|
|
97
|
+
message: 'Border radius style:',
|
|
98
|
+
choices: [
|
|
99
|
+
{ name: 'Sharp (0px)', value: '0' },
|
|
100
|
+
{ name: 'Subtle (4px)', value: '0.25rem' },
|
|
101
|
+
{ name: 'Rounded (8px)', value: '0.5rem' },
|
|
102
|
+
{ name: 'Pill (16px)', value: '1rem' },
|
|
103
|
+
{ name: 'Full (9999px)', value: '9999px' }
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
type: 'confirm',
|
|
108
|
+
name: 'darkMode',
|
|
109
|
+
message: 'Include dark mode support?',
|
|
110
|
+
default: true
|
|
111
|
+
}
|
|
112
|
+
]);
|
|
113
|
+
|
|
114
|
+
config.branding = {
|
|
115
|
+
...config.branding,
|
|
116
|
+
colors: {
|
|
117
|
+
primary: brandingAnswers.primaryColor,
|
|
118
|
+
secondary: brandingAnswers.secondaryColor,
|
|
119
|
+
accent: brandingAnswers.accentColor
|
|
120
|
+
},
|
|
121
|
+
typography: {
|
|
122
|
+
fontFamily: brandingAnswers.fontFamily
|
|
123
|
+
},
|
|
124
|
+
borderRadius: {
|
|
125
|
+
default: brandingAnswers.borderRadius
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
config.darkMode = brandingAnswers.darkMode;
|
|
129
|
+
} else {
|
|
130
|
+
config = { ...config, ...templates[answers.template] };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
config.projectName = answers.projectName;
|
|
134
|
+
|
|
135
|
+
// Component selection
|
|
136
|
+
const componentAnswers = await inquirer.prompt([
|
|
137
|
+
{
|
|
138
|
+
type: 'checkbox',
|
|
139
|
+
name: 'components',
|
|
140
|
+
message: 'Select components to include:',
|
|
141
|
+
choices: [
|
|
142
|
+
{ name: 'Buttons', value: 'buttons', checked: true },
|
|
143
|
+
{ name: 'Cards', value: 'cards', checked: true },
|
|
144
|
+
{ name: 'Forms', value: 'forms', checked: true },
|
|
145
|
+
{ name: 'Navigation', value: 'navigation', checked: true },
|
|
146
|
+
{ name: 'Modals', value: 'modals', checked: false },
|
|
147
|
+
{ name: 'Tables', value: 'tables', checked: false },
|
|
148
|
+
{ name: 'Alerts', value: 'alerts', checked: true },
|
|
149
|
+
{ name: 'Badges', value: 'badges', checked: true },
|
|
150
|
+
{ name: 'Avatars', value: 'avatars', checked: false },
|
|
151
|
+
{ name: 'Tooltips', value: 'tooltips', checked: false },
|
|
152
|
+
{ name: 'Progress', value: 'progress', checked: false },
|
|
153
|
+
{ name: 'Skeleton', value: 'skeleton', checked: false }
|
|
154
|
+
]
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
type: 'checkbox',
|
|
158
|
+
name: 'utilities',
|
|
159
|
+
message: 'Select utility modules:',
|
|
160
|
+
choices: [
|
|
161
|
+
{ name: 'Layout (flex, grid, container)', value: 'layout', checked: true },
|
|
162
|
+
{ name: 'Spacing (margin, padding)', value: 'spacing', checked: true },
|
|
163
|
+
{ name: 'Typography', value: 'typography', checked: true },
|
|
164
|
+
{ name: 'Colors', value: 'colors', checked: true },
|
|
165
|
+
{ name: 'Effects (shadows, blur)', value: 'effects', checked: true },
|
|
166
|
+
{ name: 'Animations', value: 'animations', checked: true },
|
|
167
|
+
{ name: 'Transforms', value: 'transforms', checked: false },
|
|
168
|
+
{ name: 'Filters', value: 'filters', checked: false }
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
]);
|
|
172
|
+
|
|
173
|
+
config.components = componentAnswers.components;
|
|
174
|
+
config.utilities = componentAnswers.utilities;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Generate config file
|
|
178
|
+
const configContent = `/** @type {import('jasmincss').JasminConfig} */
|
|
179
|
+
export default ${JSON.stringify(config, null, 2)};
|
|
180
|
+
`;
|
|
181
|
+
|
|
182
|
+
fs.writeFileSync(configPath, configContent);
|
|
183
|
+
console.log(pc.green('\n✓ Created jasmin.config.js'));
|
|
184
|
+
|
|
185
|
+
// Create CSS entry point
|
|
186
|
+
const cssDir = path.join(cwd, 'styles');
|
|
187
|
+
if (!fs.existsSync(cssDir)) {
|
|
188
|
+
fs.mkdirSync(cssDir, { recursive: true });
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const mainCssPath = path.join(cssDir, 'jasmin.css');
|
|
192
|
+
const mainCssContent = `/* JasminCSS - Main Entry Point */
|
|
193
|
+
@import 'jasmincss/css';
|
|
194
|
+
|
|
195
|
+
/* Your custom styles below */
|
|
196
|
+
`;
|
|
197
|
+
|
|
198
|
+
fs.writeFileSync(mainCssPath, mainCssContent);
|
|
199
|
+
console.log(pc.green('✓ Created styles/jasmin.css'));
|
|
200
|
+
|
|
201
|
+
// Print next steps
|
|
202
|
+
console.log(pc.cyan('\n📦 Next steps:\n'));
|
|
203
|
+
console.log(pc.white(' 1. Run'), pc.yellow('jasmin run dev'), pc.white('to compile the full library'));
|
|
204
|
+
console.log(pc.white(' 2. Run'), pc.yellow('jasmin run build'), pc.white('for production (tree-shaken)'));
|
|
205
|
+
console.log(pc.white(' 3. Run'), pc.yellow('jasmin run watch'), pc.white('for development with hot reload'));
|
|
206
|
+
console.log(pc.white('\n Import in your project:'));
|
|
207
|
+
console.log(pc.dim(' import \'./dist/jasmin.min.css\';'));
|
|
208
|
+
console.log(pc.dim(' // or'));
|
|
209
|
+
console.log(pc.dim(' import \'jasmincss/css\';\n'));
|
|
210
|
+
}
|
package/src/cli/run.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import pc from 'picocolors';
|
|
4
|
+
import chokidar from 'chokidar';
|
|
5
|
+
import { compileCSS, scanForUsedClasses } from '../core/compiler.js';
|
|
6
|
+
import { loadConfig } from '../config/loader.js';
|
|
7
|
+
|
|
8
|
+
export async function runCommand(task, options) {
|
|
9
|
+
const cwd = process.cwd();
|
|
10
|
+
const configPath = path.resolve(cwd, options.config);
|
|
11
|
+
const outputDir = path.resolve(cwd, options.output);
|
|
12
|
+
|
|
13
|
+
// Load config
|
|
14
|
+
let config;
|
|
15
|
+
try {
|
|
16
|
+
config = await loadConfig(configPath);
|
|
17
|
+
} catch (err) {
|
|
18
|
+
console.log(pc.yellow('No jasmin.config.js found. Using defaults.'));
|
|
19
|
+
config = (await import('../config/defaults.js')).defaultConfig;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Ensure output directory exists
|
|
23
|
+
if (!fs.existsSync(outputDir)) {
|
|
24
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
switch (task) {
|
|
28
|
+
case 'build':
|
|
29
|
+
await buildTask(config, outputDir, cwd, true);
|
|
30
|
+
break;
|
|
31
|
+
|
|
32
|
+
case 'dev':
|
|
33
|
+
await buildTask(config, outputDir, cwd, false);
|
|
34
|
+
break;
|
|
35
|
+
|
|
36
|
+
case 'watch':
|
|
37
|
+
await watchTask(config, outputDir, cwd, options);
|
|
38
|
+
break;
|
|
39
|
+
|
|
40
|
+
default:
|
|
41
|
+
console.log(pc.red(`Unknown task: ${task}`));
|
|
42
|
+
console.log(pc.dim('Available tasks: build, dev, watch'));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function buildTask(config, outputDir, cwd, isProduction) {
|
|
48
|
+
const startTime = Date.now();
|
|
49
|
+
|
|
50
|
+
console.log(pc.cyan(`\n🌸 JasminCSS ${isProduction ? 'Production' : 'Development'} Build\n`));
|
|
51
|
+
|
|
52
|
+
let usedClasses = null;
|
|
53
|
+
|
|
54
|
+
if (isProduction) {
|
|
55
|
+
// Scan project for used classes (tree-shaking)
|
|
56
|
+
console.log(pc.dim('Scanning project for used classes...'));
|
|
57
|
+
usedClasses = await scanForUsedClasses(cwd, config.content || [
|
|
58
|
+
'./**/*.{html,js,jsx,ts,tsx,vue,svelte}',
|
|
59
|
+
'!./node_modules/**'
|
|
60
|
+
]);
|
|
61
|
+
console.log(pc.dim(`Found ${usedClasses.size} unique class references`));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Compile CSS
|
|
65
|
+
console.log(pc.dim('Compiling CSS...'));
|
|
66
|
+
const { css, minified, stats } = await compileCSS(config, {
|
|
67
|
+
usedClasses,
|
|
68
|
+
minify: isProduction,
|
|
69
|
+
includeAll: !isProduction
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Write output files
|
|
73
|
+
const outputPath = path.join(outputDir, 'jasmin.css');
|
|
74
|
+
const minOutputPath = path.join(outputDir, 'jasmin.min.css');
|
|
75
|
+
|
|
76
|
+
fs.writeFileSync(outputPath, css);
|
|
77
|
+
console.log(pc.green(`✓ ${outputPath}`), pc.dim(`(${formatSize(css.length)})`));
|
|
78
|
+
|
|
79
|
+
if (isProduction && minified) {
|
|
80
|
+
fs.writeFileSync(minOutputPath, minified);
|
|
81
|
+
console.log(pc.green(`✓ ${minOutputPath}`), pc.dim(`(${formatSize(minified.length)})`));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const elapsed = Date.now() - startTime;
|
|
85
|
+
console.log(pc.cyan(`\n✨ Built in ${elapsed}ms`));
|
|
86
|
+
|
|
87
|
+
if (stats) {
|
|
88
|
+
console.log(pc.dim(` ${stats.utilities} utilities, ${stats.components} components`));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function watchTask(config, outputDir, cwd, options) {
|
|
93
|
+
console.log(pc.cyan('\n🌸 JasminCSS Watch Mode\n'));
|
|
94
|
+
console.log(pc.dim('Watching for changes...\n'));
|
|
95
|
+
|
|
96
|
+
// Initial build
|
|
97
|
+
await buildTask(config, outputDir, cwd, false);
|
|
98
|
+
|
|
99
|
+
// Watch for changes
|
|
100
|
+
const watchPaths = config.content || [
|
|
101
|
+
'./**/*.{html,js,jsx,ts,tsx,vue,svelte}',
|
|
102
|
+
'jasmin.config.js'
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
const watcher = chokidar.watch(watchPaths, {
|
|
106
|
+
ignored: /node_modules/,
|
|
107
|
+
persistent: true,
|
|
108
|
+
cwd
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
let rebuildTimeout;
|
|
112
|
+
const debouncedRebuild = () => {
|
|
113
|
+
clearTimeout(rebuildTimeout);
|
|
114
|
+
rebuildTimeout = setTimeout(async () => {
|
|
115
|
+
console.log(pc.dim('\nChange detected, rebuilding...'));
|
|
116
|
+
try {
|
|
117
|
+
// Reload config
|
|
118
|
+
const newConfig = await loadConfig(path.resolve(cwd, options.config));
|
|
119
|
+
await buildTask(newConfig, outputDir, cwd, false);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
console.log(pc.red('Build error:'), err.message);
|
|
122
|
+
}
|
|
123
|
+
}, 100);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
watcher.on('change', debouncedRebuild);
|
|
127
|
+
watcher.on('add', debouncedRebuild);
|
|
128
|
+
watcher.on('unlink', debouncedRebuild);
|
|
129
|
+
|
|
130
|
+
// Handle exit
|
|
131
|
+
process.on('SIGINT', () => {
|
|
132
|
+
console.log(pc.dim('\n\nStopping watch mode...'));
|
|
133
|
+
watcher.close();
|
|
134
|
+
process.exit(0);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function formatSize(bytes) {
|
|
139
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
140
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
141
|
+
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
142
|
+
}
|