kempo-css 2.0.0 → 2.1.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/.github/workflows/test.yml +25 -25
- package/AGENTS.md +43 -43
- package/CHANGELOG.md +117 -107
- package/CONTRIBUTING.md +17 -0
- package/LICENSE.md +21 -21
- package/README.md +2 -48
- package/dist/kempo.min.css +1 -1
- package/docs/demo.inc.html +213 -213
- package/docs/index.html +171 -160
- package/docs/kempo-hljs.css +124 -124
- package/docs/kempo.css +1194 -1210
- package/docs/kempo.min.css +1 -1
- package/docs/manifest.json +87 -87
- package/docs/nav.js +32 -32
- package/docs/theme-editor.html +19 -64
- package/llms.txt +205 -0
- package/package.json +1 -1
- package/scripts/build.js +173 -173
- package/src/kempo-hljs.css +124 -124
- package/src/kempo.css +1194 -1210
- package/tests/base_reset.browser-test.js +201 -201
- package/tests/buttons.browser-test.js +223 -223
- package/tests/colors.browser-test.js +277 -277
- package/tests/components.browser-test.js +131 -131
- package/tests/css_variables.browser-test.js +170 -170
- package/tests/display_flex.browser-test.js +159 -159
- package/tests/elevation.browser-test.js +239 -239
- package/tests/forms.browser-test.js +224 -224
- package/tests/rows_columns.browser-test.js +171 -171
- package/tests/spacing.browser-test.js +310 -310
- package/tests/tables.browser-test.js +192 -192
- package/tests/typography.browser-test.js +255 -255
package/llms.txt
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# Kempo CSS
|
|
2
|
+
|
|
3
|
+
> A lightweight, modern CSS-only framework providing utility classes and semantic components for rapid web development. No JavaScript required. Supports dark mode, theming via CSS custom properties, and a comprehensive color/elevation system.
|
|
4
|
+
|
|
5
|
+
## Project
|
|
6
|
+
|
|
7
|
+
- [Documentation](https://dustinpoissant.github.io/kempo-css/): Full docs with live examples and an interactive theme editor
|
|
8
|
+
- [GitHub Repository](https://github.com/dustinpoissant/kempo-css): Source code, issues, and releases
|
|
9
|
+
- [npm Package](https://www.npmjs.com/package/kempo-css): `npm install kempo-css`
|
|
10
|
+
- License: MIT
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```html
|
|
15
|
+
<!-- From npm -->
|
|
16
|
+
<link rel="stylesheet" href="node_modules/kempo-css/kempo.css">
|
|
17
|
+
|
|
18
|
+
<!-- From CDN (jsDelivr) -->
|
|
19
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/kempo-css/kempo.css">
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Or import in CSS/SCSS:
|
|
23
|
+
```css
|
|
24
|
+
@import 'kempo-css/kempo.css';
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Theming
|
|
28
|
+
|
|
29
|
+
All visual properties are controlled by CSS custom properties on `:root`. Override them to theme the framework. Only the base colors need to be defined — hover, text, and inverse variants are auto-calculated using `oklch` relative color syntax.
|
|
30
|
+
|
|
31
|
+
Base color variables (override to theme):
|
|
32
|
+
- `--c_bg` — page background; light-dark aware (default light: `rgb(249,249,249)`, dark: `rgb(51,51,51)`)
|
|
33
|
+
- `--c_overscroll` — overscroll/rubber-band background
|
|
34
|
+
- `--c_border` — border color; light-dark aware
|
|
35
|
+
- `--c_primary` — primary brand color (default `rgb(51,102,255)`)
|
|
36
|
+
- `--c_secondary` — secondary brand color (default `rgb(153,51,255)`)
|
|
37
|
+
- `--c_success` — success state (default `rgb(0,136,0)`)
|
|
38
|
+
- `--c_warning` — warning state (default `rgb(255,102,0)`)
|
|
39
|
+
- `--c_danger` — danger/error state (default `rgb(255,0,51)`)
|
|
40
|
+
- `--btn_bg` — default button background
|
|
41
|
+
- `--tc` — default text color; light-dark aware
|
|
42
|
+
- `--tc_dark` / `--tc_light` — always-dark / always-light text
|
|
43
|
+
- `--tc_muted` — muted/secondary text; light-dark aware
|
|
44
|
+
- `--c_overlay` — overlay backdrop color
|
|
45
|
+
|
|
46
|
+
Layout/typography variables:
|
|
47
|
+
- `--spacer` (default `1rem`) — base spacing unit; `--spacer_h` (0.5rem), `--spacer_q` (0.25rem)
|
|
48
|
+
- `--fs_base` (default `16px`) — base font size; heading sizes h1–h6 are derived from this
|
|
49
|
+
- `--container_width` (default `90rem`) — max-width for `main` and `.container`
|
|
50
|
+
- `--radius` (default `0.25rem`) — border radius
|
|
51
|
+
- `--animation_ms` (default `256ms`) — transition duration
|
|
52
|
+
- `--line-height` (default `1.35em`)
|
|
53
|
+
- `--ff_body`, `--ff_heading`, `--ff_mono` — font families
|
|
54
|
+
|
|
55
|
+
## Dark Mode
|
|
56
|
+
|
|
57
|
+
Dark mode is controlled via the `theme` attribute. Apply `theme="dark"` to force dark, `theme="light"` to force light, or `theme="auto"` to follow the system `prefers-color-scheme`.
|
|
58
|
+
|
|
59
|
+
```html
|
|
60
|
+
<html theme="dark">
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Classes
|
|
64
|
+
|
|
65
|
+
### Display
|
|
66
|
+
|
|
67
|
+
| Class | Effect |
|
|
68
|
+
|-------|--------|
|
|
69
|
+
| `.d-b` | `display: block` |
|
|
70
|
+
| `.d-ib` | `display: inline-block` |
|
|
71
|
+
| `.d-i` | `display: inline` |
|
|
72
|
+
| `.d-f` | `display: flex; flex-wrap: wrap` |
|
|
73
|
+
| `.d-if` | `display: inline-flex; flex-wrap: wrap` |
|
|
74
|
+
| `.d-g` | `display: grid` |
|
|
75
|
+
| `.d-n` | `display: none` |
|
|
76
|
+
|
|
77
|
+
Responsive prefixes: `d-` (desktop ≥1024px), `t-` (tablet 769–1023px), `m-` (mobile ≤768px).
|
|
78
|
+
Examples: `.m-d-n` hides on mobile; `.d-d-f` makes flex on desktop only.
|
|
79
|
+
|
|
80
|
+
### Flex
|
|
81
|
+
|
|
82
|
+
`.flex` / `.flex-1` through `.flex-10` — sets `flex: N N auto`. Same classes with `d-`, `t-`, `m-` prefixes for responsive variants (e.g. `.m-flex-2`).
|
|
83
|
+
|
|
84
|
+
`.flex-0` — `flex: 0 0` (no grow/shrink).
|
|
85
|
+
|
|
86
|
+
### Layout
|
|
87
|
+
|
|
88
|
+
- `main`, `.container` — centered, max-width (`--container_width`), padded wrapper
|
|
89
|
+
- `.fixed` — `position: fixed; top: 0; width: 100%; z-index: 99`; add `.scrolled` to show shadow
|
|
90
|
+
- `.full` — `display: block; width: 100%`
|
|
91
|
+
- `body.no-scroll` — prevents body scroll (use when dialogs or other overlays active)
|
|
92
|
+
|
|
93
|
+
### Rows / Columns (12-column flex grid)
|
|
94
|
+
|
|
95
|
+
- `.row` — `display: flex; flex-wrap: wrap`
|
|
96
|
+
- `.col` — `flex: 1 1` (fills remaining space)
|
|
97
|
+
- `.span-1` through `.span-12` — 12-col span widths
|
|
98
|
+
- Responsive variants: `.d-span-*` (desktop), `.t-span-*` (tablet), `.m-span-*` (mobile)
|
|
99
|
+
|
|
100
|
+
### CSS Grid Columns
|
|
101
|
+
|
|
102
|
+
- `.cols-2` through `.cols-10` — sets `grid-template-columns: repeat(N, 1fr)`
|
|
103
|
+
- Responsive variants: `.d-cols-*`, `.t-cols-*`, `.m-cols-*`
|
|
104
|
+
|
|
105
|
+
### Typography
|
|
106
|
+
|
|
107
|
+
- `.h1`–`.h6` — apply heading font size to any element
|
|
108
|
+
- `.small` — `font-size: var(--fs_small)` (0.6× base)
|
|
109
|
+
- `.large` — `font-size: var(--fs_large)` (1.5× base)
|
|
110
|
+
- `.ff-mono` — monospace font
|
|
111
|
+
- `.ta-left`, `.ta-center`, `.ta-right` — text alignment
|
|
112
|
+
- `.td-n` — `text-decoration: none`
|
|
113
|
+
- `.no-link` / `.no-link:hover` — removes link color and underline
|
|
114
|
+
- `.link` — applies link styling to non-`<a>` elements
|
|
115
|
+
|
|
116
|
+
Block elements (`p`, `h1`–`h6`, `blockquote`, `ul`, `ol`, `dl`, `pre`, `hr`, `dd`) all get `margin-bottom: var(--spacer)` by default.
|
|
117
|
+
|
|
118
|
+
### Spacing
|
|
119
|
+
|
|
120
|
+
Sizes: whole = `--spacer` (1rem), half (`h`) = `--spacer_h` (0.5rem), quarter (`q`) = `--spacer_q` (0.25rem), zero (`0`) = 0.
|
|
121
|
+
|
|
122
|
+
| Side | Padding (whole) | Padding (half) | Padding (quarter) | Padding (zero) | Margin (whole) | Margin (half) | Margin (quarter) | Margin (zero) | Margin (negative) |
|
|
123
|
+
|------|-----------------|----------------|-------------------|----------------|----------------|---------------|------------------|---------------|-------------------|
|
|
124
|
+
| All | `.p` | `.ph` | `.pq` | `.p0` | `.m` | `.mh` | `.mq` | `.m0` | `.-m` |
|
|
125
|
+
| Top | `.pt` | `.pth` | `.ptq` | `.pt0` | `.mt` | `.mth` | `.mtq` | `.mt0` | `.-mt` |
|
|
126
|
+
| Bottom | `.pb` | `.pbh` | `.pbq` | `.pb0` | `.mb` | `.mbh` | `.mbq` | `.mb0` | `.-mb` |
|
|
127
|
+
| Left | `.pl` | `.plh` | `.plq` | `.pl0` | `.ml` | `.mlh` | `.mlq` | `.ml0` | `.-ml` |
|
|
128
|
+
| Right | `.pr` | `.prh` | `.prq` | `.pr0` | `.mr` | `.mrh` | `.mrq` | `.mr0` | `.-mr` |
|
|
129
|
+
| Horizontal | `.px` | `.pxh` | `.pxq` | `.px0` | `.mx` | `.mxh` | `.mxq` | `.mx0` | `.-mx` |
|
|
130
|
+
| Vertical | `.py` | `.pyh` | `.pyq` | `.py0` | `.my` | `.myh` | `.myq` | `.my0` | `.-my` |
|
|
131
|
+
|
|
132
|
+
### Borders
|
|
133
|
+
|
|
134
|
+
- `.b` — all sides; `.bt` / `.bb` / `.bl` / `.br` — individual sides; `.bx` — horizontal; `.by` — vertical
|
|
135
|
+
- `.b0` — remove all; `.bt0` / `.bb0` / `.bl0` / `.br0` / `.bx0` / `.by0` — remove individual
|
|
136
|
+
|
|
137
|
+
### Border Radius
|
|
138
|
+
|
|
139
|
+
- `.r` — all corners; `.rt` / `.rb` / `.rl` / `.rr` — sides; `.rtl` / `.rtr` / `.rbl` / `.rbr` — individual corners
|
|
140
|
+
- `.r0` — remove all; `.rt0` / `.rb0` / `.rl0` / `.rr0` / `.rtl0` / `.rtr0` / `.rbl0` / `.rbr0` — remove individual
|
|
141
|
+
- `.round` — `border-radius: 9999rem` (pill/circle)
|
|
142
|
+
|
|
143
|
+
### Buttons
|
|
144
|
+
|
|
145
|
+
`button`, `.btn`, `input[type="button"]`, `input[type="submit"]`, and `input[type="reset"]` are all styled by default.
|
|
146
|
+
|
|
147
|
+
Semantic color variants — add to a button element:
|
|
148
|
+
- `.primary`, `.secondary`, `.success`, `.warning`, `.danger`
|
|
149
|
+
|
|
150
|
+
Other button modifiers:
|
|
151
|
+
- `.link` — transparent, no border, inherits text color and font size, used to make a button (or other element) look like a link
|
|
152
|
+
- `.no-btn` — strips all kempo styles; renders as plain inline element inheriting color/font, no border/background/padding (retains focus ring via `--focus_shadow`)
|
|
153
|
+
- `.no-style` — opts a `<button>` out of kempo styles entirely, leaving browser default button appearance
|
|
154
|
+
- `.btn-grp` — wraps buttons in an inline-flex group with joined borders
|
|
155
|
+
|
|
156
|
+
### Forms
|
|
157
|
+
|
|
158
|
+
All standard inputs are auto-styled: `input` (except buttons/radio/checkbox), `select`, `textarea`. Custom styling is also applied to `input[type="checkbox"]`, `input[type="radio"]`, `input[type="color"]`, and date/time/search inputs.
|
|
159
|
+
|
|
160
|
+
- `label` — `display: block`
|
|
161
|
+
- `label.checkbox` / `label.radio` — inline-block label for use next to checkbox/radio
|
|
162
|
+
|
|
163
|
+
### Tables
|
|
164
|
+
|
|
165
|
+
- `table` — full-width, no border-spacing, auto-styled `th`/`td` with borders and padding
|
|
166
|
+
- `.table-wrapper` — wraps a table for horizontal scroll overflow
|
|
167
|
+
|
|
168
|
+
### Background Colors
|
|
169
|
+
|
|
170
|
+
- `.bg-default` — `--c_bg` background with `--tc` text
|
|
171
|
+
- `.bg-alt` — `--c_bg__alt` (slightly darker/lighter than bg)
|
|
172
|
+
- `.bg-inv` — inverted background; also re-scopes all `--c_*` vars to their inverse variants
|
|
173
|
+
- `.bg-primary`, `.bg-secondary`, `.bg-success`, `.bg-warning`, `.bg-danger` — semantic color backgrounds with appropriate text color set automatically
|
|
174
|
+
|
|
175
|
+
### Text Colors
|
|
176
|
+
|
|
177
|
+
- `.tc-default` — default text color
|
|
178
|
+
- `.tc-inv` — inverted text color
|
|
179
|
+
- `.tc-muted` — muted text
|
|
180
|
+
- `.tc-primary`, `.tc-secondary`, `.tc-success`, `.tc-warning`, `.tc-danger` — semantic text colors; automatically switch to their inverse when inside `.bg-inv` or `.is-inv`
|
|
181
|
+
|
|
182
|
+
### Elevation
|
|
183
|
+
|
|
184
|
+
Elevation classes only set `z-index`. Combine with `.shadow` and/or `.bg-elevation` for visual depth.
|
|
185
|
+
|
|
186
|
+
- `.elevation-0` through `.elevation-10` — `z-index: 0` through `z-index: 100` (increments of 10); level 2 = page default
|
|
187
|
+
- `.shadow` + `.elevation-*` — adds `box-shadow`; inset shadow at levels 0–1, no shadow at level 2, outset shadow at levels 3–5
|
|
188
|
+
- `.bg-elevation` + `.elevation-*` — sets `background-color` to the elevation-appropriate tint (`--c_bg_elevation_0` through `--c_bg_elevation_10`)
|
|
189
|
+
- Shadows and backgrounds max out at 5, 6-10 look the same as 5 but still increase z-index.
|
|
190
|
+
|
|
191
|
+
CSS variables: `--c_bg_elevation_0`–`--c_bg_elevation_10`, `--shadow_0`–`--shadow_10` (shadow vars `__light`/`__dark` variants also exist).
|
|
192
|
+
|
|
193
|
+
### Components
|
|
194
|
+
|
|
195
|
+
- `.card` — bordered box with `--radius`, top/left/right padding, and `margin-bottom`
|
|
196
|
+
- `.icon` — `display: inline-block; width: 1.35em; vertical-align: top` for inline SVG icons
|
|
197
|
+
|
|
198
|
+
## File Structure
|
|
199
|
+
|
|
200
|
+
- `dist/kempo.min.css` — minified file for production
|
|
201
|
+
- `dist/kempo-hljs.min.css` - minified "highlight.js" styles for production
|
|
202
|
+
- `src/*` - source files for kempo-css developement
|
|
203
|
+
- `test/*` - unit tests for kempo-css developmenet
|
|
204
|
+
- `docs/*` - github pages docs
|
|
205
|
+
|
package/package.json
CHANGED
package/scripts/build.js
CHANGED
|
@@ -1,174 +1,174 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { execSync } from 'child_process';
|
|
4
|
-
import fs from 'fs';
|
|
5
|
-
import path from 'path';
|
|
6
|
-
import { minify } from 'terser';
|
|
7
|
-
|
|
8
|
-
// Check for watch flag
|
|
9
|
-
const isWatchMode = process.argv.includes('--watch');
|
|
10
|
-
|
|
11
|
-
if (isWatchMode) {
|
|
12
|
-
console.log('Watch mode enabled - monitoring CSS files for changes...\n');
|
|
13
|
-
} else {
|
|
14
|
-
console.log('Building Kempo CSS...\n');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Define input and output files
|
|
18
|
-
const inputFiles = [
|
|
19
|
-
'src/kempo.css',
|
|
20
|
-
'src/kempo-hljs.css'
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
const outputDir = 'dist';
|
|
24
|
-
const outputFiles = [
|
|
25
|
-
'kempo.min.css',
|
|
26
|
-
'kempo-hljs.min.css'
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
// Create dist directory if it doesn't exist
|
|
30
|
-
if (!fs.existsSync(outputDir)) {
|
|
31
|
-
fs.mkdirSync(outputDir);
|
|
32
|
-
console.log(`Created ${outputDir}/ directory`);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Minify each CSS file
|
|
36
|
-
inputFiles.forEach((inputFile, index) => {
|
|
37
|
-
const outputFile = path.join(outputDir, outputFiles[index]);
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
// Check if input file exists
|
|
41
|
-
if (!fs.existsSync(inputFile)) {
|
|
42
|
-
console.log(`Skipping ${inputFile} (file not found)`);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Get file size before minification
|
|
47
|
-
const originalSize = fs.statSync(inputFile).size;
|
|
48
|
-
|
|
49
|
-
// Minify the CSS using clean-css-cli
|
|
50
|
-
console.log(`Minifying ${inputFile}...`);
|
|
51
|
-
execSync(`npx cleancss -o ${outputFile} ${inputFile}`, { stdio: 'inherit' });
|
|
52
|
-
|
|
53
|
-
// Get file size after minification
|
|
54
|
-
const minifiedSize = fs.statSync(outputFile).size;
|
|
55
|
-
const savings = ((originalSize - minifiedSize) / originalSize * 100).toFixed(1);
|
|
56
|
-
|
|
57
|
-
console.log(`${inputFile} → ${outputFile}`);
|
|
58
|
-
console.log(` Original: ${(originalSize / 1024).toFixed(1)}KB`);
|
|
59
|
-
console.log(` Minified: ${(minifiedSize / 1024).toFixed(1)}KB`);
|
|
60
|
-
console.log(` Savings: ${savings}%\n`);
|
|
61
|
-
} catch (error) {
|
|
62
|
-
console.error(`Error minifying ${inputFile}:`, error.message);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Process and minify components
|
|
67
|
-
async function processComponents(){
|
|
68
|
-
const componentsDir = 'src/components';
|
|
69
|
-
const docsComponentsDir = 'docs/components';
|
|
70
|
-
|
|
71
|
-
if(!fs.existsSync(componentsDir)){
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if(!fs.existsSync(docsComponentsDir)){
|
|
76
|
-
fs.mkdirSync(docsComponentsDir, { recursive: true });
|
|
77
|
-
console.log(`Created ${docsComponentsDir}/ directory`);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const componentFiles = fs.readdirSync(componentsDir).filter(file => file.endsWith('.js'));
|
|
81
|
-
|
|
82
|
-
console.log('\nProcessing JavaScript files...');
|
|
83
|
-
for(const file of componentFiles){
|
|
84
|
-
const srcPath = path.join(componentsDir, file);
|
|
85
|
-
const destPath = path.join(docsComponentsDir, file);
|
|
86
|
-
|
|
87
|
-
try{
|
|
88
|
-
const code = fs.readFileSync(srcPath, 'utf-8');
|
|
89
|
-
|
|
90
|
-
if(file.endsWith('.min.js')){
|
|
91
|
-
fs.writeFileSync(destPath, code);
|
|
92
|
-
console.log(`Copied ${srcPath} → ${destPath} (already minified)`);
|
|
93
|
-
}else{
|
|
94
|
-
console.log(`Minifying ${srcPath}...`);
|
|
95
|
-
const result = await minify(code);
|
|
96
|
-
fs.writeFileSync(destPath, result.code);
|
|
97
|
-
const originalSize = Buffer.byteLength(code, 'utf-8');
|
|
98
|
-
const minifiedSize = Buffer.byteLength(result.code, 'utf-8');
|
|
99
|
-
const savings = ((originalSize - minifiedSize) / originalSize * 100).toFixed(1);
|
|
100
|
-
console.log(` Original: ${(originalSize / 1024).toFixed(1)}KB`);
|
|
101
|
-
console.log(` Minified: ${(minifiedSize / 1024).toFixed(1)}KB`);
|
|
102
|
-
console.log(` Savings: ${savings}%`);
|
|
103
|
-
}
|
|
104
|
-
}catch(error){
|
|
105
|
-
console.error(`Error processing ${srcPath}:`, error.message);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
processComponents().then(() => {
|
|
111
|
-
|
|
112
|
-
// Copy CSS to docs
|
|
113
|
-
const cssFiles = ['src/kempo.css', 'src/kempo-hljs.css'];
|
|
114
|
-
const docsDir = 'docs';
|
|
115
|
-
|
|
116
|
-
cssFiles.forEach(file => {
|
|
117
|
-
if(fs.existsSync(file)){
|
|
118
|
-
const fileName = path.basename(file);
|
|
119
|
-
const destPath = path.join(docsDir, fileName);
|
|
120
|
-
fs.copyFileSync(file, destPath);
|
|
121
|
-
console.log(`Copied ${file} → ${destPath}`);
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
// Copy minified CSS to docs
|
|
126
|
-
const minifiedFiles = fs.readdirSync(outputDir).filter(file => file.endsWith('.css'));
|
|
127
|
-
minifiedFiles.forEach(file => {
|
|
128
|
-
const srcPath = path.join(outputDir, file);
|
|
129
|
-
const destPath = path.join(docsDir, file);
|
|
130
|
-
fs.copyFileSync(srcPath, destPath);
|
|
131
|
-
console.log(`Copied ${srcPath} → ${destPath}`);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
console.log('\nBuild complete!');
|
|
135
|
-
console.log(`Minified files are in the ${outputDir}/ directory`);
|
|
136
|
-
}).catch(error => {
|
|
137
|
-
console.error('Build error:', error);
|
|
138
|
-
process.exit(1);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
// Watch mode functionality
|
|
142
|
-
if (isWatchMode) {
|
|
143
|
-
console.log('Watching for changes... (Press Ctrl+C to stop)\n');
|
|
144
|
-
|
|
145
|
-
inputFiles.forEach(inputFile => {
|
|
146
|
-
if (fs.existsSync(inputFile)) {
|
|
147
|
-
fs.watchFile(inputFile, { interval: 1000 }, (curr, prev) => {
|
|
148
|
-
if (curr.mtime !== prev.mtime) {
|
|
149
|
-
console.log(`\n${inputFile} changed, rebuilding...`);
|
|
150
|
-
|
|
151
|
-
// Find the corresponding output file
|
|
152
|
-
const index = inputFiles.indexOf(inputFile);
|
|
153
|
-
const outputFile = path.join(outputDir, outputFiles[index]);
|
|
154
|
-
try {
|
|
155
|
-
const originalSize = fs.statSync(inputFile).size;
|
|
156
|
-
console.log(`Minifying ${inputFile}...`);
|
|
157
|
-
execSync(`npx cleancss -o ${outputFile} ${inputFile}`, { stdio: 'inherit' });
|
|
158
|
-
|
|
159
|
-
const minifiedSize = fs.statSync(outputFile).size;
|
|
160
|
-
const savings = ((originalSize - minifiedSize) / originalSize * 100).toFixed(1);
|
|
161
|
-
|
|
162
|
-
console.log(`${inputFile} → ${outputFile}`);
|
|
163
|
-
console.log(` Original: ${(originalSize / 1024).toFixed(1)}KB`);
|
|
164
|
-
console.log(` Minified: ${(minifiedSize / 1024).toFixed(1)}KB`);
|
|
165
|
-
console.log(` Savings: ${savings}%`);
|
|
166
|
-
console.log('\nWatching for changes...');
|
|
167
|
-
} catch (error) {
|
|
168
|
-
console.error(`Error minifying ${inputFile}:`, error.message);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { minify } from 'terser';
|
|
7
|
+
|
|
8
|
+
// Check for watch flag
|
|
9
|
+
const isWatchMode = process.argv.includes('--watch');
|
|
10
|
+
|
|
11
|
+
if (isWatchMode) {
|
|
12
|
+
console.log('Watch mode enabled - monitoring CSS files for changes...\n');
|
|
13
|
+
} else {
|
|
14
|
+
console.log('Building Kempo CSS...\n');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Define input and output files
|
|
18
|
+
const inputFiles = [
|
|
19
|
+
'src/kempo.css',
|
|
20
|
+
'src/kempo-hljs.css'
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const outputDir = 'dist';
|
|
24
|
+
const outputFiles = [
|
|
25
|
+
'kempo.min.css',
|
|
26
|
+
'kempo-hljs.min.css'
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
// Create dist directory if it doesn't exist
|
|
30
|
+
if (!fs.existsSync(outputDir)) {
|
|
31
|
+
fs.mkdirSync(outputDir);
|
|
32
|
+
console.log(`Created ${outputDir}/ directory`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Minify each CSS file
|
|
36
|
+
inputFiles.forEach((inputFile, index) => {
|
|
37
|
+
const outputFile = path.join(outputDir, outputFiles[index]);
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
// Check if input file exists
|
|
41
|
+
if (!fs.existsSync(inputFile)) {
|
|
42
|
+
console.log(`Skipping ${inputFile} (file not found)`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Get file size before minification
|
|
47
|
+
const originalSize = fs.statSync(inputFile).size;
|
|
48
|
+
|
|
49
|
+
// Minify the CSS using clean-css-cli
|
|
50
|
+
console.log(`Minifying ${inputFile}...`);
|
|
51
|
+
execSync(`npx cleancss -o ${outputFile} ${inputFile}`, { stdio: 'inherit' });
|
|
52
|
+
|
|
53
|
+
// Get file size after minification
|
|
54
|
+
const minifiedSize = fs.statSync(outputFile).size;
|
|
55
|
+
const savings = ((originalSize - minifiedSize) / originalSize * 100).toFixed(1);
|
|
56
|
+
|
|
57
|
+
console.log(`${inputFile} → ${outputFile}`);
|
|
58
|
+
console.log(` Original: ${(originalSize / 1024).toFixed(1)}KB`);
|
|
59
|
+
console.log(` Minified: ${(minifiedSize / 1024).toFixed(1)}KB`);
|
|
60
|
+
console.log(` Savings: ${savings}%\n`);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error(`Error minifying ${inputFile}:`, error.message);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Process and minify components
|
|
67
|
+
async function processComponents(){
|
|
68
|
+
const componentsDir = 'src/components';
|
|
69
|
+
const docsComponentsDir = 'docs/components';
|
|
70
|
+
|
|
71
|
+
if(!fs.existsSync(componentsDir)){
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if(!fs.existsSync(docsComponentsDir)){
|
|
76
|
+
fs.mkdirSync(docsComponentsDir, { recursive: true });
|
|
77
|
+
console.log(`Created ${docsComponentsDir}/ directory`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const componentFiles = fs.readdirSync(componentsDir).filter(file => file.endsWith('.js'));
|
|
81
|
+
|
|
82
|
+
console.log('\nProcessing JavaScript files...');
|
|
83
|
+
for(const file of componentFiles){
|
|
84
|
+
const srcPath = path.join(componentsDir, file);
|
|
85
|
+
const destPath = path.join(docsComponentsDir, file);
|
|
86
|
+
|
|
87
|
+
try{
|
|
88
|
+
const code = fs.readFileSync(srcPath, 'utf-8');
|
|
89
|
+
|
|
90
|
+
if(file.endsWith('.min.js')){
|
|
91
|
+
fs.writeFileSync(destPath, code);
|
|
92
|
+
console.log(`Copied ${srcPath} → ${destPath} (already minified)`);
|
|
93
|
+
}else{
|
|
94
|
+
console.log(`Minifying ${srcPath}...`);
|
|
95
|
+
const result = await minify(code);
|
|
96
|
+
fs.writeFileSync(destPath, result.code);
|
|
97
|
+
const originalSize = Buffer.byteLength(code, 'utf-8');
|
|
98
|
+
const minifiedSize = Buffer.byteLength(result.code, 'utf-8');
|
|
99
|
+
const savings = ((originalSize - minifiedSize) / originalSize * 100).toFixed(1);
|
|
100
|
+
console.log(` Original: ${(originalSize / 1024).toFixed(1)}KB`);
|
|
101
|
+
console.log(` Minified: ${(minifiedSize / 1024).toFixed(1)}KB`);
|
|
102
|
+
console.log(` Savings: ${savings}%`);
|
|
103
|
+
}
|
|
104
|
+
}catch(error){
|
|
105
|
+
console.error(`Error processing ${srcPath}:`, error.message);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
processComponents().then(() => {
|
|
111
|
+
|
|
112
|
+
// Copy CSS to docs
|
|
113
|
+
const cssFiles = ['src/kempo.css', 'src/kempo-hljs.css'];
|
|
114
|
+
const docsDir = 'docs';
|
|
115
|
+
|
|
116
|
+
cssFiles.forEach(file => {
|
|
117
|
+
if(fs.existsSync(file)){
|
|
118
|
+
const fileName = path.basename(file);
|
|
119
|
+
const destPath = path.join(docsDir, fileName);
|
|
120
|
+
fs.copyFileSync(file, destPath);
|
|
121
|
+
console.log(`Copied ${file} → ${destPath}`);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Copy minified CSS to docs
|
|
126
|
+
const minifiedFiles = fs.readdirSync(outputDir).filter(file => file.endsWith('.css'));
|
|
127
|
+
minifiedFiles.forEach(file => {
|
|
128
|
+
const srcPath = path.join(outputDir, file);
|
|
129
|
+
const destPath = path.join(docsDir, file);
|
|
130
|
+
fs.copyFileSync(srcPath, destPath);
|
|
131
|
+
console.log(`Copied ${srcPath} → ${destPath}`);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
console.log('\nBuild complete!');
|
|
135
|
+
console.log(`Minified files are in the ${outputDir}/ directory`);
|
|
136
|
+
}).catch(error => {
|
|
137
|
+
console.error('Build error:', error);
|
|
138
|
+
process.exit(1);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Watch mode functionality
|
|
142
|
+
if (isWatchMode) {
|
|
143
|
+
console.log('Watching for changes... (Press Ctrl+C to stop)\n');
|
|
144
|
+
|
|
145
|
+
inputFiles.forEach(inputFile => {
|
|
146
|
+
if (fs.existsSync(inputFile)) {
|
|
147
|
+
fs.watchFile(inputFile, { interval: 1000 }, (curr, prev) => {
|
|
148
|
+
if (curr.mtime !== prev.mtime) {
|
|
149
|
+
console.log(`\n${inputFile} changed, rebuilding...`);
|
|
150
|
+
|
|
151
|
+
// Find the corresponding output file
|
|
152
|
+
const index = inputFiles.indexOf(inputFile);
|
|
153
|
+
const outputFile = path.join(outputDir, outputFiles[index]);
|
|
154
|
+
try {
|
|
155
|
+
const originalSize = fs.statSync(inputFile).size;
|
|
156
|
+
console.log(`Minifying ${inputFile}...`);
|
|
157
|
+
execSync(`npx cleancss -o ${outputFile} ${inputFile}`, { stdio: 'inherit' });
|
|
158
|
+
|
|
159
|
+
const minifiedSize = fs.statSync(outputFile).size;
|
|
160
|
+
const savings = ((originalSize - minifiedSize) / originalSize * 100).toFixed(1);
|
|
161
|
+
|
|
162
|
+
console.log(`${inputFile} → ${outputFile}`);
|
|
163
|
+
console.log(` Original: ${(originalSize / 1024).toFixed(1)}KB`);
|
|
164
|
+
console.log(` Minified: ${(minifiedSize / 1024).toFixed(1)}KB`);
|
|
165
|
+
console.log(` Savings: ${savings}%`);
|
|
166
|
+
console.log('\nWatching for changes...');
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error(`Error minifying ${inputFile}:`, error.message);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
174
|
}
|