create-quilltap-theme 1.0.6 → 2.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/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.0",
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": "^24.10.13",
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
+ }