swatchkit 0.0.1 → 0.0.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.
Files changed (3) hide show
  1. package/README.md +68 -32
  2. package/build.js +194 -36
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,57 +1,93 @@
1
1
  # SwatchKit
2
2
 
3
- **SwatchKit** is a lightweight, zero-configuration tool for creating HTML pattern libraries. It follows the "Magic Folder" principle: you drop files in, and a documentation site comes out.
3
+ **SwatchKit** is a lightweight tool for generating HTML pattern libraries. It acts as a **Pattern Discovery Engine**: it scans your folders for HTML components and stitches them into a documentation site using a layout you control.
4
4
 
5
- ## How it works
5
+ It follows the "Magic Folder" principle: drop files in, and a library comes out.
6
6
 
7
- 1. **Drop Patterns:** Add `.html` files (or folders) to `src/patterns/`.
8
- 2. **Add Styles:** Add standard CSS to `src/css/styles.css`.
9
- 3. **Build:** Run `node build.js`.
7
+ ## Quick Start
10
8
 
11
- ## Features
9
+ Try it instantly in any project:
12
10
 
13
- ### 1. The Magic Folder
14
- * **Single File:** Drop `button.html` into `src/patterns/`. It automatically appears in the library.
15
- * **Component Folder:** Drop a folder like `src/patterns/carousel/` containing `index.html`. It works exactly the same way.
11
+ ```bash
12
+ # 1. Initialize the layout
13
+ npx swatchkit init
16
14
 
17
- ### 2. Automatic JS Bundling
18
- If your component needs client-side JavaScript, just add a `.js` file to its folder.
19
- * Example: `src/patterns/carousel/script.js`
20
- * **SwatchKit** will automatically find it, wrap it in an IIFE (to protect scope), and bundle it into the final site. You can have multiple JS files per pattern.
15
+ # 2. Build the library
16
+ npx swatchkit
17
+ ```
21
18
 
22
- ### 3. Zero Config
23
- No config files. No build pipelines. No complex templating engines. Just HTML, CSS, and JS.
19
+ This will create a `swatches/` folder and build your site to `public/swatchkit/`.
24
20
 
25
- ## Usage
21
+ ---
26
22
 
27
- ### Using npx (Recommended)
23
+ ## Project Setup (Recommended)
28
24
 
29
- Run directly without installing:
30
- ```bash
31
- npx swatchkit
32
- ```
33
-
34
- ### Installing locally
25
+ For real projects, install SwatchKit as a development dependency to lock the version.
35
26
 
36
- Install as a dev dependency:
37
27
  ```bash
38
28
  npm install -D swatchkit
39
29
  ```
40
30
 
41
- Then add to your `package.json` scripts:
31
+ Then add it to your `package.json` scripts:
32
+
42
33
  ```json
43
34
  "scripts": {
44
- "build:patterns": "swatchkit"
35
+ "patterns": "swatchkit"
45
36
  }
46
37
  ```
47
38
 
48
- And run:
39
+ ## How It Works
40
+
41
+ ### 1. The Magic Folder
42
+ By default, SwatchKit looks for a `swatches/` folder in your project root.
43
+ * **Single File:** Drop `card.html` into `swatches/`. It appears in the library.
44
+ * **Component Folder:** Drop a folder like `swatches/carousel/` containing `index.html`. It works the same way.
45
+
46
+ ### 2. Custom Layouts
47
+ When you run `swatchkit init`, we create `swatches/_layout.html`.
48
+ **You own this file.**
49
+ * Add your own `<link rel="stylesheet" href="/css/app.css">`.
50
+ * Add custom fonts, scripts, or meta tags.
51
+ * Change the HTML structure, logo, or classes.
52
+
53
+ SwatchKit simply injects the content into the `<!-- PATTERNS -->` and `<!-- SIDEBAR_LINKS -->` placeholders.
54
+
55
+ ### 3. JavaScript Bundling
56
+ If your component needs client-side JS:
57
+ 1. Create a folder: `swatches/carousel/`.
58
+ 2. Add `index.html` (Markup).
59
+ 3. Add `script.js` (Logic).
60
+
61
+ SwatchKit automatically bundles your JS files, wraps them in a safety scope (IIFE), and injects them into the final build.
62
+
63
+ ## CLI Reference
64
+
49
65
  ```bash
50
- npm run build:patterns
66
+ swatchkit [command] [options]
51
67
  ```
52
68
 
53
- ### View the library
54
- After building, open the generated file:
55
- ```bash
56
- open dist/index.html
69
+ ### Commands
70
+ * `swatchkit` (Default): Builds the library.
71
+ * `swatchkit init`: Scaffolds the `_layout.html` file.
72
+
73
+ ### Flags
74
+ | Flag | Short | Description |
75
+ | :--- | :--- | :--- |
76
+ | `--watch` | `-w` | Watch mode (coming soon). |
77
+ | `--config` | `-c` | Path to config file. |
78
+ | `--input` | `-i` | Pattern directory (Default: `swatches/`). |
79
+ | `--outDir` | `-o` | Output directory (Default: `public/swatchkit`). |
80
+ | `--force` | `-f` | Overwrite layout file during init. |
81
+
82
+ ## Configuration
83
+ Optional. Create `swatchkit.config.js` in your root for persistent settings.
84
+
85
+ ```javascript
86
+ module.exports = {
87
+ // Override default pattern directory
88
+ input: './src/patterns',
89
+
90
+ // Override default output directory
91
+ outDir: './dist/docs'
92
+ };
57
93
  ```
package/build.js CHANGED
@@ -2,38 +2,170 @@
2
2
  const fs = require('fs');
3
3
  const path = require('path');
4
4
 
5
- const config = {
6
- srcDir: path.join(process.cwd(), 'src'),
7
- cssDir: path.join(process.cwd(), 'src/css'),
8
- patternsDir: path.join(process.cwd(), 'src/patterns'),
9
- layoutFile: path.join(__dirname, 'src/layout.html'),
10
- distDir: path.join(process.cwd(), 'dist'),
11
- distCssDir: path.join(process.cwd(), 'dist/css'),
12
- distJsDir: path.join(process.cwd(), 'dist/js'),
13
- outputFile: path.join(process.cwd(), 'dist/index.html'),
14
- outputJsFile: path.join(process.cwd(), 'dist/js/patterns.js')
15
- };
16
-
17
- function build() {
18
- console.log('[SwatchKit] Starting build...');
5
+ /**
6
+ * SwatchKit Build Script
7
+ * Refactored for Phase 1 Expansion
8
+ */
9
+
10
+ // --- 1. CLI Argument Parsing ---
11
+ function parseArgs(args) {
12
+ const options = {
13
+ command: null,
14
+ watch: false,
15
+ config: null,
16
+ input: null,
17
+ outDir: null,
18
+ force: false
19
+ };
20
+
21
+ for (let i = 2; i < args.length; i++) {
22
+ const arg = args[i];
23
+ if (arg === 'init') {
24
+ options.command = 'init';
25
+ } else if (arg === '-w' || arg === '--watch') {
26
+ options.watch = true;
27
+ } else if (arg === '-f' || arg === '--force') {
28
+ options.force = true;
29
+ } else if (arg === '-c' || arg === '--config') {
30
+ // Handle case where flag is last arg
31
+ if (i + 1 < args.length) {
32
+ options.config = args[++i];
33
+ }
34
+ } else if (arg === '-i' || arg === '--input') {
35
+ if (i + 1 < args.length) {
36
+ options.input = args[++i];
37
+ }
38
+ } else if (arg === '-o' || arg === '--outDir') {
39
+ if (i + 1 < args.length) {
40
+ options.outDir = args[++i];
41
+ }
42
+ }
43
+ }
44
+ return options;
45
+ }
46
+
47
+ // --- 2. Config Loading ---
48
+ function loadConfig(configPath) {
49
+ let finalPath;
50
+ if (configPath) {
51
+ finalPath = path.resolve(process.cwd(), configPath);
52
+ } else {
53
+ finalPath = path.join(process.cwd(), 'swatchkit.config.js');
54
+ }
55
+
56
+ if (fs.existsSync(finalPath)) {
57
+ try {
58
+ console.log(`[SwatchKit] Loading config from ${finalPath}`);
59
+ return require(finalPath);
60
+ } catch (e) {
61
+ console.error('[SwatchKit] Error loading config file:', e.message);
62
+ return {};
63
+ }
64
+ }
65
+ return {};
66
+ }
67
+
68
+ // --- 3. Smart Defaults & Path Resolution ---
69
+ function resolveSettings(cliOptions, fileConfig) {
70
+ const cwd = process.cwd();
71
+
72
+ // Helper to find patterns dir
73
+ function findPatternsDir() {
74
+ // 1. Explicit input
75
+ if (cliOptions.input) return path.resolve(cwd, cliOptions.input);
76
+ if (fileConfig.input) return path.resolve(cwd, fileConfig.input);
77
+
78
+ // 2. Search candidates
79
+ const candidates = ['swatches', 'src/swatches', 'src/patterns'];
80
+ for (const cand of candidates) {
81
+ const absPath = path.join(cwd, cand);
82
+ if (fs.existsSync(absPath)) return absPath;
83
+ }
84
+
85
+ // 3. Fallback default (swatches)
86
+ return path.join(cwd, 'swatches');
87
+ }
88
+
89
+ const patternsDir = findPatternsDir();
90
+
91
+ // Output Dir
92
+ // Default: public/swatchkit
93
+ const outDir = cliOptions.outDir
94
+ ? path.resolve(cwd, cliOptions.outDir)
95
+ : (fileConfig.outDir ? path.resolve(cwd, fileConfig.outDir) : path.join(cwd, 'public/swatchkit'));
96
+
97
+ // CSS Dir (Legacy support: src/css)
98
+ const cssDir = path.join(cwd, 'src/css');
99
+
100
+ return {
101
+ patternsDir,
102
+ outDir,
103
+ cssDir,
104
+ // Internal layout template (relative to this script)
105
+ internalLayout: path.join(__dirname, 'src/layout.html'),
106
+ // Project specific layout override
107
+ projectLayout: path.join(patternsDir, '_layout.html'),
108
+
109
+ // Derived paths
110
+ distCssDir: path.join(outDir, 'css'),
111
+ distJsDir: path.join(outDir, 'js'),
112
+ outputFile: path.join(outDir, 'index.html'),
113
+ outputJsFile: path.join(outDir, 'js/patterns.js')
114
+ };
115
+ }
116
+
117
+ // --- 4. Init Command Logic ---
118
+ function runInit(settings, options) {
119
+ console.log('[SwatchKit] Initializing...');
120
+
121
+ // Ensure patterns directory exists
122
+ if (!fs.existsSync(settings.patternsDir)) {
123
+ console.log(`Creating patterns directory: ${settings.patternsDir}`);
124
+ fs.mkdirSync(settings.patternsDir, { recursive: true });
125
+ }
126
+
127
+ const targetLayout = settings.projectLayout;
128
+
129
+ if (fs.existsSync(targetLayout) && !options.force) {
130
+ console.warn(`Warning: Layout file already exists at ${targetLayout}`);
131
+ console.warn('Use --force to overwrite.');
132
+ return;
133
+ }
134
+
135
+ if (fs.existsSync(settings.internalLayout)) {
136
+ const layoutContent = fs.readFileSync(settings.internalLayout, 'utf-8');
137
+ fs.writeFileSync(targetLayout, layoutContent);
138
+ console.log(`Created layout file at ${targetLayout}`);
139
+ } else {
140
+ console.error(`Error: Internal layout file not found at ${settings.internalLayout}`);
141
+ process.exit(1);
142
+ }
143
+ }
144
+
145
+ // --- 5. Build Logic ---
146
+ function build(settings) {
147
+ console.log(`[SwatchKit] Starting build...`);
148
+ console.log(` Patterns: ${settings.patternsDir}`);
149
+ console.log(` Output: ${settings.outDir}`);
19
150
 
20
151
  // 1. Check if patterns directory exists
21
- if (!fs.existsSync(config.patternsDir)) {
22
- console.error('Error: No patterns found. Create src/patterns to get started.');
152
+ if (!fs.existsSync(settings.patternsDir)) {
153
+ console.error(`Error: Patterns directory not found at ${settings.patternsDir}`);
154
+ console.error('Run "swatchkit init" to get started.');
23
155
  process.exit(1);
24
156
  }
25
157
 
26
158
  // 2. Ensure dist directories exist
27
- [config.distDir, config.distCssDir, config.distJsDir].forEach(dir => {
159
+ [settings.outDir, settings.distCssDir, settings.distJsDir].forEach(dir => {
28
160
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
29
161
  });
30
162
 
31
163
  // 3. Copy CSS files
32
- console.log('Copying CSS...');
33
- if (fs.existsSync(config.cssDir)) {
34
- const cssFiles = fs.readdirSync(config.cssDir).filter(file => file.endsWith('.css'));
164
+ if (fs.existsSync(settings.cssDir)) {
165
+ console.log('Copying CSS...');
166
+ const cssFiles = fs.readdirSync(settings.cssDir).filter(file => file.endsWith('.css'));
35
167
  cssFiles.forEach(file => {
36
- fs.copyFileSync(path.join(config.cssDir, file), path.join(config.distCssDir, file));
168
+ fs.copyFileSync(path.join(settings.cssDir, file), path.join(settings.distCssDir, file));
37
169
  });
38
170
  }
39
171
 
@@ -42,15 +174,18 @@ function build() {
42
174
  const patterns = [];
43
175
  const scripts = [];
44
176
 
45
- const items = fs.readdirSync(config.patternsDir);
177
+ const items = fs.readdirSync(settings.patternsDir);
46
178
 
47
179
  items.forEach(item => {
48
- const itemPath = path.join(config.patternsDir, item);
180
+ // Skip _layout.html or hidden files
181
+ if (item.startsWith('_') || item.startsWith('.')) return;
182
+
183
+ const itemPath = path.join(settings.patternsDir, item);
49
184
  const stat = fs.statSync(itemPath);
50
185
 
51
186
  let name, content, id;
52
187
 
53
- // Handle Directory Pattern (Folder with index.html + optional JS files)
188
+ // Handle Directory Pattern
54
189
  if (stat.isDirectory()) {
55
190
  const indexFile = path.join(itemPath, 'index.html');
56
191
 
@@ -59,7 +194,7 @@ function build() {
59
194
  id = item;
60
195
  content = fs.readFileSync(indexFile, 'utf-8');
61
196
 
62
- // Find all .js files in this directory
197
+ // Find all .js files
63
198
  const jsFiles = fs.readdirSync(itemPath).filter(file => file.endsWith('.js'));
64
199
 
65
200
  jsFiles.forEach(jsFile => {
@@ -73,7 +208,7 @@ ${scriptContent}
73
208
  });
74
209
  }
75
210
  }
76
- // Handle Single File Pattern (.html)
211
+ // Handle Single File Pattern
77
212
  else if (item.endsWith('.html')) {
78
213
  name = path.basename(item, '.html');
79
214
  id = name;
@@ -109,24 +244,47 @@ ${scriptContent}
109
244
 
110
245
  // 6. Write JS Bundle
111
246
  if (scripts.length > 0) {
112
- fs.writeFileSync(config.outputJsFile, scripts.join('\n'));
113
- console.log(`Bundled ${scripts.length} scripts to ${config.outputJsFile}`);
247
+ fs.writeFileSync(settings.outputJsFile, scripts.join('\n'));
248
+ console.log(`Bundled ${scripts.length} scripts to ${settings.outputJsFile}`);
114
249
  } else {
115
- // Write empty file if no scripts so browser doesn't 404
116
- fs.writeFileSync(config.outputJsFile, '// No pattern scripts found');
250
+ fs.writeFileSync(settings.outputJsFile, '// No pattern scripts found');
117
251
  }
118
252
 
119
- // 7. Read layout and replace placeholders
120
- let layout = fs.readFileSync(config.layoutFile, 'utf-8');
253
+ // 7. Load Layout
254
+ let layoutContent;
255
+ if (fs.existsSync(settings.projectLayout)) {
256
+ console.log(`Using custom layout: ${settings.projectLayout}`);
257
+ layoutContent = fs.readFileSync(settings.projectLayout, 'utf-8');
258
+ } else {
259
+ // console.log(`Using internal layout`);
260
+ layoutContent = fs.readFileSync(settings.internalLayout, 'utf-8');
261
+ }
121
262
 
122
- const finalHtml = layout
263
+ const finalHtml = layoutContent
123
264
  .replace('<!-- SIDEBAR_LINKS -->', sidebarLinks)
124
265
  .replace('<!-- PATTERNS -->', patternBlocks);
125
266
 
126
267
  // 8. Write output
127
- fs.writeFileSync(config.outputFile, finalHtml);
268
+ fs.writeFileSync(settings.outputFile, finalHtml);
128
269
 
129
- console.log(`Build complete! Generated ${config.outputFile}`);
270
+ console.log(`Build complete! Generated ${settings.outputFile}`);
130
271
  }
131
272
 
132
- build();
273
+ // --- Main Execution ---
274
+ try {
275
+ const cliOptions = parseArgs(process.argv);
276
+ const fileConfig = loadConfig(cliOptions.config);
277
+ const settings = resolveSettings(cliOptions, fileConfig);
278
+
279
+ if (cliOptions.command === 'init') {
280
+ runInit(settings, cliOptions);
281
+ } else {
282
+ build(settings);
283
+ if (cliOptions.watch) {
284
+ console.log('[SwatchKit] Watch mode is not yet fully implemented.');
285
+ }
286
+ }
287
+ } catch (error) {
288
+ console.error('[SwatchKit] Error:', error.message);
289
+ process.exit(1);
290
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swatchkit",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "A lightweight tool for creating HTML pattern libraries.",
5
5
  "main": "build.js",
6
6
  "bin": {