create-quilltap-theme 1.0.6 → 2.0.1

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 CHANGED
@@ -1,27 +1,31 @@
1
1
  # create-quilltap-theme
2
2
 
3
- Scaffold a new Quilltap theme plugin with a single command.
3
+ Scaffold a new Quilltap theme with a single command.
4
4
 
5
5
  ## Usage
6
6
 
7
- ### Using npm init (recommended)
7
+ ### Bundle format (default, recommended)
8
8
 
9
9
  ```bash
10
- npm init quilltap-theme my-theme
10
+ npx create-quilltap-theme my-theme
11
11
  ```
12
12
 
13
- ### Using npx
13
+ This creates a `.qtap-theme` bundle directory — a simple, declarative format with JSON tokens, CSS, and fonts. No build tools, npm packages, or TypeScript required.
14
+
15
+ ### Legacy plugin format (deprecated)
14
16
 
15
17
  ```bash
16
- npx create-quilltap-theme my-theme
18
+ npx create-quilltap-theme my-theme --plugin
17
19
  ```
18
20
 
21
+ Creates an npm-based theme plugin. This format is deprecated; use bundles for new themes.
22
+
19
23
  ### Interactive mode
20
24
 
21
25
  Run without arguments for interactive prompts:
22
26
 
23
27
  ```bash
24
- npm init quilltap-theme
28
+ npx create-quilltap-theme
25
29
  ```
26
30
 
27
31
  ### Skip prompts
@@ -29,11 +33,24 @@ npm init quilltap-theme
29
33
  Use `-y` or `--yes` to use defaults:
30
34
 
31
35
  ```bash
32
- npm init quilltap-theme my-theme --yes
36
+ npx create-quilltap-theme my-theme --yes
33
37
  ```
34
38
 
35
39
  ## What gets created
36
40
 
41
+ ### Bundle format (default)
42
+
43
+ ```
44
+ my-theme/
45
+ ├── theme.json # Theme manifest with metadata and tokens
46
+ ├── tokens.json # Design tokens (colors, fonts, spacing)
47
+ ├── styles.css # CSS component overrides
48
+ ├── fonts/ # Custom font files (add .woff2 files here)
49
+ └── README.md # Documentation
50
+ ```
51
+
52
+ ### Plugin format (--plugin)
53
+
37
54
  ```
38
55
  qtap-plugin-theme-my-theme/
39
56
  ├── package.json # npm package configuration
@@ -57,6 +74,7 @@ qtap-plugin-theme-my-theme/
57
74
 
58
75
  | Option | Description |
59
76
  |--------|-------------|
77
+ | `--plugin` | Create a legacy npm plugin instead of a bundle |
60
78
  | `-y, --yes` | Skip prompts and use default values |
61
79
  | `-h, --help` | Show help message |
62
80
 
@@ -69,38 +87,49 @@ When run without `--yes`, you'll be asked:
69
87
  3. **Author name** - Your name
70
88
  4. **Author email** - Your email
71
89
  5. **Primary color** - Main theme color in HSL format
72
- 6. **Include CSS overrides?** - Whether to create styles.css
73
- 7. **Include Storybook?** - Whether to set up Storybook for development
90
+ 6. **Include CSS overrides?** - Whether to create styles.css (bundle and plugin)
91
+ 7. **Include Storybook?** - Whether to set up Storybook for development (plugin only)
74
92
 
75
93
  ## Next steps after scaffolding
76
94
 
95
+ ### Bundle themes
96
+
77
97
  ```bash
78
- cd qtap-plugin-theme-my-theme
79
- npm install
80
- npm run build
98
+ cd my-theme
99
+ # Edit theme.json, tokens.json, and styles.css
100
+ # Then install into Quilltap:
101
+ npx quilltap themes install .
102
+ # Or validate first:
103
+ npx quilltap themes validate .
81
104
  ```
82
105
 
83
- To preview in Storybook (if included):
106
+ ### Plugin themes (deprecated)
84
107
 
85
108
  ```bash
86
- npm run storybook
109
+ cd qtap-plugin-theme-my-theme
110
+ npm install
111
+ npm run build
112
+ npm publish --access public
87
113
  ```
88
114
 
89
- To publish:
115
+ ## Managing themes via CLI
90
116
 
91
117
  ```bash
92
- npm publish --access public
118
+ npx quilltap themes list # List all installed themes
119
+ npx quilltap themes install my.qtap-theme # Install a bundle
120
+ npx quilltap themes validate my.qtap-theme # Validate without installing
121
+ npx quilltap themes export earl-grey # Export any theme as a bundle
122
+ npx quilltap themes search "dark" # Search registries
123
+ npx quilltap themes update # Check for updates
93
124
  ```
94
125
 
95
126
  ## Documentation
96
127
 
97
- Every scaffolded theme includes a complete development guide at `docs/THEME_PLUGIN_DEVELOPMENT.md`.
98
-
99
128
  For the latest online documentation:
100
129
 
101
- - [Theme Plugin Development Guide](https://github.com/foundry-9/quilltap/blob/main/docs/THEME_PLUGIN_DEVELOPMENT.md)
130
+ - [Theme Plugin Development Guide](https://github.com/foundry-9/quilltap/blob/main/docs/THEME_PLUGIN_DEVELOPMENT.md) (legacy plugin format)
102
131
  - [Plugin Manifest Reference](https://github.com/foundry-9/quilltap/blob/main/docs/PLUGIN_MANIFEST.md)
103
- - [@quilltap/theme-storybook](https://www.npmjs.com/package/@quilltap/theme-storybook)
132
+ - [@quilltap/theme-storybook](https://www.npmjs.com/package/@quilltap/theme-storybook) (for plugin development with Storybook)
104
133
 
105
134
  ## License
106
135
 
package/dist/index.js CHANGED
@@ -96,13 +96,64 @@ function copyTemplate(templateName, destPath, config, destName) {
96
96
  const content = processTemplate(templatePath, config);
97
97
  fs.writeFileSync(finalDestPath, content, "utf-8");
98
98
  }
99
- async function scaffold(config) {
99
+ async function scaffoldBundle(config) {
100
+ const destPath = path.resolve(process.cwd(), config.themeId);
101
+ if (fs.existsSync(destPath)) {
102
+ error(`Directory "${config.themeId}" already exists.`);
103
+ process.exit(1);
104
+ }
105
+ heading("Creating your Quilltap theme bundle...");
106
+ fs.mkdirSync(destPath, { recursive: true });
107
+ success(`Created ${config.themeId}/`);
108
+ copyTemplate("bundle/theme.json.template", destPath, config, "theme.json");
109
+ success("Created theme.json");
110
+ copyTemplate("tokens.json.template", destPath, config, "tokens.json");
111
+ success("Created tokens.json");
112
+ if (config.includeCssOverrides) {
113
+ copyTemplate("bundle/styles.css.template", destPath, config, "styles.css");
114
+ success("Created styles.css");
115
+ }
116
+ copyTemplate("bundle/README.md.template", destPath, config, "README.md");
117
+ success("Created README.md");
118
+ const fontsDir = path.join(destPath, "fonts");
119
+ fs.mkdirSync(fontsDir, { recursive: true });
120
+ fs.writeFileSync(
121
+ path.join(fontsDir, ".gitkeep"),
122
+ "# Place custom .woff2 font files here and reference them in theme.json\n",
123
+ "utf-8"
124
+ );
125
+ success("Created fonts/");
126
+ heading("Done! Next steps:");
127
+ log(` ${colors.dim}# Edit your theme:${colors.reset}`);
128
+ log(` ${colors.cyan}cd ${config.themeId}${colors.reset}`);
129
+ log(` ${colors.dim}# Edit tokens.json to customize colors, typography, and spacing${colors.reset}`);
130
+ if (config.includeCssOverrides) {
131
+ log(` ${colors.dim}# Edit styles.css for advanced component styling${colors.reset}`);
132
+ }
133
+ log("");
134
+ log(` ${colors.dim}# To install in Quilltap:${colors.reset}`);
135
+ log(` ${colors.cyan}cd ${config.themeId} && zip -r ../${config.themeId}.qtap-theme .${colors.reset}`);
136
+ log(` ${colors.dim}# Then upload the .qtap-theme file in Settings > Appearance > Install Theme${colors.reset}`);
137
+ log("");
138
+ log(` ${colors.dim}# Or install via CLI:${colors.reset}`);
139
+ log(` ${colors.cyan}quilltap themes install ${config.themeId}.qtap-theme${colors.reset}`);
140
+ log("");
141
+ log(` ${colors.dim}# Validate your bundle:${colors.reset}`);
142
+ log(` ${colors.cyan}quilltap themes validate ${config.themeId}.qtap-theme${colors.reset}`);
143
+ log("");
144
+ info("No build tools required \u2014 just edit JSON and CSS files!");
145
+ log("");
146
+ }
147
+ async function scaffoldPlugin(config) {
100
148
  const destPath = path.resolve(process.cwd(), config.themeName);
101
149
  if (fs.existsSync(destPath)) {
102
150
  error(`Directory "${config.themeName}" already exists.`);
103
151
  process.exit(1);
104
152
  }
105
153
  heading("Creating your Quilltap theme plugin...");
154
+ log(` ${colors.yellow}Note: npm plugin format is deprecated. Consider using bundle format instead.${colors.reset}`);
155
+ log(` ${colors.dim}Run without --plugin to create a .qtap-theme bundle.${colors.reset}`);
156
+ log("");
106
157
  fs.mkdirSync(destPath, { recursive: true });
107
158
  success(`Created ${config.themeName}/`);
108
159
  copyTemplate("package.json.template", destPath, config, "package.json");
@@ -170,20 +221,23 @@ function parseArgs() {
170
221
  let themeName;
171
222
  let help = false;
172
223
  let yes = false;
224
+ let plugin = false;
173
225
  for (const arg of args) {
174
226
  if (arg === "-h" || arg === "--help") {
175
227
  help = true;
176
228
  } else if (arg === "-y" || arg === "--yes") {
177
229
  yes = true;
230
+ } else if (arg === "--plugin") {
231
+ plugin = true;
178
232
  } else if (!arg.startsWith("-")) {
179
233
  themeName = arg;
180
234
  }
181
235
  }
182
- return { themeName, help, yes };
236
+ return { themeName, help, yes, plugin };
183
237
  }
184
238
  function showHelp() {
185
239
  log(`
186
- ${colors.bold}create-quilltap-theme${colors.reset} - Scaffold a new Quilltap theme plugin
240
+ ${colors.bold}create-quilltap-theme${colors.reset} - Scaffold a new Quilltap theme
187
241
 
188
242
  ${colors.bold}Usage:${colors.reset}
189
243
  npm init quilltap-theme [theme-name] [options]
@@ -193,38 +247,45 @@ ${colors.bold}Arguments:${colors.reset}
193
247
  theme-name Name for your theme (e.g., "sunset", "ocean-breeze")
194
248
 
195
249
  ${colors.bold}Options:${colors.reset}
196
- -y, --yes Skip prompts and use defaults
197
- -h, --help Show this help message
250
+ -y, --yes Skip prompts and use defaults
251
+ --plugin Create an npm plugin theme (deprecated, use bundle instead)
252
+ -h, --help Show this help message
198
253
 
199
254
  ${colors.bold}Examples:${colors.reset}
200
- npm init quilltap-theme my-theme
201
- npx create-quilltap-theme sunset --yes
202
- npm init quilltap-theme
255
+ npm init quilltap-theme my-theme # Create a .qtap-theme bundle (recommended)
256
+ npx create-quilltap-theme sunset --yes # Bundle with defaults
257
+ npx create-quilltap-theme sunset --plugin # Legacy npm plugin format
258
+
259
+ ${colors.bold}Bundle format (default):${colors.reset}
260
+ <theme-name>/
261
+ \u251C\u2500\u2500 theme.json # Theme manifest
262
+ \u251C\u2500\u2500 tokens.json # Design tokens
263
+ \u251C\u2500\u2500 styles.css # CSS overrides (optional)
264
+ \u251C\u2500\u2500 fonts/ # Custom fonts (optional)
265
+ \u2514\u2500\u2500 README.md # Documentation
266
+
267
+ No build tools required! Just edit JSON/CSS and zip to install.
203
268
 
204
- ${colors.bold}What gets created:${colors.reset}
269
+ ${colors.bold}Plugin format (deprecated):${colors.reset}
205
270
  qtap-plugin-theme-<name>/
206
- \u251C\u2500\u2500 package.json # npm package config
207
- \u251C\u2500\u2500 manifest.json # Quilltap plugin manifest
208
- \u251C\u2500\u2500 tokens.json # Theme design tokens
209
- \u251C\u2500\u2500 index.ts # Plugin entry point
210
- \u251C\u2500\u2500 styles.css # CSS overrides (optional)
211
- \u251C\u2500\u2500 tsconfig.json # TypeScript config
212
- \u251C\u2500\u2500 esbuild.config.mjs # Build config
213
- \u251C\u2500\u2500 README.md # Documentation
214
- \u251C\u2500\u2500 docs/ # Development guide
215
- \u2502 \u2514\u2500\u2500 THEME_PLUGIN_DEVELOPMENT.md
216
- \u2514\u2500\u2500 .storybook/ # Storybook setup (optional)
271
+ \u251C\u2500\u2500 package.json, manifest.json, index.ts, tokens.json, ...
272
+ Requires npm, esbuild, TypeScript. Use --plugin flag.
217
273
  `);
218
274
  }
219
275
  async function main() {
220
- const { themeName: argThemeName, help, yes } = parseArgs();
276
+ const { themeName: argThemeName, help, yes, plugin } = parseArgs();
221
277
  if (help) {
222
278
  showHelp();
223
279
  process.exit(0);
224
280
  }
281
+ const mode = plugin ? "plugin" : "bundle";
225
282
  log("");
226
283
  log(`${colors.bold}${colors.blue} create-quilltap-theme${colors.reset}`);
227
- log(`${colors.dim} Scaffold a new Quilltap theme plugin${colors.reset}`);
284
+ if (mode === "bundle") {
285
+ log(`${colors.dim} Scaffold a new Quilltap theme bundle (.qtap-theme)${colors.reset}`);
286
+ } else {
287
+ log(`${colors.dim} Scaffold a new Quilltap theme plugin ${colors.yellow}(deprecated)${colors.reset}`);
288
+ }
228
289
  log("");
229
290
  const rl = readline.createInterface({
230
291
  input: process.stdin,
@@ -258,10 +319,10 @@ async function main() {
258
319
  authorEmail = await prompt(rl, "Author email", "you@example.com");
259
320
  primaryColor = await prompt(rl, "Primary color (HSL)", "hsl(220 90% 50%)");
260
321
  includeCssOverrides = await promptYesNo(rl, "Include CSS overrides (styles.css)?", true);
261
- includeStorybook = await promptYesNo(rl, "Include Storybook setup?", false);
322
+ includeStorybook = mode === "plugin" ? await promptYesNo(rl, "Include Storybook setup?", false) : false;
262
323
  }
263
324
  const config = {
264
- themeName: packageName,
325
+ themeName: mode === "bundle" ? themeId : packageName,
265
326
  packageName,
266
327
  themeId,
267
328
  displayName,
@@ -270,9 +331,14 @@ async function main() {
270
331
  authorEmail,
271
332
  primaryColor,
272
333
  includeCssOverrides,
273
- includeStorybook
334
+ includeStorybook,
335
+ mode
274
336
  };
275
- await scaffold(config);
337
+ if (mode === "bundle") {
338
+ await scaffoldBundle(config);
339
+ } else {
340
+ await scaffoldPlugin(config);
341
+ }
276
342
  } finally {
277
343
  rl.close();
278
344
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-quilltap-theme",
3
- "version": "1.0.6",
3
+ "version": "2.0.1",
4
4
  "description": "Scaffold a new Quilltap theme plugin",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -35,7 +35,7 @@
35
35
  "node": ">=18.0.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@types/node": "^22.19.7",
38
+ "@types/node": "^22.19.15",
39
39
  "esbuild": "^0.27.0",
40
40
  "typescript": "^5.0.0"
41
41
  }
@@ -0,0 +1,46 @@
1
+ # {{DISPLAY_NAME}}
2
+
3
+ A custom theme for Quilltap.
4
+
5
+ ## Format
6
+
7
+ This is a `.qtap-theme` bundle — a simple directory (or zip archive) containing design tokens, CSS overrides, and optional font files. No build tools, npm packages, or JavaScript code required.
8
+
9
+ ## Structure
10
+
11
+ ```
12
+ {{THEME_ID}}/
13
+ ├── theme.json # Theme manifest with metadata
14
+ ├── tokens.json # Design tokens (colors, typography, spacing, effects)
15
+ ├── styles.css # CSS overrides (optional)
16
+ ├── fonts/ # Custom font files (optional)
17
+ └── README.md # This file
18
+ ```
19
+
20
+ ## Editing
21
+
22
+ - **Colors**: Edit `tokens.json` → `colors.light` and `colors.dark` sections
23
+ - **Typography**: Edit `tokens.json` → `typography` section
24
+ - **Spacing/Radius**: Edit `tokens.json` → `spacing` section
25
+ - **Component styles**: Edit `styles.css` for custom CSS overrides
26
+ - **Custom fonts**: Add `.woff2` files to `fonts/` and reference them in `theme.json`
27
+
28
+ ## Installing
29
+
30
+ ### From directory
31
+ Zip this directory and upload the `.qtap-theme` file in Quilltap Settings > Appearance > Install Theme.
32
+
33
+ ### From CLI
34
+ ```bash
35
+ # Pack as .qtap-theme
36
+ cd {{THEME_ID}} && zip -r ../{{THEME_ID}}.qtap-theme .
37
+
38
+ # Install
39
+ quilltap themes install {{THEME_ID}}.qtap-theme
40
+ ```
41
+
42
+ ## Validating
43
+
44
+ ```bash
45
+ quilltap themes validate {{THEME_ID}}.qtap-theme
46
+ ```
@@ -0,0 +1,33 @@
1
+ /**
2
+ * {{DISPLAY_NAME}} - CSS Overrides
3
+ *
4
+ * Custom CSS overrides for the {{DISPLAY_NAME}} theme.
5
+ * These styles are applied on top of the design tokens defined in tokens.json.
6
+ *
7
+ * Available CSS custom properties (set from tokens.json):
8
+ * --qt-bg, --qt-fg, --qt-primary, --qt-accent, etc.
9
+ * --qt-font-sans, --qt-font-serif, --qt-font-mono
10
+ * --qt-radius-sm, --qt-radius-md, --qt-radius-lg
11
+ * --qt-shadow-sm, --qt-shadow-md, --qt-shadow-lg
12
+ *
13
+ * Tips:
14
+ * - Use qt-* CSS custom properties for theme-aware styling
15
+ * - Override specific components by targeting their qt-* class names
16
+ * - Keep overrides minimal; prefer tokens.json for color/spacing changes
17
+ */
18
+
19
+ /* Example: custom heading styles */
20
+ /*
21
+ .qt-heading {
22
+ letter-spacing: 0.05em;
23
+ text-transform: uppercase;
24
+ }
25
+ */
26
+
27
+ /* Example: custom card styling */
28
+ /*
29
+ .qt-card {
30
+ border: 2px solid var(--qt-border);
31
+ box-shadow: var(--qt-shadow-md);
32
+ }
33
+ */
@@ -0,0 +1,14 @@
1
+ {
2
+ "format": "qtap-theme",
3
+ "formatVersion": 1,
4
+ "id": "{{THEME_ID}}",
5
+ "name": "{{DISPLAY_NAME}}",
6
+ "description": "{{DESCRIPTION}}",
7
+ "version": "1.0.0",
8
+ "author": "{{AUTHOR_NAME}}",
9
+ "license": "MIT",
10
+ "supportsDarkMode": true,
11
+ "tags": [],
12
+ "tokensPath": "tokens.json",
13
+ "stylesPath": "styles.css"
14
+ }
@@ -560,7 +560,7 @@ For advanced customization, create `styles.css` with component overrides. This u
560
560
  | `.qt-button`, `.qt-button-primary`, `.qt-button-secondary`, `.qt-button-ghost`, `.qt-button-destructive` | Button variants |
561
561
  | `.qt-button-sm`, `.qt-button-lg`, `.qt-button-icon` | Button sizes |
562
562
  | `.qt-card`, `.qt-card-header`, `.qt-card-body`, `.qt-card-footer` | Card components |
563
- | `.qt-card-interactive`, `.qt-entity-card`, `.qt-panel` | Card variants |
563
+ | `.qt-card-interactive`, `.qt-entity-card`, `.qt-character-card`, `.qt-panel` | Card variants |
564
564
  | `.qt-input`, `.qt-textarea`, `.qt-select` | Form inputs |
565
565
  | `.qt-badge`, `.qt-badge-primary`, `.qt-badge-secondary`, `.qt-badge-outline` | Badges |
566
566
  | `.qt-avatar`, `.qt-avatar-sm`, `.qt-avatar-lg`, `.qt-avatar-xl` | Avatars |
@@ -588,6 +588,7 @@ Override these variables for consistent component styling:
588
588
  --qt-card-padding
589
589
  --qt-card-shadow
590
590
  --qt-card-border
591
+ --qt-character-card-padding
591
592
 
592
593
  /* Inputs */
593
594
  --qt-input-radius