@svgrid/ui 0.3.1 → 0.3.3
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 +5 -3
- package/index.mjs +75 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,9 +30,11 @@ npx @svgrid/ui add button --preview
|
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
`try` needs no project - it caches a tiny Vite + Svelte sandbox under your temp
|
|
33
|
-
dir (so repeat runs are instant) and opens the browser
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
dir (so repeat runs are instant) and opens the browser, with a **theme picker
|
|
34
|
+
(all 19 presets) and a light/dark toggle** so you can see the component in your
|
|
35
|
+
target theme. `--preview` drops a `src/routes/preview/<id>` page (plus a
|
|
36
|
+
`/preview` index) into an existing SvelteKit app so it renders in your running
|
|
37
|
+
dev server.
|
|
36
38
|
|
|
37
39
|
## Usage
|
|
38
40
|
|
package/index.mjs
CHANGED
|
@@ -345,26 +345,30 @@ async function cmdAdd(registry, tokens, args) {
|
|
|
345
345
|
return
|
|
346
346
|
}
|
|
347
347
|
|
|
348
|
-
//
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
if (
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
348
|
+
// Install the dependency - only meaningful inside a project (on by default;
|
|
349
|
+
// --no-install just prints the command). `add` writes into an EXISTING app;
|
|
350
|
+
// a no-project run is handled in the next-steps block below.
|
|
351
|
+
if (projectRoot) {
|
|
352
|
+
const pm = detectPm(projectRoot)
|
|
353
|
+
const added = await ensureDeps(projectRoot, [...deps])
|
|
354
|
+
if (added.length) {
|
|
355
|
+
if (args.install) {
|
|
356
|
+
stdout.write(`\n${color('dim', `Installing with ${pm.id}...`)}\n`)
|
|
357
|
+
// Single shell string (not bin + args[]) so Node doesn't warn DEP0190
|
|
358
|
+
// under shell:true; the tokens here are fixed pm commands + npm package ids.
|
|
359
|
+
const res = spawnSync(`${pm.add} ${added.join(' ')}`, { cwd: projectRoot, stdio: 'inherit', shell: true })
|
|
360
|
+
if (res.status !== 0) {
|
|
361
|
+
stdout.write(`${color('yellow', '!')} Install failed - run it yourself: ${color('cyan', `${pm.add} ${added.join(' ')}`)}\n`)
|
|
362
|
+
}
|
|
363
|
+
} else {
|
|
364
|
+
stdout.write(`\n${color('bold', 'Install the dependency')}\n ${color('cyan', `${pm.add} ${added.join(' ')}`)}\n`)
|
|
359
365
|
}
|
|
360
|
-
} else {
|
|
361
|
-
stdout.write(`\n${color('
|
|
366
|
+
} else if ([...deps].length) {
|
|
367
|
+
stdout.write(`\n${color('dim', `${[...deps].join(', ')} already in package.json.`)}\n`)
|
|
362
368
|
}
|
|
363
|
-
} else if ([...deps].length) {
|
|
364
|
-
stdout.write(`\n${color('dim', `${[...deps].join(', ')} already in package.json.`)}\n`)
|
|
365
369
|
}
|
|
366
370
|
|
|
367
|
-
// Optional preview route(s).
|
|
371
|
+
// Optional preview route(s) - needs a SvelteKit project.
|
|
368
372
|
if (args.preview) {
|
|
369
373
|
if (isSvelteKit(projectRoot)) {
|
|
370
374
|
const urls = await writePreviewRoutes(projectRoot, dest, items, args.force)
|
|
@@ -378,14 +382,22 @@ async function cmdAdd(registry, tokens, args) {
|
|
|
378
382
|
}
|
|
379
383
|
}
|
|
380
384
|
|
|
381
|
-
// Next steps
|
|
385
|
+
// Next steps.
|
|
382
386
|
const first = items[0]
|
|
387
|
+
const ids = items.map((it) => it.id).join(' ')
|
|
383
388
|
stdout.write(`\n${color('green', '✔')} Added ${written.length} file(s). They're yours - edit away.\n`)
|
|
384
|
-
if (
|
|
389
|
+
if (!projectRoot) {
|
|
390
|
+
// A lone component file with no app to run it - `add` targets an existing
|
|
391
|
+
// project. Point at the two real paths instead of leaving a stranded file.
|
|
392
|
+
stdout.write(
|
|
393
|
+
` ${color('yellow', 'Heads up:')} no package.json here, so there's nothing to run this in yet.\n` +
|
|
394
|
+
` ${color('dim', 'See it now:')} ${color('cyan', `npx @svgrid/ui try ${ids}`)} ${color('dim', '(no project needed)')}\n` +
|
|
395
|
+
` ${color('dim', 'Start an app:')} ${color('cyan', 'npm create @svgrid@latest')} ${color('dim', '(then run add inside it)')}\n`,
|
|
396
|
+
)
|
|
397
|
+
} else {
|
|
385
398
|
stdout.write(` ${color('dim', 'Use it:')} import { ${exportName(first.id)} } from '@svgrid/grid'\n`)
|
|
386
399
|
// "See it" - skip when we already wrote preview routes just above.
|
|
387
400
|
if (!(args.preview && isSvelteKit(projectRoot))) {
|
|
388
|
-
const ids = items.map((it) => it.id).join(' ')
|
|
389
401
|
stdout.write(` ${color('dim', 'See it:')} ${color('cyan', `npx @svgrid/ui try ${ids}`)} ${color('dim', '(opens in your browser)')}\n`)
|
|
390
402
|
if (isSvelteKit(projectRoot)) {
|
|
391
403
|
stdout.write(` ${color('dim', 'In app:')} re-run with ${color('cyan', '--preview')} to add a /preview/${first.id} route\n`)
|
|
@@ -459,23 +471,58 @@ async function cmdTry(registry, tokens) {
|
|
|
459
471
|
await writeFile(
|
|
460
472
|
join(src, 'App.svelte'),
|
|
461
473
|
`<script lang="ts">
|
|
474
|
+
import { themePresets, resolveThemeTokens } from '@svgrid/grid/themes'
|
|
462
475
|
${imports.join('\n')}
|
|
476
|
+
|
|
477
|
+
let themeId = $state(themePresets[0].id)
|
|
478
|
+
let mode = $state<'light' | 'dark'>('light')
|
|
479
|
+
const preset = $derived(themePresets.find((p) => p.id === themeId) ?? themePresets[0])
|
|
480
|
+
|
|
481
|
+
// Apply the chosen preset + light/dark as --sg-* tokens on :root, the same way
|
|
482
|
+
// the shipped themes/<id>.css files do (light in :root, dark under data-theme),
|
|
483
|
+
// so both the components and this page follow the picker.
|
|
484
|
+
$effect(() => {
|
|
485
|
+
const tokens = resolveThemeTokens(preset, mode)
|
|
486
|
+
const root = document.documentElement
|
|
487
|
+
for (const [k, v] of Object.entries(tokens)) root.style.setProperty(k, v)
|
|
488
|
+
root.setAttribute('data-theme', mode)
|
|
489
|
+
root.style.colorScheme = mode
|
|
490
|
+
})
|
|
463
491
|
</script>
|
|
464
492
|
|
|
493
|
+
<header class="svui-try__bar">
|
|
494
|
+
<strong class="svui-try__brand">@svgrid/ui preview</strong>
|
|
495
|
+
<div class="svui-try__controls">
|
|
496
|
+
<label class="svui-try__field">
|
|
497
|
+
Theme
|
|
498
|
+
<select bind:value={themeId}>
|
|
499
|
+
{#each themePresets as p (p.id)}<option value={p.id}>{p.name}</option>{/each}
|
|
500
|
+
</select>
|
|
501
|
+
</label>
|
|
502
|
+
<button type="button" class="svui-try__toggle" onclick={() => (mode = mode === 'light' ? 'dark' : 'light')}>
|
|
503
|
+
{mode === 'light' ? 'Dark' : 'Light'} mode
|
|
504
|
+
</button>
|
|
505
|
+
</div>
|
|
506
|
+
</header>
|
|
507
|
+
|
|
465
508
|
<main class="svui-try">
|
|
466
|
-
<
|
|
467
|
-
<strong>@svgrid/ui preview</strong>
|
|
468
|
-
<span>${esc(items.map((i) => i.id).join(', '))}</span>
|
|
469
|
-
</header>
|
|
509
|
+
<p class="svui-try__sub">${esc(items.map((i) => i.id).join(', '))}</p>
|
|
470
510
|
${sections.join('\n')}
|
|
471
511
|
</main>
|
|
472
512
|
|
|
473
513
|
<style>
|
|
474
|
-
:global(body) { margin: 0; background: #f8fafc; }
|
|
475
|
-
.svui-
|
|
476
|
-
.svui-
|
|
477
|
-
.svui-
|
|
478
|
-
.svui-
|
|
514
|
+
:global(body) { margin: 0; background: var(--sg-bg, #f8fafc); color: var(--sg-fg, #0f172a); transition: background 0.15s, color 0.15s; }
|
|
515
|
+
.svui-try__bar { position: sticky; top: 0; z-index: 10; display: flex; justify-content: space-between; align-items: center; gap: 16px; padding: 12px 24px; background: var(--sg-header-bg, #fff); border-bottom: 1px solid var(--sg-border, #e2e8f0); }
|
|
516
|
+
.svui-try__brand { font-size: 13px; color: var(--sg-muted, #64748b); }
|
|
517
|
+
.svui-try__controls { display: flex; align-items: center; gap: 12px; }
|
|
518
|
+
.svui-try__field { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--sg-muted, #64748b); }
|
|
519
|
+
.svui-try__field select { font: inherit; padding: 5px 8px; border-radius: 8px; border: 1px solid var(--sg-border, #cbd5e1); background: var(--sg-bg, #fff); color: var(--sg-fg, #0f172a); }
|
|
520
|
+
.svui-try__toggle { font: inherit; font-size: 12px; padding: 6px 12px; border-radius: 8px; cursor: pointer; border: 1px solid var(--sg-border, #cbd5e1); background: var(--sg-bg, #fff); color: var(--sg-fg, #0f172a); }
|
|
521
|
+
.svui-try__toggle:hover { border-color: var(--sg-accent, #6366f1); }
|
|
522
|
+
.svui-try { max-width: 960px; margin: 0 auto; padding: 24px; font-family: system-ui, sans-serif; }
|
|
523
|
+
.svui-try__sub { margin: 0 0 20px; font-size: 12px; color: var(--sg-muted, #64748b); }
|
|
524
|
+
.svui-try__item { padding: 28px; border: 1px solid var(--sg-border, #e2e8f0); border-radius: 12px; background: var(--sg-bg, #fff); margin-bottom: 16px; }
|
|
525
|
+
.svui-try__item h2 { margin: 0 0 16px; font-size: 15px; color: var(--sg-muted, #334155); }
|
|
479
526
|
</style>
|
|
480
527
|
`,
|
|
481
528
|
)
|
package/package.json
CHANGED