@xanots/sdk 0.0.2 → 0.0.3-beta.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/README.md +10 -1
- package/dist/.build-fingerprint +1 -1
- package/dist/{agent-file-refresh-7XCACU34.js → agent-file-refresh-J3KY54E5.js} +3 -2
- package/dist/bin.js +7 -7
- package/dist/chunk-4HKZH6YK.js +307 -0
- package/dist/chunk-6DHJVLYP.js +2044 -0
- package/dist/{chunk-MUDLJG2O.js → chunk-CBL57QBQ.js} +25 -15
- package/dist/{chunk-5YTBTF25.js → chunk-EWFHDJY5.js} +2 -2
- package/dist/{chunk-IZW6MK3U.js → chunk-FY6LXRR6.js} +2 -2
- package/dist/{chunk-ZPEY5WE4.js → chunk-HKAX756N.js} +3 -3
- package/dist/{chunk-XLD4BUTF.js → chunk-MWLNBSTY.js} +2 -2
- package/dist/{chunk-YYRDLFSJ.js → chunk-QO4I5OYF.js} +40 -2
- package/dist/{chunk-UVLVQWWF.js → chunk-VVXPK6SE.js} +62 -20
- package/dist/{chunk-VKFQJEMW.js → chunk-WRYT2PAX.js} +14 -371
- package/dist/{chunk-ODNMVJ6H.js → chunk-YZ4GU6F5.js} +283 -252
- package/dist/cli.d.ts +22 -0
- package/dist/cli.js +5 -5
- package/dist/{codegen-command-RY2GWDLX.js → codegen-command-EXLKZ2ZI.js} +12 -10
- package/dist/{completion-TIPPZN7H.js → completion-2PVZK6YX.js} +2 -2
- package/dist/{deploy-command-DSISLUW5.js → deploy-command-SXX6RJWM.js} +13 -13
- package/dist/{env-target-7C2GKBCY.js → env-target-3EGIPR4D.js} +2 -2
- package/dist/{ephemeral-command-5K573ZSG.js → ephemeral-command-OGOYP7D6.js} +15 -15
- package/dist/{init-command-4AWL6CLW.js → init-command-6DGXEVZD.js} +10 -8
- package/dist/internal.js +1 -1
- package/dist/{lock-commands-7Q5LNZKL.js → lock-commands-R22J54XV.js} +9 -9
- package/dist/{marketplace-command-RATXTKXN.js → marketplace-command-XJIWL4YP.js} +6 -6
- package/dist/meta-client-OW5WKWW7.js +1 -1
- package/dist/node.js +8 -8
- package/dist/{release-command-QXLRJMY7.js → release-command-6PLMLGDK.js} +15 -15
- package/dist/sandbox-export-command-QCJY4GMV.js +1 -1
- package/dist/scaffold.d.ts +1896 -0
- package/dist/scaffold.js +101 -0
- package/dist/{test-command-BOLIU57E.js → test-command-LLPXKT35.js} +4 -4
- package/dist/{validate-command-SYCFEYZN.js → validate-command-WAT3ZJT3.js} +7 -7
- package/dist/{workspace-command-TOB2AJ6X.js → workspace-command-JKMI7RZ4.js} +13 -11
- package/dist/workspace-export-AJMGN3CQ.js +1 -1
- package/llms-full.txt +1 -1
- package/llms.txt +1 -1
- package/manifest.json +141 -1
- package/package.json +7 -1
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
blank,
|
|
12
|
-
detail,
|
|
13
|
-
info,
|
|
14
|
-
step,
|
|
15
|
-
style,
|
|
16
|
-
success
|
|
17
|
-
} from "./chunk-EZG76F7R.js";
|
|
18
|
-
|
|
19
|
-
// src/emit/init-command.ts
|
|
20
|
-
import { basename, resolve } from "path";
|
|
2
|
+
colorTokens,
|
|
3
|
+
defaultThemeChoice,
|
|
4
|
+
fontDependencies,
|
|
5
|
+
fontImports,
|
|
6
|
+
fontThemeVars,
|
|
7
|
+
iconLibraryOf,
|
|
8
|
+
orderedTokens,
|
|
9
|
+
reactPreset
|
|
10
|
+
} from "./chunk-6DHJVLYP.js";
|
|
21
11
|
|
|
22
12
|
// src/emit/init-templates.ts
|
|
23
13
|
function sdkDep(sdkVersion) {
|
|
@@ -27,7 +17,7 @@ function sdkDep(sdkVersion) {
|
|
|
27
17
|
const ceiling = major > 0 ? `${major + 1}.0.0` : `0.${minor + 1}.0`;
|
|
28
18
|
return `>=${sdkVersion} <${ceiling}`;
|
|
29
19
|
}
|
|
30
|
-
function renderPackageJson({ appName, sdkVersion }, preset) {
|
|
20
|
+
function renderPackageJson({ appName, sdkVersion }, preset, choice = defaultThemeChoice()) {
|
|
31
21
|
const check = preset.checkCmd;
|
|
32
22
|
const pkg = {
|
|
33
23
|
name: appName,
|
|
@@ -76,7 +66,13 @@ function renderPackageJson({ appName, sdkVersion }, preset) {
|
|
|
76
66
|
// on demand — a project that never registers auth should not carry it,
|
|
77
67
|
// and an add-on's release cadence is its own, not the CLI's.
|
|
78
68
|
"@xanots/sdk": sdkDep(sdkVersion),
|
|
79
|
-
...preset.dependencies
|
|
69
|
+
...preset.dependencies,
|
|
70
|
+
// The icon set and the typefaces are choices, not framework constants, so
|
|
71
|
+
// they are merged here rather than sitting in `preset.dependencies`. Both
|
|
72
|
+
// land after the preset's own entries: a preset that still names an icon
|
|
73
|
+
// package would otherwise win over the set the user actually picked.
|
|
74
|
+
...preset.iconBinding(choice.icons).dependency,
|
|
75
|
+
...fontDependencies(choice.fonts)
|
|
80
76
|
},
|
|
81
77
|
devDependencies: { ...preset.devDependencies },
|
|
82
78
|
// Not ">=20": Vite 8 and vite-plugin-svelte 7 both declare
|
|
@@ -163,7 +159,7 @@ function renderInlineObject(obj) {
|
|
|
163
159
|
const entries = Object.entries(obj).map(([k, v]) => `${k}: ${JSON.stringify(v)}`);
|
|
164
160
|
return entries.length === 0 ? "{}" : `{ ${entries.join(", ")} }`;
|
|
165
161
|
}
|
|
166
|
-
function renderIndexHtml({ appName }, preset) {
|
|
162
|
+
function renderIndexHtml({ appName }, preset, choice = defaultThemeChoice()) {
|
|
167
163
|
if (preset.entryScript === void 0) {
|
|
168
164
|
throw new Error(`The ${preset.id} preset owns its own HTML entry; renderIndexHtml does not apply.`);
|
|
169
165
|
}
|
|
@@ -173,7 +169,7 @@ function renderIndexHtml({ appName }, preset) {
|
|
|
173
169
|
<meta charset="UTF-8" />
|
|
174
170
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
175
171
|
<title>${appName}</title>
|
|
176
|
-
</head>
|
|
172
|
+
${renderThemeScript(choice.dark)} </head>
|
|
177
173
|
<body>
|
|
178
174
|
<div id="root"></div>
|
|
179
175
|
<script type="module" src="${preset.entryScript}"></script>
|
|
@@ -203,7 +199,7 @@ function renderEnvExample() {
|
|
|
203
199
|
VITE_XANO_HOST=https://your-instance.xano.io
|
|
204
200
|
`;
|
|
205
201
|
}
|
|
206
|
-
function renderReadme({ appName }, preset) {
|
|
202
|
+
function renderReadme({ appName }, preset, choice = defaultThemeChoice()) {
|
|
207
203
|
return `# ${appName}
|
|
208
204
|
|
|
209
205
|
A [XanoTS](https://www.npmjs.com/package/@xanots/sdk) project: a Xano
|
|
@@ -277,7 +273,9 @@ body \u2014 change a def and the frontend types follow.
|
|
|
277
273
|
|
|
278
274
|
## The frontend
|
|
279
275
|
|
|
280
|
-
${preset.readmeFrontendSection()}
|
|
276
|
+
${preset.readmeFrontendSection(choice.icons)}
|
|
277
|
+
|
|
278
|
+
${renderReadmeThemingSection(choice)}
|
|
281
279
|
|
|
282
280
|
## Add-ons
|
|
283
281
|
|
|
@@ -566,6 +564,44 @@ npx xanots paths xano/index.ts # list every endpoint's verb + path
|
|
|
566
564
|
request paths and types from the query defs in \`xano/\` rather than hand-typing a URL.
|
|
567
565
|
`;
|
|
568
566
|
}
|
|
567
|
+
function renderReadmeThemingSection(choice) {
|
|
568
|
+
const { theme, dark } = choice;
|
|
569
|
+
const darkNote = {
|
|
570
|
+
system: `Dark mode follows the OS. An inline script in the HTML entry sets
|
|
571
|
+
\`class="dark"\` on \`<html>\` before first paint (so the page never flashes light
|
|
572
|
+
first), and the \`.dark\` block in the stylesheet supplies the palette. To let
|
|
573
|
+
people override it, add a control that toggles that class \u2014 or scaffold your
|
|
574
|
+
next project with \`--dark toggle\`, which ships one.`,
|
|
575
|
+
toggle: `Dark mode follows the OS until the user says otherwise. The pieces:
|
|
576
|
+
an inline script in the HTML entry applies the mode before first paint,
|
|
577
|
+
[\`frontend/src/lib/theme.ts\`](frontend/src/lib/theme.ts) holds and persists it,
|
|
578
|
+
and the mode toggle on the landing page cycles system \u2192 light \u2192 dark.`,
|
|
579
|
+
off: `This project was scaffolded with \`--dark off\`, so nothing switches
|
|
580
|
+
themes. The \`.dark\` block in the stylesheet is still there and still complete \u2014
|
|
581
|
+
add \`class="dark"\` to \`<html>\` to see it, and wire that to a control (or the OS
|
|
582
|
+
setting) to turn it on for real.`
|
|
583
|
+
}[dark];
|
|
584
|
+
return `## Theming
|
|
585
|
+
|
|
586
|
+
Scaffolded with the **${theme.label}** theme. Every color in the app comes from
|
|
587
|
+
the semantic tokens at the top of
|
|
588
|
+
[\`frontend/src/index.css\`](frontend/src/index.css) \u2014 \`--primary\`,
|
|
589
|
+
\`--muted-foreground\`, \`--border\`, the \`--chart-*\` ramp, the \`--sidebar-*\` set \u2014
|
|
590
|
+
and every shadcn component reads those names, so editing one value rebrands
|
|
591
|
+
everything that uses it. Style with the token classes (\`bg-primary\`,
|
|
592
|
+
\`text-muted-foreground\`) rather than raw palette classes like \`bg-gray-100\`, or
|
|
593
|
+
the theme stops being one.
|
|
594
|
+
|
|
595
|
+
Tailwind v4 has no \`tailwind.config.js\`; that stylesheet *is* the config.
|
|
596
|
+
|
|
597
|
+
To swap the whole palette later:
|
|
598
|
+
|
|
599
|
+
\`\`\`bash
|
|
600
|
+
npx shadcn@latest add https://ui.shadcn.com/r/themes/stone.json # or any registry theme
|
|
601
|
+
\`\`\`
|
|
602
|
+
|
|
603
|
+
${darkNote}`;
|
|
604
|
+
}
|
|
569
605
|
var UI_DOCS_CTA = {
|
|
570
606
|
label: "Browse UI components",
|
|
571
607
|
href: "https://ui.shadcn.com/docs/components"
|
|
@@ -624,8 +660,22 @@ function codegenLanding({ appName }, origin) {
|
|
|
624
660
|
cta: UI_DOCS_CTA
|
|
625
661
|
};
|
|
626
662
|
}
|
|
627
|
-
function renderIndexCss() {
|
|
628
|
-
|
|
663
|
+
function renderIndexCss(choice = defaultThemeChoice()) {
|
|
664
|
+
const { theme } = choice;
|
|
665
|
+
const colorMap = colorTokens(theme.light).map((token) => ` --color-${token}: var(--${token});`).join("\n");
|
|
666
|
+
const block = (vars) => orderedTokens(vars).map(([name, value]) => ` --${name}: ${value};`).join("\n");
|
|
667
|
+
const faces = fontImports(choice.fonts);
|
|
668
|
+
const fontVars = fontThemeVars(choice.fonts).map(([name, value]) => ` ${name}: ${value};`).join("\n");
|
|
669
|
+
const headingRule = choice.fonts?.heading === void 0 ? "" : `
|
|
670
|
+
h1,
|
|
671
|
+
h2,
|
|
672
|
+
h3,
|
|
673
|
+
h4,
|
|
674
|
+
h5,
|
|
675
|
+
h6 {
|
|
676
|
+
font-family: var(--font-heading);
|
|
677
|
+
}`;
|
|
678
|
+
return `${faces.length === 0 ? "" : faces.join("\n") + "\n"}@import "tailwindcss";
|
|
629
679
|
@import "tw-animate-css";
|
|
630
680
|
|
|
631
681
|
@custom-variant dark (&:is(.dark *));
|
|
@@ -633,74 +683,25 @@ function renderIndexCss() {
|
|
|
633
683
|
/* Map the tokens below into Tailwind's theme so \`bg-primary\` and friends
|
|
634
684
|
resolve. Tailwind v4 does this in CSS; there is no tailwind.config.js. */
|
|
635
685
|
@theme inline {
|
|
636
|
-
|
|
637
|
-
--color-foreground: var(--foreground);
|
|
638
|
-
--color-card: var(--card);
|
|
639
|
-
--color-card-foreground: var(--card-foreground);
|
|
640
|
-
--color-popover: var(--popover);
|
|
641
|
-
--color-popover-foreground: var(--popover-foreground);
|
|
642
|
-
--color-primary: var(--primary);
|
|
643
|
-
--color-primary-foreground: var(--primary-foreground);
|
|
644
|
-
--color-secondary: var(--secondary);
|
|
645
|
-
--color-secondary-foreground: var(--secondary-foreground);
|
|
646
|
-
--color-muted: var(--muted);
|
|
647
|
-
--color-muted-foreground: var(--muted-foreground);
|
|
648
|
-
--color-accent: var(--accent);
|
|
649
|
-
--color-accent-foreground: var(--accent-foreground);
|
|
650
|
-
--color-destructive: var(--destructive);
|
|
651
|
-
--color-border: var(--border);
|
|
652
|
-
--color-input: var(--input);
|
|
653
|
-
--color-ring: var(--ring);
|
|
686
|
+
${colorMap}
|
|
654
687
|
--radius-sm: calc(var(--radius) - 4px);
|
|
655
688
|
--radius-md: calc(var(--radius) - 2px);
|
|
656
689
|
--radius-lg: var(--radius);
|
|
657
|
-
--radius-xl: calc(var(--radius) + 4px)
|
|
690
|
+
--radius-xl: calc(var(--radius) + 4px);${fontVars === "" ? "" : `
|
|
691
|
+
${fontVars}`}
|
|
658
692
|
}
|
|
659
693
|
|
|
660
|
-
/* Rebrand here
|
|
694
|
+
/* Theme: ${theme.label}. Rebrand here \u2014 these are the only colors the
|
|
695
|
+
components know about. Swap the whole palette for another shadcn theme with
|
|
696
|
+
\`npx shadcn@latest add <registry-theme-url>\`, or scaffold a different one
|
|
697
|
+
next time with \`xanots init --theme <base>-<accent>\`. */
|
|
661
698
|
:root {
|
|
662
|
-
|
|
663
|
-
--background: oklch(1 0 0);
|
|
664
|
-
--foreground: oklch(0.145 0 0);
|
|
665
|
-
--card: oklch(1 0 0);
|
|
666
|
-
--card-foreground: oklch(0.145 0 0);
|
|
667
|
-
--popover: oklch(1 0 0);
|
|
668
|
-
--popover-foreground: oklch(0.145 0 0);
|
|
669
|
-
--primary: oklch(0.205 0 0);
|
|
670
|
-
--primary-foreground: oklch(0.985 0 0);
|
|
671
|
-
--secondary: oklch(0.97 0 0);
|
|
672
|
-
--secondary-foreground: oklch(0.205 0 0);
|
|
673
|
-
--muted: oklch(0.97 0 0);
|
|
674
|
-
--muted-foreground: oklch(0.556 0 0);
|
|
675
|
-
--accent: oklch(0.97 0 0);
|
|
676
|
-
--accent-foreground: oklch(0.205 0 0);
|
|
677
|
-
--destructive: oklch(0.577 0.245 27.325);
|
|
678
|
-
--border: oklch(0.922 0 0);
|
|
679
|
-
--input: oklch(0.922 0 0);
|
|
680
|
-
--ring: oklch(0.708 0 0);
|
|
699
|
+
${block(theme.light)}
|
|
681
700
|
}
|
|
682
701
|
|
|
683
|
-
|
|
684
|
-
want one; the scaffold ships light-only. */
|
|
702
|
+
${darkBlockComment(choice.dark)}
|
|
685
703
|
.dark {
|
|
686
|
-
|
|
687
|
-
--foreground: oklch(0.985 0 0);
|
|
688
|
-
--card: oklch(0.205 0 0);
|
|
689
|
-
--card-foreground: oklch(0.985 0 0);
|
|
690
|
-
--popover: oklch(0.205 0 0);
|
|
691
|
-
--popover-foreground: oklch(0.985 0 0);
|
|
692
|
-
--primary: oklch(0.922 0 0);
|
|
693
|
-
--primary-foreground: oklch(0.205 0 0);
|
|
694
|
-
--secondary: oklch(0.269 0 0);
|
|
695
|
-
--secondary-foreground: oklch(0.985 0 0);
|
|
696
|
-
--muted: oklch(0.269 0 0);
|
|
697
|
-
--muted-foreground: oklch(0.708 0 0);
|
|
698
|
-
--accent: oklch(0.269 0 0);
|
|
699
|
-
--accent-foreground: oklch(0.985 0 0);
|
|
700
|
-
--destructive: oklch(0.704 0.191 22.216);
|
|
701
|
-
--border: oklch(1 0 0 / 10%);
|
|
702
|
-
--input: oklch(1 0 0 / 15%);
|
|
703
|
-
--ring: oklch(0.556 0 0);
|
|
704
|
+
${block(theme.dark)}
|
|
704
705
|
}
|
|
705
706
|
|
|
706
707
|
@layer base {
|
|
@@ -709,8 +710,95 @@ function renderIndexCss() {
|
|
|
709
710
|
}
|
|
710
711
|
body {
|
|
711
712
|
@apply bg-background text-foreground;
|
|
713
|
+
}${headingRule}
|
|
714
|
+
}
|
|
715
|
+
`;
|
|
716
|
+
}
|
|
717
|
+
function darkBlockComment(dark) {
|
|
718
|
+
switch (dark) {
|
|
719
|
+
case "system":
|
|
720
|
+
return `/* Applied by the inline script in index.html, which follows the OS setting.
|
|
721
|
+
Add a control that toggles this class to let the user override it. */`;
|
|
722
|
+
case "toggle":
|
|
723
|
+
return `/* Applied by frontend/src/lib/theme.ts \u2014 the OS setting by default, and the
|
|
724
|
+
user's choice once they use the mode toggle. */`;
|
|
725
|
+
case "off":
|
|
726
|
+
return `/* Applied by adding \`class="dark"\` to <html> \u2014 wire that to a toggle if you
|
|
727
|
+
want one; this scaffold was created with --dark off, so nothing does yet. */`;
|
|
712
728
|
}
|
|
713
729
|
}
|
|
730
|
+
function renderThemeScript(dark) {
|
|
731
|
+
if (dark === "off") return "";
|
|
732
|
+
const resolve = dark === "toggle" ? `var stored = localStorage.getItem("theme");
|
|
733
|
+
var dark = stored === "dark" || (stored !== "light" && media.matches);` : `var dark = media.matches;`;
|
|
734
|
+
return ` <script>
|
|
735
|
+
// Sets the \`dark\` class before first paint, so the page never flashes
|
|
736
|
+
// light before switching. Keep this inline and above the stylesheet.
|
|
737
|
+
(function () {
|
|
738
|
+
try {
|
|
739
|
+
var media = window.matchMedia("(prefers-color-scheme: dark)");
|
|
740
|
+
${resolve}
|
|
741
|
+
document.documentElement.classList.toggle("dark", dark);
|
|
742
|
+
} catch (e) {}
|
|
743
|
+
})();
|
|
744
|
+
</script>
|
|
745
|
+
`;
|
|
746
|
+
}
|
|
747
|
+
function renderThemeModule() {
|
|
748
|
+
return `/**
|
|
749
|
+
* Color mode, persisted. The inline script in index.html applies the stored
|
|
750
|
+
* value before first paint; this module is what changes it afterwards.
|
|
751
|
+
*
|
|
752
|
+
* "system" means no stored preference \u2014 the OS decides, and keeps deciding if
|
|
753
|
+
* the user changes it while the page is open.
|
|
754
|
+
*/
|
|
755
|
+
export type Mode = "light" | "dark" | "system";
|
|
756
|
+
|
|
757
|
+
const KEY = "theme";
|
|
758
|
+
|
|
759
|
+
const prefersDark = () =>
|
|
760
|
+
window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
761
|
+
|
|
762
|
+
/** The stored preference, or "system" when there is none. */
|
|
763
|
+
export function getMode(): Mode {
|
|
764
|
+
const stored = localStorage.getItem(KEY);
|
|
765
|
+
return stored === "light" || stored === "dark" ? stored : "system";
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/** Whether \`mode\` renders dark right now. */
|
|
769
|
+
export function isDark(mode: Mode): boolean {
|
|
770
|
+
return mode === "dark" || (mode === "system" && prefersDark());
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/** Persist a mode and apply it. "system" clears the stored override. */
|
|
774
|
+
export function setMode(mode: Mode): void {
|
|
775
|
+
if (mode === "system") localStorage.removeItem(KEY);
|
|
776
|
+
else localStorage.setItem(KEY, mode);
|
|
777
|
+
document.documentElement.classList.toggle("dark", isDark(mode));
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* Re-apply on OS changes, and on changes made in another tab. Returns an
|
|
782
|
+
* unsubscribe function \u2014 call it from your framework's cleanup hook.
|
|
783
|
+
*
|
|
784
|
+
* The OS listener re-reads the mode rather than closing over it, so it stays
|
|
785
|
+
* correct after the user picks an explicit light/dark and then goes back to
|
|
786
|
+
* system.
|
|
787
|
+
*/
|
|
788
|
+
export function watchMode(onChange: (mode: Mode) => void): () => void {
|
|
789
|
+
const media = window.matchMedia("(prefers-color-scheme: dark)");
|
|
790
|
+
const apply = () => {
|
|
791
|
+
const mode = getMode();
|
|
792
|
+
document.documentElement.classList.toggle("dark", isDark(mode));
|
|
793
|
+
onChange(mode);
|
|
794
|
+
};
|
|
795
|
+
media.addEventListener("change", apply);
|
|
796
|
+
window.addEventListener("storage", apply);
|
|
797
|
+
return () => {
|
|
798
|
+
media.removeEventListener("change", apply);
|
|
799
|
+
window.removeEventListener("storage", apply);
|
|
800
|
+
};
|
|
801
|
+
}
|
|
714
802
|
`;
|
|
715
803
|
}
|
|
716
804
|
function renderCnUtil(extra = "") {
|
|
@@ -779,9 +867,6 @@ export const XANO_HOST: string =
|
|
|
779
867
|
`;
|
|
780
868
|
}
|
|
781
869
|
|
|
782
|
-
// src/emit/frontend-resolve.ts
|
|
783
|
-
import { createInterface } from "readline/promises";
|
|
784
|
-
|
|
785
870
|
// src/emit/frontend-svelte.ts
|
|
786
871
|
var CODE_CLASS = "bg-muted rounded px-1.5 py-0.5 font-mono text-sm";
|
|
787
872
|
function htmlText(s) {
|
|
@@ -796,16 +881,22 @@ function renderNode(node) {
|
|
|
796
881
|
function renderNodes(nodes) {
|
|
797
882
|
return nodes.map(renderNode).join("");
|
|
798
883
|
}
|
|
799
|
-
function renderApp(landing) {
|
|
800
|
-
const steps = landing.steps.map((
|
|
884
|
+
function renderApp(landing, choice) {
|
|
885
|
+
const steps = landing.steps.map((step) => ` <li>${renderNodes(step)}</li>`).join("\n");
|
|
886
|
+
const toggle = choice.dark === "toggle";
|
|
887
|
+
const icons = iconLibraryOf(choice.icons).svelte;
|
|
801
888
|
return `<script lang="ts">
|
|
802
|
-
|
|
889
|
+
${icons.arrowImport}
|
|
803
890
|
|
|
804
891
|
import { Button } from "$lib/components/ui/button/index.js";
|
|
805
|
-
import * as Card from "$lib/components/ui/card/index.js"
|
|
892
|
+
import * as Card from "$lib/components/ui/card/index.js";${toggle ? `
|
|
893
|
+
import ModeToggle from "$lib/components/mode-toggle.svelte";` : ""}
|
|
806
894
|
</script>
|
|
807
895
|
|
|
808
|
-
<main class="mx-auto flex min-h-screen max-w-2xl flex-col justify-center p-8"
|
|
896
|
+
<main class="mx-auto flex min-h-screen max-w-2xl flex-col justify-center p-8">${toggle ? `
|
|
897
|
+
<div class="mb-4 flex justify-end">
|
|
898
|
+
<ModeToggle />
|
|
899
|
+
</div>` : ""}
|
|
809
900
|
<Card.Root>
|
|
810
901
|
<Card.Header>
|
|
811
902
|
<Card.Title class="text-3xl tracking-tight">${svelteText(landing.title)}</Card.Title>
|
|
@@ -823,7 +914,7 @@ ${steps}
|
|
|
823
914
|
\`npx shadcn-svelte@latest add <name>\`. -->
|
|
824
915
|
<Button href="${landing.cta.href}" target="_blank" rel="noreferrer">
|
|
825
916
|
${svelteText(landing.cta.label)}
|
|
826
|
-
|
|
917
|
+
<${icons.arrowComponent} />
|
|
827
918
|
</Button>
|
|
828
919
|
</Card.Footer>
|
|
829
920
|
</Card.Root>
|
|
@@ -913,13 +1004,14 @@ function renderSvelteKitPlugin() {
|
|
|
913
1004
|
},
|
|
914
1005
|
})`;
|
|
915
1006
|
}
|
|
916
|
-
function renderAppHtml({ appName }) {
|
|
1007
|
+
function renderAppHtml({ appName }, choice) {
|
|
917
1008
|
return `<!doctype html>
|
|
918
1009
|
<html lang="en">
|
|
919
1010
|
<head>
|
|
920
1011
|
<meta charset="utf-8" />
|
|
921
1012
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
922
1013
|
<title>${htmlText(appName)}</title>
|
|
1014
|
+
${renderThemeScript(choice.dark)}
|
|
923
1015
|
<!-- Drop a favicon.png into frontend/static/ and link it here:
|
|
924
1016
|
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
|
925
1017
|
Everything in that directory is copied to the site root verbatim. -->
|
|
@@ -933,6 +1025,46 @@ function renderAppHtml({ appName }) {
|
|
|
933
1025
|
</html>
|
|
934
1026
|
`;
|
|
935
1027
|
}
|
|
1028
|
+
function renderModeToggleSvelte(icons) {
|
|
1029
|
+
return `<script lang="ts">
|
|
1030
|
+
${icons.modeImports.join("\n ")}
|
|
1031
|
+
|
|
1032
|
+
import { Button } from "$lib/components/ui/button/index.js";
|
|
1033
|
+
import { getMode, setMode, watchMode, type Mode } from "$lib/theme.js";
|
|
1034
|
+
|
|
1035
|
+
/** system \u2192 light \u2192 dark \u2192 system. */
|
|
1036
|
+
const next: Record<Mode, Mode> = { system: "light", light: "dark", dark: "system" };
|
|
1037
|
+
|
|
1038
|
+
const icons = {
|
|
1039
|
+
system: ${icons.modeComponents.system},
|
|
1040
|
+
light: ${icons.modeComponents.light},
|
|
1041
|
+
dark: ${icons.modeComponents.dark},
|
|
1042
|
+
};
|
|
1043
|
+
|
|
1044
|
+
// Starts at "system" so the prerendered HTML is deterministic; the effect
|
|
1045
|
+
// corrects it in the browser, after the inline script has already applied
|
|
1046
|
+
// the right class.
|
|
1047
|
+
let mode = $state<Mode>("system");
|
|
1048
|
+
|
|
1049
|
+
$effect(() => {
|
|
1050
|
+
mode = getMode();
|
|
1051
|
+
return watchMode((m) => (mode = m));
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
function change() {
|
|
1055
|
+
const target = next[mode];
|
|
1056
|
+
setMode(target);
|
|
1057
|
+
mode = target;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
const Icon = $derived(icons[mode]);
|
|
1061
|
+
</script>
|
|
1062
|
+
|
|
1063
|
+
<Button variant="ghost" size="icon" onclick={change} aria-label="Switch to {next[mode]} theme">
|
|
1064
|
+
<Icon />
|
|
1065
|
+
</Button>
|
|
1066
|
+
`;
|
|
1067
|
+
}
|
|
936
1068
|
function renderAppDts() {
|
|
937
1069
|
return `// See https://svelte.dev/docs/kit/types#app.d.ts
|
|
938
1070
|
declare global {
|
|
@@ -1048,14 +1180,16 @@ function renderLayoutSvelte() {
|
|
|
1048
1180
|
{@render children()}
|
|
1049
1181
|
`;
|
|
1050
1182
|
}
|
|
1051
|
-
function renderComponentsJson() {
|
|
1183
|
+
function renderComponentsJson(choice) {
|
|
1052
1184
|
const config = {
|
|
1053
1185
|
$schema: "https://shadcn-svelte.com/schema.json",
|
|
1054
1186
|
tailwind: {
|
|
1055
1187
|
// v4 has no config file; the theme lives in the stylesheet — the same
|
|
1056
1188
|
// shared one the React preset points at.
|
|
1057
1189
|
css: "frontend/src/index.css",
|
|
1058
|
-
|
|
1190
|
+
// Tracks the theme the stylesheet was rendered from — see the React
|
|
1191
|
+
// preset's note; the shadcn-svelte CLI reads it the same way.
|
|
1192
|
+
baseColor: choice.theme.baseColor ?? "neutral"
|
|
1059
1193
|
},
|
|
1060
1194
|
aliases: {
|
|
1061
1195
|
components: "$lib/components",
|
|
@@ -1215,14 +1349,14 @@ var sveltePreset = {
|
|
|
1215
1349
|
// shadcn-svelte's runtime surface. `bits-ui` is the headless primitive
|
|
1216
1350
|
// library its components are built on (the Radix equivalent), and
|
|
1217
1351
|
// `tailwind-variants` types the variants (the cva equivalent). clsx +
|
|
1218
|
-
// tailwind-merge back `cn()` exactly as in the React preset
|
|
1219
|
-
//
|
|
1220
|
-
//
|
|
1352
|
+
// tailwind-merge back `cn()` exactly as in the React preset. Pre-installed
|
|
1353
|
+
// so `npx shadcn-svelte@latest add <component>` works without a separate
|
|
1354
|
+
// npm i.
|
|
1355
|
+
//
|
|
1356
|
+
// The icon package is `--icons`, merged in by renderPackageJson from
|
|
1357
|
+
// `iconBinding` below — see the React preset's note.
|
|
1221
1358
|
"bits-ui": "^2.18.1",
|
|
1222
1359
|
clsx: "^2.1.1",
|
|
1223
|
-
// Not the same version line as `lucide-react`: the Svelte icons ship from a
|
|
1224
|
-
// separate package on their own 1.x.
|
|
1225
|
-
"@lucide/svelte": "^1.31.0",
|
|
1226
1360
|
"tailwind-merge": "^3.0.1",
|
|
1227
1361
|
"tailwind-variants": "^3.3.1"
|
|
1228
1362
|
},
|
|
@@ -1321,15 +1455,22 @@ export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?:
|
|
|
1321
1455
|
// SvelteKit owns the page template — frontend/src/app.html. No `entryScript`
|
|
1322
1456
|
// follows: there is no shared index.html for it to point at.
|
|
1323
1457
|
ownsHtmlEntry: true,
|
|
1324
|
-
files(vars, landing) {
|
|
1458
|
+
files(vars, landing, choice = defaultThemeChoice()) {
|
|
1325
1459
|
const ui = "frontend/src/lib/components/ui";
|
|
1326
1460
|
return [
|
|
1327
|
-
{ path: "components.json", content: renderComponentsJson() },
|
|
1328
|
-
{ path: "frontend/src/app.html", content: renderAppHtml(vars) },
|
|
1461
|
+
{ path: "components.json", content: renderComponentsJson(choice) },
|
|
1462
|
+
{ path: "frontend/src/app.html", content: renderAppHtml(vars, choice) },
|
|
1463
|
+
// Only for `--dark toggle` — see the React preset's note.
|
|
1464
|
+
...choice.dark === "toggle" ? [
|
|
1465
|
+
{
|
|
1466
|
+
path: "frontend/src/lib/components/mode-toggle.svelte",
|
|
1467
|
+
content: renderModeToggleSvelte(iconLibraryOf(choice.icons).svelte)
|
|
1468
|
+
}
|
|
1469
|
+
] : [],
|
|
1329
1470
|
{ path: "frontend/src/app.d.ts", content: renderAppDts() },
|
|
1330
1471
|
{ path: "frontend/src/routes/+layout.ts", content: renderLayoutTs() },
|
|
1331
1472
|
{ path: "frontend/src/routes/+layout.svelte", content: renderLayoutSvelte() },
|
|
1332
|
-
{ path: "frontend/src/routes/+page.svelte", content: renderApp(landing) },
|
|
1473
|
+
{ path: "frontend/src/routes/+page.svelte", content: renderApp(landing, choice) },
|
|
1333
1474
|
{ path: "frontend/src/routes/+error.svelte", content: renderErrorSvelte() },
|
|
1334
1475
|
{ path: "frontend/src/routes/404/+page.svelte", content: renderNotFoundRoute() },
|
|
1335
1476
|
{ path: "frontend/src/lib/components/error-state.svelte", content: renderErrorState() },
|
|
@@ -1383,7 +1524,10 @@ Delete this file once you add something real.
|
|
|
1383
1524
|
{ path: `${ui}/card/index.ts`, content: renderCardIndex() }
|
|
1384
1525
|
];
|
|
1385
1526
|
},
|
|
1386
|
-
|
|
1527
|
+
iconBinding(id) {
|
|
1528
|
+
return iconLibraryOf(id).svelte;
|
|
1529
|
+
},
|
|
1530
|
+
readmeFrontendSection(icons) {
|
|
1387
1531
|
return `[SvelteKit](https://svelte.dev/docs/kit) with Svelte 5, styled with
|
|
1388
1532
|
[Tailwind CSS](https://tailwindcss.com) v4 and
|
|
1389
1533
|
[shadcn-svelte](https://shadcn-svelte.com).
|
|
@@ -1434,12 +1578,10 @@ npx shadcn-svelte@latest add dialog input form
|
|
|
1434
1578
|
\`\`\`
|
|
1435
1579
|
|
|
1436
1580
|
[\`components.json\`](components.json) is pre-configured, so that works with no
|
|
1437
|
-
\`shadcn-svelte init\` step.
|
|
1438
|
-
installed as \`@lucide/svelte\`. Import one per module, with the icon name
|
|
1439
|
-
kebab-cased into the path:
|
|
1581
|
+
\`shadcn-svelte init\` step. ${iconLibraryOf(icons).guidance.svelte}
|
|
1440
1582
|
|
|
1441
1583
|
\`\`\`ts
|
|
1442
|
-
|
|
1584
|
+
${iconLibraryOf(icons).svelte.arrowImport}
|
|
1443
1585
|
\`\`\`
|
|
1444
1586
|
|
|
1445
1587
|
[\`frontend/src/routes/+page.svelte\`](frontend/src/routes/+page.svelte) already
|
|
@@ -1451,9 +1593,8 @@ Components import through the \`$lib\` alias
|
|
|
1451
1593
|
[\`vite.config.ts\`](vite.config.ts) \u2014 there is no \`paths\` entry to keep in
|
|
1452
1594
|
sync, and adding one would just be a second answer that can disagree.
|
|
1453
1595
|
|
|
1454
|
-
|
|
1455
|
-
[\`frontend/src/index.css\`](frontend/src/index.css)
|
|
1456
|
-
\`tailwind.config.js\`; the theme lives in that stylesheet.
|
|
1596
|
+
Colors come from the theme tokens in
|
|
1597
|
+
[\`frontend/src/index.css\`](frontend/src/index.css) \u2014 see **Theming** below.
|
|
1457
1598
|
|
|
1458
1599
|
> \`npm run typecheck\` runs \`svelte-kit sync && svelte-check\`, not \`tsc\`. It
|
|
1459
1600
|
> checks both halves \u2014 the backend's TypeScript and the components \u2014 where
|
|
@@ -1461,7 +1602,7 @@ To rebrand, edit the color tokens at the top of
|
|
|
1461
1602
|
> makes the frontend unable to drift from the backend defs. \`sync\` regenerates
|
|
1462
1603
|
> \`.svelte-kit/\`, which \`tsconfig.json\` extends; \`npm install\` runs it too.`;
|
|
1463
1604
|
},
|
|
1464
|
-
agentGuidanceSection() {
|
|
1605
|
+
agentGuidanceSection(icons) {
|
|
1465
1606
|
return `- \`frontend/src/\` \u2014 the SvelteKit app. Svelte 5 + Tailwind v4 + shadcn-svelte.
|
|
1466
1607
|
- **There is no server.** This deploys to a static host with no runtime, and
|
|
1467
1608
|
Xano is the backend. Never write \`+page.server.ts\`, \`+layout.server.ts\`,
|
|
@@ -1508,16 +1649,11 @@ To rebrand, edit the color tokens at the top of
|
|
|
1508
1649
|
- Need one that isn't there? \`npx shadcn-svelte@latest add <name>\` \u2014 do not
|
|
1509
1650
|
hand-roll it, and do not add a different component library. Note the
|
|
1510
1651
|
\`-svelte\` suffix: the plain \`shadcn\` CLI writes React and will not work here.
|
|
1511
|
-
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
\`import ArrowRight from "@lucide/svelte/icons/arrow-right";\` \u2014
|
|
1517
|
-
\`frontend/src/routes/+page.svelte\` already does. This is the form
|
|
1518
|
-
\`npx shadcn-svelte@latest add\` writes, so matching it keeps the components
|
|
1519
|
-
you write consistent with the ones the CLI generates beside them. Do not add
|
|
1520
|
-
another icon library and do not paste raw inline \`<svg>\` markup.
|
|
1652
|
+
- ${iconLibraryOf(icons).guidance.svelte.replace(/\n/g, "\n ")}
|
|
1653
|
+
- That import form is what \`frontend/src/routes/+page.svelte\` already uses and
|
|
1654
|
+
what \`npx shadcn-svelte@latest add\` writes, so matching it keeps what you
|
|
1655
|
+
write consistent with what the CLI generates beside it. Do not add another
|
|
1656
|
+
icon library and do not paste raw inline \`<svg>\` markup.
|
|
1521
1657
|
- Import via the \`$lib\` alias (\`$lib/components/ui/button\`, \`$lib/utils\`),
|
|
1522
1658
|
which SvelteKit generates for both TypeScript and the bundler. Do not add a
|
|
1523
1659
|
\`paths\` entry for it \u2014 a hand-written one is a second source of truth that
|
|
@@ -1528,10 +1664,6 @@ To rebrand, edit the color tokens at the top of
|
|
|
1528
1664
|
naming the file rather than a component that quietly builds in legacy mode.
|
|
1529
1665
|
Do not "fix" that error by relaxing \`compilerOptions.runes\` \u2014 write the
|
|
1530
1666
|
rune.
|
|
1531
|
-
- Style with the semantic tokens (\`bg-primary\`, \`text-muted-foreground\`,
|
|
1532
|
-
\`border-input\`), never raw palette classes like \`bg-gray-100\` \u2014 the tokens are
|
|
1533
|
-
defined in \`frontend/src/index.css\`, which is also where you rebrand. Tailwind
|
|
1534
|
-
v4 has no \`tailwind.config.js\`.
|
|
1535
1667
|
- \`npm run typecheck\` runs \`svelte-kit sync && svelte-check\`, which checks both
|
|
1536
1668
|
\`xano/\` and the components. Do not swap it for \`tsc --noEmit\`: \`tsc\` cannot
|
|
1537
1669
|
read \`.svelte\` files and fails on the UI kit's barrels. \`sync\` regenerates
|
|
@@ -1563,130 +1695,29 @@ function resolveFrameworkFlag(raw) {
|
|
|
1563
1695
|
return preset;
|
|
1564
1696
|
}
|
|
1565
1697
|
|
|
1566
|
-
// src/emit/frontend-resolve.ts
|
|
1567
|
-
function defaultFrontendPreset() {
|
|
1568
|
-
const preset = findFrontendPreset(DEFAULT_FRAMEWORK);
|
|
1569
|
-
if (preset === void 0) {
|
|
1570
|
-
throw new Error(`Default frontend preset "${DEFAULT_FRAMEWORK}" is missing from the table.`);
|
|
1571
|
-
}
|
|
1572
|
-
return preset;
|
|
1573
|
-
}
|
|
1574
|
-
async function promptFramework() {
|
|
1575
|
-
const presets = allFrontendPresets();
|
|
1576
|
-
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
1577
|
-
try {
|
|
1578
|
-
process.stderr.write(
|
|
1579
|
-
`
|
|
1580
|
-
Which frontend framework?
|
|
1581
|
-
` + presets.map((p, i) => ` ${i + 1}) ${p.label}${p.id === DEFAULT_FRAMEWORK ? " (default)" : ""}`).join("\n") + `
|
|
1582
|
-
`
|
|
1583
|
-
);
|
|
1584
|
-
const answer = await rl.question(`Enter a number or name, or leave blank for the default: `);
|
|
1585
|
-
const token = answer.trim().toLowerCase();
|
|
1586
|
-
if (token === "") return defaultFrontendPreset();
|
|
1587
|
-
const byIndex = Number.parseInt(token, 10);
|
|
1588
|
-
if (Number.isInteger(byIndex) && byIndex >= 1 && byIndex <= presets.length) {
|
|
1589
|
-
return presets[byIndex - 1];
|
|
1590
|
-
}
|
|
1591
|
-
return findFrontendPreset(token) ?? defaultFrontendPreset();
|
|
1592
|
-
} finally {
|
|
1593
|
-
rl.close();
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
|
-
async function resolveFrontendPreset(flag) {
|
|
1597
|
-
if (flag !== void 0 && flag !== "") return resolveFrameworkFlag(flag);
|
|
1598
|
-
if (process.stdin.isTTY && process.stderr.isTTY) return promptFramework();
|
|
1599
|
-
return defaultFrontendPreset();
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
// src/emit/init-command.ts
|
|
1603
|
-
function sanitizeAppName(raw) {
|
|
1604
|
-
const name = raw.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
1605
|
-
return name === "" ? "app" : name;
|
|
1606
|
-
}
|
|
1607
|
-
function projectShellFiles(vars, preset, parts) {
|
|
1608
|
-
return [
|
|
1609
|
-
{ path: "package.json", content: renderPackageJson(vars, preset) },
|
|
1610
|
-
{ path: "tsconfig.json", content: renderTsconfig(preset) },
|
|
1611
|
-
{ path: "vite.config.ts", content: renderViteConfig(preset) },
|
|
1612
|
-
{ path: ".gitignore", content: renderGitignore(preset) },
|
|
1613
|
-
{ path: ".env.example", content: renderEnvExample() },
|
|
1614
|
-
{ path: "README.md", content: parts.readme },
|
|
1615
|
-
// Skipped when the framework supplies its own entry document — see
|
|
1616
|
-
// FrontendPreset.ownsHtmlEntry. A second index.html beside SvelteKit's
|
|
1617
|
-
// app.html would never be served and would still read as the entry point.
|
|
1618
|
-
...preset.ownsHtmlEntry === true ? [] : [{ path: "frontend/index.html", content: renderIndexHtml(vars, preset) }],
|
|
1619
|
-
// Shared across every framework: both UI kits resolve against the same
|
|
1620
|
-
// Tailwind v4 semantic tokens, back `cn()` with clsx + tailwind-merge, and
|
|
1621
|
-
// look for library code at frontend/src/lib/. Only the alias NAME pointing
|
|
1622
|
-
// at that directory differs, and the preset owns that.
|
|
1623
|
-
{ path: "frontend/src/index.css", content: renderIndexCss() },
|
|
1624
|
-
{ path: "frontend/src/lib/api.ts", content: renderApiTs() },
|
|
1625
|
-
{ path: "frontend/src/lib/utils.ts", content: renderCnUtil(preset.libUtilsExtra) },
|
|
1626
|
-
// The framework's own half: entry module, app component, vendored UI kit,
|
|
1627
|
-
// and whatever tool config that kit's CLI reads.
|
|
1628
|
-
...preset.files(vars, parts.landing)
|
|
1629
|
-
];
|
|
1630
|
-
}
|
|
1631
|
-
function buildFileSet(vars, preset) {
|
|
1632
|
-
return [
|
|
1633
|
-
...projectShellFiles(vars, preset, {
|
|
1634
|
-
readme: renderReadme(vars, preset),
|
|
1635
|
-
landing: initLanding(vars)
|
|
1636
|
-
}),
|
|
1637
|
-
{ path: "xano/index.ts", content: renderXanoIndex(vars) },
|
|
1638
|
-
{ path: "xano/EXAMPLE.md", content: renderXanoExampleMd(vars) }
|
|
1639
|
-
];
|
|
1640
|
-
}
|
|
1641
|
-
async function runInitCommand(args) {
|
|
1642
|
-
const targetArg = args.positionals[0] ?? ".";
|
|
1643
|
-
const targetDir = resolve(targetArg);
|
|
1644
|
-
const appName = sanitizeAppName(args.name ?? basename(targetDir));
|
|
1645
|
-
const preset = await resolveFrontendPreset(args.framework);
|
|
1646
|
-
const presets = await resolveAiPresets(args.ai);
|
|
1647
|
-
const vars = { appName, sdkVersion: readVersion() };
|
|
1648
|
-
step(`Scaffolding ${style.bold(appName)} (${preset.label}) in ${targetDir}`);
|
|
1649
|
-
const result = await scaffoldProject({
|
|
1650
|
-
targetDir,
|
|
1651
|
-
files: buildFileSet(vars, preset),
|
|
1652
|
-
presets,
|
|
1653
|
-
appName,
|
|
1654
|
-
force: args.force,
|
|
1655
|
-
noInstall: args.noInstall,
|
|
1656
|
-
// An `init` project's `xano/` is hand-authored, never machine-written: it is
|
|
1657
|
-
// not refreshable, and `--force` must not clear it.
|
|
1658
|
-
regenerable: false,
|
|
1659
|
-
sdkVersion: readVersion(),
|
|
1660
|
-
frontend: preset
|
|
1661
|
-
});
|
|
1662
|
-
if (presets.length > 0) {
|
|
1663
|
-
info(`AI instructions: ${presets.map(presetFilePath).join(", ")}`);
|
|
1664
|
-
}
|
|
1665
|
-
blank();
|
|
1666
|
-
success("Project ready.");
|
|
1667
|
-
const cdHint = targetDir === process.cwd() ? "" : ` cd ${targetArg}
|
|
1668
|
-
`;
|
|
1669
|
-
detail(
|
|
1670
|
-
`Next steps:
|
|
1671
|
-
` + cdHint + (result.install === "installed" ? `` : ` npm install
|
|
1672
|
-
`) + ` npm run dev # run the frontend
|
|
1673
|
-
xanots login # authenticate with Xano
|
|
1674
|
-
npm run xano:deploy # build the frontend, then deploy \u2192 live ephemeral URL
|
|
1675
|
-
|
|
1676
|
-
The first export or deploy writes xano/xano.lock \u2014 commit it. It pins each
|
|
1677
|
-
object's identity, so renaming one later renames it instead of deleting and
|
|
1678
|
-
recreating it. See "xano.lock \u2014 commit it" in the README.`
|
|
1679
|
-
);
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
1698
|
export {
|
|
1699
|
+
renderPackageJson,
|
|
1700
|
+
renderTsconfig,
|
|
1701
|
+
renderViteConfig,
|
|
1702
|
+
renderIndexHtml,
|
|
1703
|
+
renderGitignore,
|
|
1704
|
+
renderEnvExample,
|
|
1705
|
+
renderReadme,
|
|
1706
|
+
renderXanoIndex,
|
|
1707
|
+
renderXanoExampleMd,
|
|
1683
1708
|
describeOrigin,
|
|
1684
1709
|
renderCodegenMarker,
|
|
1685
1710
|
renderCodegenReadme,
|
|
1711
|
+
initLanding,
|
|
1686
1712
|
codegenLanding,
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1713
|
+
renderIndexCss,
|
|
1714
|
+
renderThemeModule,
|
|
1715
|
+
renderCnUtil,
|
|
1716
|
+
renderApiTs,
|
|
1717
|
+
FRAMEWORKS,
|
|
1718
|
+
DEFAULT_FRAMEWORK,
|
|
1719
|
+
findFrontendPreset,
|
|
1720
|
+
allFrontendPresets,
|
|
1721
|
+
resolveFrameworkFlag
|
|
1691
1722
|
};
|
|
1692
|
-
//# sourceMappingURL=chunk-
|
|
1723
|
+
//# sourceMappingURL=chunk-YZ4GU6F5.js.map
|