@ludoloops/svelteforge 0.1.0 → 0.1.2
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 -5
- package/dist/index.js +100 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
# Full stack (UI + auth + DB)
|
|
9
|
-
sv create my-app --template minimal --types ts --add tailwindcss @
|
|
9
|
+
sv create my-app --template minimal --types ts --add tailwindcss @ludoloops/svelteforge
|
|
10
10
|
|
|
11
11
|
# Or add to an existing project
|
|
12
12
|
cd my-app
|
|
13
|
-
sv add @
|
|
13
|
+
sv add @ludoloops/svelteforge
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
The addon prompts for a template mode:
|
|
@@ -139,7 +139,7 @@ svelteforge/ ← this repo (addon package)
|
|
|
139
139
|
├── scripts/
|
|
140
140
|
│ └── prebuild.ts ← reads templates/ → generates src/templates.ts
|
|
141
141
|
├── tsdown.config.ts ← bundler (bundles everything into dist/index.js)
|
|
142
|
-
├── package.json ← @
|
|
142
|
+
├── package.json ← @ludoloops/svelteforge
|
|
143
143
|
├── AGENTS.md
|
|
144
144
|
└── README.md
|
|
145
145
|
```
|
|
@@ -148,7 +148,7 @@ svelteforge/ ← this repo (addon package)
|
|
|
148
148
|
|
|
149
149
|
1. `bun run prebuild` — reads `templates/` directories, inlines all file contents into `src/templates.ts`
|
|
150
150
|
2. `tsdown` — bundles `src/index.ts` + modes + templates into a single `dist/index.js`
|
|
151
|
-
3. Published on npm as `@
|
|
151
|
+
3. Published on npm as `@ludoloops/svelteforge`
|
|
152
152
|
|
|
153
153
|
## Development
|
|
154
154
|
|
|
@@ -159,7 +159,7 @@ bun run build
|
|
|
159
159
|
# Test locally with bun link
|
|
160
160
|
bun link
|
|
161
161
|
mkdir /tmp/test-app && cd /tmp/test-app
|
|
162
|
-
sv create my-app --template minimal --types ts --add tailwindcss @
|
|
162
|
+
sv create my-app --template minimal --types ts --add tailwindcss @ludoloops/svelteforge
|
|
163
163
|
cd my-app
|
|
164
164
|
bun dev
|
|
165
165
|
```
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ const landingFiles = {
|
|
|
8
8
|
"/lib/components/anim/DynamicCounter.svelte": "<script lang=\"ts\">\n import { onMount } from 'svelte';\n\n const {\n target = 0,\n duration = 2,\n suffix = '',\n prefix = '',\n once = true\n }: {\n target: number;\n duration?: number;\n suffix?: string;\n prefix?: string;\n once?: boolean;\n } = $props();\n\n let container: HTMLElement;\n let currentValue = $state(0);\n let hasAnimated = $state(false);\n\n onMount(() => {\n if (!container) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n const entry = entries[0];\n if (entry.isIntersecting && (!hasAnimated || !once)) {\n hasAnimated = true;\n\n const startTime = performance.now();\n const animate = () => {\n const elapsed = performance.now() - startTime;\n const progress = Math.min(elapsed / (duration * 1000), 1);\n const easedProgress = 1 - Math.pow(1 - progress, 3);\n currentValue = Math.round(easedProgress * target);\n\n if (progress < 1) {\n requestAnimationFrame(animate);\n }\n };\n\n requestAnimationFrame(animate);\n\n if (once) {\n observer.disconnect();\n }\n } else if (!entry.isIntersecting && !once) {\n currentValue = 0;\n }\n },\n {\n threshold: 0.1,\n rootMargin: '0px 0px -10% 0px'\n }\n );\n\n observer.observe(container);\n return () => observer.disconnect();\n });\n<\/script>\n\n<span bind:this={container}>{prefix}{currentValue}{suffix}</span>\n",
|
|
9
9
|
"/lib/components/layout/navbar.svelte": "<script lang=\"ts\">\n import { AppBar } from '@skeletonlabs/skeleton-svelte';\n import ThemeToggle from '$lib/components/ui/ThemeToggle.svelte';\n import { themeStore } from '$lib/utils/theme.svelte';\n import { onMount, onDestroy } from 'svelte';\n\n let mobileMenuOpen = $state(false);\n\n onMount(() => {\n themeStore.init();\n });\n onDestroy(() => {\n themeStore.destroy();\n });\n<\/script>\n\n{#if mobileMenuOpen}\n <div\n class=\"md:hidden fixed inset-0 top-16 bg-surface-50-900 z-40\"\n onclick={() => (mobileMenuOpen = false)}\n onkeydown={(e) => e.key === 'Escape' && (mobileMenuOpen = false)}\n role=\"dialog\"\n aria-modal=\"true\"\n tabindex=\"-1\"\n >\n <div class=\"flex flex-col p-6\">\n <button\n type=\"button\"\n onclick={() => {\n themeStore.toggle();\n mobileMenuOpen = false;\n }}\n class=\"flex items-center gap-3 px-4 py-3 rounded-xl hover:bg-surface-200-800 text-sm\"\n >\n {themeStore.isDark ? 'Light Mode' : 'Dark Mode'}\n </button>\n </div>\n </div>\n{/if}\n\n<AppBar>\n <AppBar.Toolbar class=\"grid-cols-[1fr_auto_1fr]\">\n <AppBar.Lead>\n <a\n href=\"/\"\n class=\"text-xl font-bold text-surface-50-950 hover:text-primary-400-500 transition-colors\"\n >\n __PROJECT_NAME__\n </a>\n </AppBar.Lead>\n\n <AppBar.Headline />\n\n <AppBar.Trail>\n <div class=\"hidden md:flex items-center gap-2\">\n <ThemeToggle />\n </div>\n\n <button\n onclick={() => (mobileMenuOpen = !mobileMenuOpen)}\n class=\"md:hidden btn-icon text-surface-50-950\"\n aria-label=\"Menu\"\n >\n {#if mobileMenuOpen}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n {:else}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"M3 12h18M3 6h18M3 18h18\" />\n </svg>\n {/if}\n </button>\n </AppBar.Trail>\n </AppBar.Toolbar>\n</AppBar>\n",
|
|
10
10
|
"/lib/data/links.ts": "const links = {\n githubForge: {\n name: 'GitHub',\n href: 'https://github.com/lelabdev/svelteForge'\n },\n githubLudo: {\n name: 'GitHub',\n href: 'https://github.com/LudoLoops'\n },\n betterAuth: {\n name: 'Better Auth',\n href: 'https://better-auth.com'\n },\n shiki: {\n name: 'Shiki',\n href: 'https://shiki.style/'\n },\n kofi: {\n name: 'ko-fi',\n href: 'https://ko-fi.com/ludoloops'\n },\n lelab: {\n name: 'LeLab.dev',\n href: 'https://lelab.dev'\n },\n ludoloops: {\n name: 'LudoLoops',\n href: 'https://ludoloops.dev/'\n }\n};\nexport default links;\n",
|
|
11
|
-
"/lib/sections/QuickStart.svelte": "<script lang=\"ts\">\n import { Badge, Card } from '$lib/components/ui';\n import Icon from '$lib/components/icons/Icon.svelte';\n\n const steps = [\n {\n number: '1',\n title: 'Create',\n description: 'One CLI command. Choose Landing or Full Stack.',\n icon: 'plus-circle'\n },\n {\n number: '2',\n title: 'Configure',\n description: 'Setup script generates .env, DB, admin. Zero files to edit.',\n icon: 'wrench'\n },\n {\n number: '3',\n title: 'Ship',\n description: 'Everything wired. Start coding what makes your project unique.',\n icon: 'rocket-launch'\n }\n ];\n\n const commands = [\n 'bunx sv create my-project --template minimal --types ts --add tailwindcss',\n 'cd my-project',\n 'bunx sv add @
|
|
11
|
+
"/lib/sections/QuickStart.svelte": "<script lang=\"ts\">\n import { Badge, Card } from '$lib/components/ui';\n import Icon from '$lib/components/icons/Icon.svelte';\n\n const steps = [\n {\n number: '1',\n title: 'Create',\n description: 'One CLI command. Choose Landing or Full Stack.',\n icon: 'plus-circle'\n },\n {\n number: '2',\n title: 'Configure',\n description: 'Setup script generates .env, DB, admin. Zero files to edit.',\n icon: 'wrench'\n },\n {\n number: '3',\n title: 'Ship',\n description: 'Everything wired. Start coding what makes your project unique.',\n icon: 'rocket-launch'\n }\n ];\n\n const commands = [\n 'bunx sv create my-project --template minimal --types ts --add tailwindcss',\n 'cd my-project',\n 'bunx sv add @ludoloops/svelteforge=template:landing',\n 'bun run dev'\n ];\n<\/script>\n\n<section class=\"bg-surface-100-900 px-6 py-20\">\n <div class=\"mx-auto max-w-5xl\">\n <div class=\"mb-12 text-center\">\n <h2 class=\"title mb-4 text-4xl font-bold text-surface-950-50\">How it works</h2>\n <p class=\"subtitle text-xl text-surface-600-400\">Three steps. Not thirty.</p>\n </div>\n\n <!-- 3 Steps -->\n <div class=\"mb-12 grid gap-8 sm:grid-cols-3\">\n {#each steps as step (step)}\n <div class=\"text-center\">\n <div\n class=\"mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-primary-500 text-xl font-bold text-white\"\n >\n {step.number}\n </div>\n <h3 class=\"title mb-2 text-xl font-semibold text-surface-950-50\">\n {step.title}\n </h3>\n <p class=\"subtitle text-surface-600-400\">{step.description}</p>\n </div>\n {/each}\n </div>\n\n <!-- Code Block -->\n <Card variant=\"flat\" class=\"bg-surface-800-900 p-0\" noPadding>\n <div class=\"p-8 font-mono text-sm text-surface-200-700\">\n {#each commands as cmd, i}\n <div class=\"mb-2 flex items-center gap-2\">\n <span class=\"text-surface-500\">➜</span>\n <span class=\"text-primary-400\">$</span>\n <span>{cmd}</span>\n </div>\n {/each}\n </div>\n </Card>\n\n <!-- Template Badges -->\n <div class=\"mt-12 text-center\">\n <p class=\"subtitle mb-6 text-lg text-surface-600-400\">Choose your template:</p>\n <div class=\"flex flex-wrap justify-center gap-3\">\n <Badge variant=\"primary\">Full Stack — Auth, DB, 40+ components</Badge>\n <Badge variant=\"surface\">Landing — Minimal, UI only</Badge>\n </div>\n </div>\n </div>\n</section>\n",
|
|
12
12
|
"/lib/sections/Stats.svelte": "<script lang=\"ts\">\n import { Card } from '$lib/components/ui';\n import DynamicCounter from '$lib/components/anim/DynamicCounter.svelte';\n\n const stats = [\n { label: 'Hours Saved', suffix: '+', value: 20, description: 'On every new project', color: 'primary' },\n { label: 'Components', suffix: '+', value: 30, description: 'Ready to use', color: 'secondary' },\n { label: 'Lines of Code', suffix: '+', value: 5000, description: 'Pre-written for you', color: 'tertiary' },\n { label: 'Time to Deploy', value: 10, prefix: '<', suffix: 'min', description: 'From clone to production', color: 'success' }\n ];\n<\/script>\n\n<section class=\"relative bg-surface-100-900 px-6 py-16\">\n <div class=\"mx-auto max-w-7xl\">\n <div class=\"mb-12 text-center\">\n <h2 class=\"title mb-3 text-2xl font-bold text-surface-950-50 sm:text-3xl\">You know the routine.</h2>\n <p class=\"subtitle text-surface-600-400\">Every project, the same thing.</p>\n </div>\n\n <div class=\"grid gap-8 sm:grid-cols-2 lg:grid-cols-4\">\n {#each stats as stat, i (stat)}\n <Card variant=\"flat\" class=\"border-t-4 p-8 text-center border-{stat.color}-500\">\n <span class=\"title mb-2 block text-4xl font-bold text-{stat.color}-500\">\n {stat.prefix ?? ''}<DynamicCounter suffix={stat.suffix} target={stat.value} duration={3} />\n </span>\n <div class=\"mb-1 text-xl font-semibold text-surface-900-50\">{stat.label}</div>\n <div class=\"text-sm text-surface-600-400\">{stat.description}</div>\n </Card>\n {/each}\n </div>\n\n <div class=\"mt-10 text-center\">\n <p class=\"subtitle mb-4 text-lg text-surface-600-400\">\n 15 hours rebuilding what already exists. And you haven't even started your product.\n </p>\n <p class=\"title text-xl font-bold text-primary-500\">\n What if all of this took 2 minutes?\n </p>\n </div>\n </div>\n</section>\n",
|
|
13
13
|
"/lib/sections/UseCase.svelte": "<script>\n import { Card } from '$lib/components/ui';\n import Icon from '$lib/components/icons/Icon.svelte';\n\n const points = [\n {\n icon: 'shieldCheck',\n title: 'MIT license — use it however you want',\n borderColor: 'border-primary-500',\n iconBg: 'bg-primary-400-600/40',\n textColor: 'text-primary-500'\n },\n {\n icon: 'arrowSquareOut',\n title: 'No vendor lock-in — it\\'s your codebase',\n borderColor: 'border-secondary-500',\n iconBg: 'bg-secondary-400-600/40',\n textColor: 'text-secondary-500'\n },\n {\n icon: 'clock',\n title: 'Built on sv create — you follow SvelteKit, not a fork',\n borderColor: 'border-tertiary-500',\n iconBg: 'bg-tertiary-400-600/40',\n textColor: 'text-tertiary-500'\n },\n {\n icon: 'airplane',\n title: 'Svelte community — one niche, done right',\n borderColor: 'border-success-500',\n iconBg: 'bg-success-400-600/40',\n textColor: 'text-success-500'\n }\n ];\n<\/script>\n\n<section class=\"relative bg-surface-50 px-6 py-20\">\n <div class=\"mx-auto max-w-4xl\">\n <div class=\"mb-16 text-center\">\n <h2 class=\"title mb-4 text-4xl font-bold text-surface-950-50\">Open source. For real.</h2>\n <p class=\"subtitle text-xl text-surface-600\">\n No hidden freemium, no surprise at upgrade time. The code is there, it stays there.\n </p>\n </div>\n\n <div class=\"grid gap-6 sm:grid-cols-2\">\n {#each points as point (point)}\n <Card variant=\"flat\" class=\"border-l-4 {point.borderColor} bg-surface-100-900 p-6 transition-all hover:scale-105 hover:shadow-lg\">\n <div class=\"flex items-start gap-4\">\n <div class=\"rounded-lg {point.iconBg} p-3\">\n <Icon name={point.icon} size={24} class={point.textColor} />\n </div>\n <p class=\"subtitle text-lg font-medium text-surface-950-50\">{point.title}</p>\n </div>\n </Card>\n {/each}\n </div>\n </div>\n</section>\n",
|
|
14
14
|
"/lib/sections/Include.svelte": "<script lang=\"ts\">\n import { Card } from '$lib/components/ui';\n\n // Define the data structure for the cards\n type IncludeItem = {\n title: string;\n description: string;\n };\n\n // Items to keep\n const keepItems: IncludeItem[] = [\n {\n title: 'Authentication System',\n description: '- /login, /register, hooks.server.ts'\n },\n {\n title: 'UI Component Library',\n description: '- src/lib/components/ui/'\n },\n {\n title: 'Database Setup',\n description: '- src/lib/server/db/'\n },\n {\n title: 'Security Helpers',\n description: '- src/lib/server/security.ts'\n },\n {\n title: 'Type Definitions',\n description: '- src/app.d.ts'\n }\n ];\n\n // Items to delete\n const deleteItems: IncludeItem[] = [\n {\n title: '/demo-ui route',\n description: '- Delete after exploring components'\n },\n {\n title: '/carta route',\n description: '- Delete if not using Markdown'\n },\n {\n title: '/dashboard & /admin',\n description: '- Example protected routes'\n },\n {\n title: 'src/lib/components/Carta/',\n description: '- If not using Markdown editor'\n },\n {\n title: 'src/lib/components/SortDnD/',\n description: '- If not using drag & drop'\n }\n ];\n<\/script>\n\n<section class=\"bg-surface-100 px-6 py-20\">\n <div class=\"mx-auto max-w-7xl\">\n <div class=\"grid gap-12 lg:grid-cols-2\">\n <!-- What to Keep column -->\n <div>\n <div class=\"mb-6 flex items-center gap-3\">\n <div class=\"rounded-full bg-success-500/20 p-2\">\n <div class=\"h-3 w-3 rounded-full bg-success-500\"></div>\n </div>\n <h2 class=\"text-3xl font-bold text-surface-900-50\">✅ What to Keep</h2>\n </div>\n <div class=\"space-y-3\">\n {#each keepItems as item, index (index)}\n <Card\n variant=\"flat\"\n class=\"border-l-4 border-success-500 bg-success-50-950/80 p-4 transition-all hover:scale-102 hover:shadow-md\"\n >\n <strong class=\"text-success-700-300\">{item.title}</strong>\n <span class=\"text-surface-600-400\">{item.description}</span>\n </Card>\n {/each}\n </div>\n </div>\n\n <!-- What to Delete column -->\n <div>\n <div class=\"mb-6 flex items-center gap-3\">\n <div class=\"rounded-full bg-error-500/20 p-2\">\n <div class=\"h-3 w-3 rounded-full bg-error-500\"></div>\n </div>\n <h2 class=\"text-3xl font-bold text-surface-950-50\">❌ What to Delete (Examples)</h2>\n </div>\n <div class=\"space-y-3\">\n {#each deleteItems as item, index (index)}\n <Card\n variant=\"flat\"\n class=\"border-l-4 border-error-500 bg-error-200-800/40 p-4 transition-all hover:scale-102 hover:shadow-md\"\n >\n <strong class=\"text-error-700-300\">{item.title}</strong>\n <span class=\"text-surface-600-400\">{item.description}</span>\n </Card>\n {/each}\n </div>\n </div>\n </div>\n </div>\n</section>\n",
|
|
@@ -156,54 +156,123 @@ const fullstackFiles = {
|
|
|
156
156
|
* Apply Landing mode files via sv.file()
|
|
157
157
|
* Landing = UI base kit for building a landing page
|
|
158
158
|
*/
|
|
159
|
+
const UI_SKIP = [
|
|
160
|
+
"AuthCard",
|
|
161
|
+
"DataTable",
|
|
162
|
+
"NavigationLoader",
|
|
163
|
+
"NotificationBadge",
|
|
164
|
+
"SearchInput",
|
|
165
|
+
".test.ts"
|
|
166
|
+
];
|
|
167
|
+
const LAYOUT_SKIP = ["auth-buttons", "AdminSidebar"];
|
|
168
|
+
function shouldSkipUi(name) {
|
|
169
|
+
return UI_SKIP.some((s) => name.startsWith(s) || name.endsWith(s));
|
|
170
|
+
}
|
|
171
|
+
function shouldSkipLayout(name) {
|
|
172
|
+
return LAYOUT_SKIP.some((s) => name.startsWith(s));
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Generate a barrel index.ts that only exports files present in the filtered set
|
|
176
|
+
*/
|
|
177
|
+
function generateBarrel(files, directory, stripExtension = true) {
|
|
178
|
+
const lines = [];
|
|
179
|
+
const sortedPaths = [...files.keys()].filter((p) => p.startsWith(directory)).sort();
|
|
180
|
+
for (const path of sortedPaths) {
|
|
181
|
+
const name = path.split("/").pop() || "";
|
|
182
|
+
if (name === "index.ts" || name.endsWith(".test.ts")) continue;
|
|
183
|
+
const baseName = stripExtension ? name.replace(/\.\w+$/, "") : name;
|
|
184
|
+
if (name.endsWith(".svelte")) {
|
|
185
|
+
const componentName = baseName;
|
|
186
|
+
lines.push(`export { default as ${componentName} } from './${name}';`);
|
|
187
|
+
} else if (name.endsWith(".ts")) lines.push(`export * from './${name}';`);
|
|
188
|
+
}
|
|
189
|
+
return lines.join("\n") + "\n";
|
|
190
|
+
}
|
|
159
191
|
function applyLandingMode(sv, landingFiles, fullstackFiles, projectName) {
|
|
160
|
-
const
|
|
192
|
+
const includedFiles = /* @__PURE__ */ new Map();
|
|
193
|
+
const uiFiles = /* @__PURE__ */ new Map();
|
|
194
|
+
const uiFormFiles = /* @__PURE__ */ new Map();
|
|
195
|
+
const uiRichTextFiles = /* @__PURE__ */ new Map();
|
|
196
|
+
const layoutFiles = /* @__PURE__ */ new Map();
|
|
197
|
+
for (const [path, content] of Object.entries(fullstackFiles)) {
|
|
161
198
|
if (path.startsWith("/lib/components/ui/")) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
"SearchInput",
|
|
169
|
-
".test.ts"
|
|
170
|
-
].some((s) => name.startsWith(s) || name.endsWith(s))) return false;
|
|
171
|
-
return true;
|
|
199
|
+
if (shouldSkipUi(path.split("/").pop() || "")) continue;
|
|
200
|
+
includedFiles.set(path, content);
|
|
201
|
+
if (path.startsWith("/lib/components/ui/form/") && !path.endsWith("index.ts")) uiFormFiles.set(path, content);
|
|
202
|
+
else if (path.startsWith("/lib/components/ui/rich-text/") && !path.endsWith("index.ts")) uiRichTextFiles.set(path, content);
|
|
203
|
+
else if (!path.endsWith("index.ts")) uiFiles.set(path, content);
|
|
204
|
+
continue;
|
|
172
205
|
}
|
|
173
206
|
if (path.startsWith("/lib/components/layout/")) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
207
|
+
if (shouldSkipLayout(path.split("/").pop() || "")) continue;
|
|
208
|
+
includedFiles.set(path, content);
|
|
209
|
+
if (!path.endsWith("index.ts")) layoutFiles.set(path, content);
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
if (path === "/lib/components/ui/index.ts" || path === "/lib/components/ui/form/index.ts" || path === "/lib/components/layout/index.ts" || path === "/lib/components/index.ts") continue;
|
|
213
|
+
if (path.startsWith("/lib/components/icons/")) {
|
|
214
|
+
includedFiles.set(path, content);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (path.startsWith("/lib/styles/")) {
|
|
218
|
+
includedFiles.set(path, content);
|
|
219
|
+
continue;
|
|
177
220
|
}
|
|
178
|
-
if (path.startsWith("/lib/components/icons/")) return true;
|
|
179
|
-
if (path === "/lib/components/index.ts") return true;
|
|
180
|
-
if (path.startsWith("/lib/components/layout/index.ts")) return true;
|
|
181
|
-
if (path.startsWith("/lib/components/ui/index.ts")) return true;
|
|
182
|
-
if (path.startsWith("/lib/components/ui/form/index.ts")) return true;
|
|
183
|
-
if (path.startsWith("/lib/styles/")) return true;
|
|
184
221
|
if (path.startsWith("/lib/utils/")) {
|
|
185
222
|
const name = path.split("/").pop() || "";
|
|
186
|
-
if (name.endsWith(".test.ts"))
|
|
223
|
+
if (name.endsWith(".test.ts")) continue;
|
|
187
224
|
if ([
|
|
188
225
|
"export.ts",
|
|
189
226
|
"slugify.ts",
|
|
190
227
|
"form-errors.ts"
|
|
191
|
-
].includes(name))
|
|
192
|
-
|
|
228
|
+
].includes(name)) continue;
|
|
229
|
+
includedFiles.set(path, content);
|
|
230
|
+
continue;
|
|
193
231
|
}
|
|
194
232
|
if ([
|
|
195
233
|
"/lib/errors.ts",
|
|
196
234
|
"/lib/logger.ts",
|
|
197
235
|
"/lib/types.ts",
|
|
198
236
|
"/lib/index.ts"
|
|
199
|
-
].includes(path))
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if (path
|
|
204
|
-
|
|
237
|
+
].includes(path)) {
|
|
238
|
+
includedFiles.set(path, content);
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (path.startsWith("/lib/schemas/")) {
|
|
242
|
+
includedFiles.set(path, content);
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (["/app.css", "/app.html"].includes(path)) {
|
|
246
|
+
includedFiles.set(path, content);
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
if (path.startsWith("/routes/(legal)/")) {
|
|
250
|
+
includedFiles.set(path, content);
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (path === "/routes/+error.svelte") {
|
|
254
|
+
includedFiles.set(path, content);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
for (const [path, content] of includedFiles) sv.file(`src${path}`, () => content);
|
|
259
|
+
sv.file("src/lib/components/ui/index.ts", () => {
|
|
260
|
+
let barrel = generateBarrel(uiFiles, "/lib/components/ui/");
|
|
261
|
+
if (uiRichTextFiles.size > 0) barrel += "\n// === Rich Text ===\nexport * from './rich-text';\n";
|
|
262
|
+
if (uiFormFiles.size > 0) barrel += "\n// === Form ===\nexport * from './form';\n";
|
|
263
|
+
return barrel;
|
|
264
|
+
});
|
|
265
|
+
sv.file("src/lib/components/ui/form/index.ts", () => {
|
|
266
|
+
const formComponents = [];
|
|
267
|
+
for (const path of [...uiFormFiles.keys()].sort()) {
|
|
268
|
+
const baseName = (path.split("/").pop() || "").replace(".svelte", "");
|
|
269
|
+
formComponents.push(baseName);
|
|
270
|
+
}
|
|
271
|
+
return `${formComponents.map((c) => `import ${c} from './${c}.svelte';`).join("\n")}\n\nexport { ${formComponents.join(", ")} };\n`;
|
|
272
|
+
});
|
|
273
|
+
sv.file("src/lib/components/layout/index.ts", () => {
|
|
274
|
+
return generateBarrel(layoutFiles, "/lib/components/layout/");
|
|
205
275
|
});
|
|
206
|
-
for (const [path, content] of sharedPaths) sv.file(`src${path}`, () => content);
|
|
207
276
|
for (const [path, content] of Object.entries(landingFiles)) {
|
|
208
277
|
const finalContent = content.replace(/__PROJECT_NAME__/g, projectName);
|
|
209
278
|
sv.file(`src${path}`, () => finalContent);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ludoloops/svelteforge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "sv community addon — 34 theme-aware UI components, admin dashboard, and 3-layer theme system for SvelteKit",
|
|
6
6
|
"author": "Ludo (https://lelab.dev)",
|