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/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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kempo-css",
3
- "version": "2.0.0",
3
+ "version": "2.1.2",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "scripts/build.js",
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
  }