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
|
|
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
|
|
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
|
|
197
|
-
|
|
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
|
-
|
|
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}
|
|
269
|
+
${colors.bold}Plugin format (deprecated):${colors.reset}
|
|
205
270
|
qtap-plugin-theme-<name>/
|
|
206
|
-
\u251C\u2500\u2500 package.json
|
|
207
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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": "
|
|
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": "^
|
|
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
|
+
}
|