From 23d0147199b06e929e208b219015051f0596a585 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Fri, 20 Dec 2024 15:02:58 +0100 Subject: [PATCH 1/8] feat: "download app" possibility closes #827 --- apps/svelte.dev/.gitignore | 2 + apps/svelte.dev/package.json | 1 + .../svelte.dev/scripts/get_svelte_template.js | 89 +++++++++++++++++++ apps/svelte.dev/scripts/update.js | 1 + .../(authed)/playground/[id]/+page.svelte | 58 ++++++++++++ apps/svelte.dev/vite.config.ts | 5 ++ pnpm-lock.yaml | 8 ++ 7 files changed, 164 insertions(+) create mode 100644 apps/svelte.dev/scripts/get_svelte_template.js diff --git a/apps/svelte.dev/.gitignore b/apps/svelte.dev/.gitignore index 321615edd..82cbd2da7 100644 --- a/apps/svelte.dev/.gitignore +++ b/apps/svelte.dev/.gitignore @@ -6,6 +6,8 @@ /src/routes/_home/Supporters/contributors.js /src/routes/_home/Supporters/donors.jpg /src/routes/_home/Supporters/donors.js +/scripts/svelte-template +/static/svelte-template.json # git-repositories of synced docs go here /repos/ diff --git a/apps/svelte.dev/package.json b/apps/svelte.dev/package.json index 64a7ab86f..429924ca8 100644 --- a/apps/svelte.dev/package.json +++ b/apps/svelte.dev/package.json @@ -37,6 +37,7 @@ "cookie": "^0.7.0", "d3-geo": "^3.1.0", "d3-geo-projection": "^4.0.0", + "do-not-zip": "^1.0.0", "editor": "workspace:*", "flexsearch": "^0.7.43", "flru": "^1.0.2", diff --git a/apps/svelte.dev/scripts/get_svelte_template.js b/apps/svelte.dev/scripts/get_svelte_template.js new file mode 100644 index 000000000..82ed367f8 --- /dev/null +++ b/apps/svelte.dev/scripts/get_svelte_template.js @@ -0,0 +1,89 @@ +// @ts-check +import { execSync } from 'node:child_process'; +import { + copyFileSync, + mkdirSync, + readdirSync, + readFileSync, + rmSync, + statSync, + writeFileSync +} from 'node:fs'; +import { join } from 'node:path'; + +// This download the currente Vite template from Github, adjusts it to our needs, and saves it to static/svelte-template.json +// This is used by the Svelte REPL as part of the "download project" feature + +const force = process.env.FORCE_UPDATE === 'true'; +const output_file = 'static/svelte-template.json'; +const output_dir = 'scripts/svelte-template'; + +try { + if (!force && statSync(output_file)) { + console.info(`[update/template] ${output_file} exists. Skipping`); + process.exit(0); + } +} catch { + // fetch svelte app + rmSync(output_dir, { force: true, recursive: true }); + execSync(`npx degit vitejs/vite/packages/create-vite/template-svelte-ts ${output_dir}`, { + stdio: 'inherit' + }); + + // remove everything that's not needed + rmSync(join(output_dir, 'src/assets'), { force: true, recursive: true }); + rmSync(join(output_dir, 'src/lib'), { force: true, recursive: true }); + rmSync(join(output_dir, 'src/app.css'), { force: true, recursive: true }); + rmSync(join(output_dir, 'src/App.svelte'), { force: true, recursive: true }); + rmSync(join(output_dir, 'src/main.ts'), { force: true, recursive: true }); + rmSync(join(output_dir, 'public'), { force: true, recursive: true }); + + // add what we need + mkdirSync(join(output_dir, 'public')); + copyFileSync('static/favicon.png', join(output_dir, 'public/favicon.png')); + + // build svelte-app.json + const files = []; + + function get_all_files(dir) { + const files = []; + const items = readdirSync(dir, { withFileTypes: true }); + + for (const item of items) { + const full_path = join(dir, item.name); + if (item.isDirectory()) { + files.push(...get_all_files(full_path)); + } else { + files.push(full_path); + } + } + + return files; + } + + const all_files = get_all_files(output_dir); + + for (let path of all_files) { + const bytes = readFileSync(path); + const string = bytes.toString(); + let data = bytes.compare(Buffer.from(string)) === 0 ? string : [...bytes]; + + // handle some special cases + path = path.slice(output_dir.length + 1); + if (path.endsWith('_gitignore')) path = path.slice(0, -10) + '.gitignore'; + + if (path.endsWith('index.html')) { + data = /** @type {any} */ (data).replace( + '', + '' + ); + } + + files.push({ path, data }); + } + + writeFileSync(output_file, JSON.stringify(files)); + + // remove output dir afterwards to prevent it messing with Vite watcher + rmSync(output_dir, { force: true, recursive: true }); +} diff --git a/apps/svelte.dev/scripts/update.js b/apps/svelte.dev/scripts/update.js index 41a4c2e9b..9c25d958d 100644 --- a/apps/svelte.dev/scripts/update.js +++ b/apps/svelte.dev/scripts/update.js @@ -9,3 +9,4 @@ const env = { fork(`${dir}/get_contributors.js`, { env }); fork(`${dir}/get_donors.js`, { env }); +fork(`${dir}/get_svelte_template.js`, { env }); diff --git a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte index f883a1ec6..3b12c1fd6 100644 --- a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte +++ b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte @@ -9,6 +9,7 @@ import { compress_and_encode_text, decode_and_decompress_text } from './gzip.js'; import { page } from '$app/state'; import type { File } from 'editor'; + import * as doNotZip from 'do-not-zip'; let { data } = $props(); @@ -113,6 +114,57 @@ } } + async function download() { + const { files: components, imports } = repl.toJSON(); + + const files: Array<{ path: string; data: string }> = await ( + await fetch('/svelte-template.json') + ).json(); + + if (imports.length > 0) { + const idx = files.findIndex(({ path }) => path === 'package.json'); + const pkg = JSON.parse(files[idx].data); + const { devDependencies } = pkg; + imports.forEach((mod) => { + const match = /^(@[^/]+\/)?[^@/]+/.exec(mod)!; + devDependencies[match[0]] = 'latest'; + }); + pkg.devDependencies = devDependencies; + files[idx].data = JSON.stringify(pkg, null, ' '); + } + + files.push( + ...components.map((component) => ({ + path: `src/${component.name}`, + data: (component as File).contents + })) + ); + files.push({ + path: `src/main.ts`, + data: `import App from './App.svelte'; +import { mount } from 'svelte'; + +const app = mount(App, { + target: document.body +}); + +export default app;` + }); + + const downloadBlob = (blob: any, filename: string) => { + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = filename; + link.style.display = 'none'; + document.body.appendChild(link); + link.click(); + URL.revokeObjectURL(url); + link.remove(); + }; + downloadBlob(doNotZip.toBlob(files), 'svelte-app.zip'); + } + async function update_hash() { // Only change hash when necessary to avoid polluting everyone's browser history if (modified) { @@ -175,6 +227,12 @@ sessionStorage.setItem(STORAGE_KEY, json); } }} + onkeydown={(e) => { + // TODO remove once dropdown from VIM UI PR is merged + if (e.ctrlKey && e.key === 'd') { + download(); + } + }} /> diff --git a/apps/svelte.dev/vite.config.ts b/apps/svelte.dev/vite.config.ts index e1d4ffc83..a008b37ee 100644 --- a/apps/svelte.dev/vite.config.ts +++ b/apps/svelte.dev/vite.config.ts @@ -3,6 +3,8 @@ import { enhancedImages } from '@sveltejs/enhanced-img'; import type { PluginOption, UserConfig } from 'vite'; import { browserslistToTargets } from 'lightningcss'; import browserslist from 'browserslist'; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; const plugins: PluginOption[] = [ enhancedImages(), @@ -62,6 +64,9 @@ const config: UserConfig = { cssMinify: 'lightningcss' }, server: { + watch: { + ignored: [dirname(fileURLToPath(import.meta.url)) + '/scripts/**'] + }, fs: { allow: ['../../packages', '../../../KIT/kit/packages/kit'] }, // for SvelteKit tutorial headers: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a5ee117b1..4b6435aa2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -77,6 +77,9 @@ importers: d3-geo-projection: specifier: ^4.0.0 version: 4.0.0 + do-not-zip: + specifier: ^1.0.0 + version: 1.0.0 editor: specifier: workspace:* version: link:../../packages/editor @@ -2131,6 +2134,9 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + do-not-zip@1.0.0: + resolution: {integrity: sha512-Pgd81ET43bhAGaN2Hq1zluSX1FmD7kl7KcV9ER/lawiLsRUB9pRA5y8r6us29Xk6BrINZETO8TjhYwtwafWUww==} + dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} @@ -4967,6 +4973,8 @@ snapshots: dependencies: path-type: 4.0.0 + do-not-zip@1.0.0: {} + dom-accessibility-api@0.5.16: {} dotenv@16.4.7: {} From acf9578b5520ccdc863cc203358b33f9eb874413 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Fri, 20 Dec 2024 15:16:50 +0100 Subject: [PATCH 2/8] lint --- .../src/routes/(authed)/playground/[id]/+page.svelte | 1 + apps/svelte.dev/vite.config.ts | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte index 3b12c1fd6..149869747 100644 --- a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte +++ b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte @@ -9,6 +9,7 @@ import { compress_and_encode_text, decode_and_decompress_text } from './gzip.js'; import { page } from '$app/state'; import type { File } from 'editor'; + // @ts-expect-error this library was created way before TS conquered the world import * as doNotZip from 'do-not-zip'; let { data } = $props(); diff --git a/apps/svelte.dev/vite.config.ts b/apps/svelte.dev/vite.config.ts index a008b37ee..e1d4ffc83 100644 --- a/apps/svelte.dev/vite.config.ts +++ b/apps/svelte.dev/vite.config.ts @@ -3,8 +3,6 @@ import { enhancedImages } from '@sveltejs/enhanced-img'; import type { PluginOption, UserConfig } from 'vite'; import { browserslistToTargets } from 'lightningcss'; import browserslist from 'browserslist'; -import { fileURLToPath } from 'node:url'; -import { dirname } from 'node:path'; const plugins: PluginOption[] = [ enhancedImages(), @@ -64,9 +62,6 @@ const config: UserConfig = { cssMinify: 'lightningcss' }, server: { - watch: { - ignored: [dirname(fileURLToPath(import.meta.url)) + '/scripts/**'] - }, fs: { allow: ['../../packages', '../../../KIT/kit/packages/kit'] }, // for SvelteKit tutorial headers: { From 12f7095295505cec594d2282f90340ce2df2f7a0 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Fri, 20 Dec 2024 17:38:36 +0100 Subject: [PATCH 3/8] maybe this? --- apps/svelte.dev/scripts/get_svelte_template.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/svelte.dev/scripts/get_svelte_template.js b/apps/svelte.dev/scripts/get_svelte_template.js index 82ed367f8..756018c4b 100644 --- a/apps/svelte.dev/scripts/get_svelte_template.js +++ b/apps/svelte.dev/scripts/get_svelte_template.js @@ -10,13 +10,14 @@ import { writeFileSync } from 'node:fs'; import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; // This download the currente Vite template from Github, adjusts it to our needs, and saves it to static/svelte-template.json // This is used by the Svelte REPL as part of the "download project" feature const force = process.env.FORCE_UPDATE === 'true'; -const output_file = 'static/svelte-template.json'; -const output_dir = 'scripts/svelte-template'; +const output_file = fileURLToPath(new URL('../static/svelte-template.json', import.meta.url)); +const output_dir = fileURLToPath(new URL('./svelte-template', import.meta.url)); try { if (!force && statSync(output_file)) { @@ -40,7 +41,10 @@ try { // add what we need mkdirSync(join(output_dir, 'public')); - copyFileSync('static/favicon.png', join(output_dir, 'public/favicon.png')); + copyFileSync( + fileURLToPath(new URL('../static/favicon.png')), + join(output_dir, 'public/favicon.png') + ); // build svelte-app.json const files = []; From 9bc402cc6d0062b54f1cec3153f578846038e102 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Fri, 20 Dec 2024 18:22:47 +0100 Subject: [PATCH 4/8] use SvelteKit instead --- apps/svelte.dev/package.json | 1 + .../svelte.dev/scripts/get_svelte_template.js | 62 ++++++------------- .../(authed)/playground/[id]/+page.svelte | 13 +--- pnpm-lock.yaml | 9 +++ 4 files changed, 29 insertions(+), 56 deletions(-) diff --git a/apps/svelte.dev/package.json b/apps/svelte.dev/package.json index 429924ca8..1db9531c6 100644 --- a/apps/svelte.dev/package.json +++ b/apps/svelte.dev/package.json @@ -73,6 +73,7 @@ "prettier-plugin-svelte": "^3.3.2", "satori": "^0.10.13", "satori-html": "^0.3.2", + "sv": "^0.6.8", "svelte": "5.14.0", "svelte-check": "^4.1.1", "svelte-preprocess": "^6.0.3", diff --git a/apps/svelte.dev/scripts/get_svelte_template.js b/apps/svelte.dev/scripts/get_svelte_template.js index 756018c4b..6dbf784ae 100644 --- a/apps/svelte.dev/scripts/get_svelte_template.js +++ b/apps/svelte.dev/scripts/get_svelte_template.js @@ -1,16 +1,8 @@ // @ts-check -import { execSync } from 'node:child_process'; -import { - copyFileSync, - mkdirSync, - readdirSync, - readFileSync, - rmSync, - statSync, - writeFileSync -} from 'node:fs'; +import { readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; +import { create } from 'sv'; // This download the currente Vite template from Github, adjusts it to our needs, and saves it to static/svelte-template.json // This is used by the Svelte REPL as part of the "download project" feature @@ -25,29 +17,8 @@ try { process.exit(0); } } catch { - // fetch svelte app - rmSync(output_dir, { force: true, recursive: true }); - execSync(`npx degit vitejs/vite/packages/create-vite/template-svelte-ts ${output_dir}`, { - stdio: 'inherit' - }); - - // remove everything that's not needed - rmSync(join(output_dir, 'src/assets'), { force: true, recursive: true }); - rmSync(join(output_dir, 'src/lib'), { force: true, recursive: true }); - rmSync(join(output_dir, 'src/app.css'), { force: true, recursive: true }); - rmSync(join(output_dir, 'src/App.svelte'), { force: true, recursive: true }); - rmSync(join(output_dir, 'src/main.ts'), { force: true, recursive: true }); - rmSync(join(output_dir, 'public'), { force: true, recursive: true }); - - // add what we need - mkdirSync(join(output_dir, 'public')); - copyFileSync( - fileURLToPath(new URL('../static/favicon.png')), - join(output_dir, 'public/favicon.png') - ); - - // build svelte-app.json - const files = []; + // create Svelte-Kit skelton app + create(output_dir, { template: 'minimal', types: 'typescript', name: 'your-app' }); function get_all_files(dir) { const files = []; @@ -58,7 +29,7 @@ try { if (item.isDirectory()) { files.push(...get_all_files(full_path)); } else { - files.push(full_path); + files.push(full_path.replaceAll('\\', '/')); } } @@ -66,26 +37,29 @@ try { } const all_files = get_all_files(output_dir); + const files = []; for (let path of all_files) { const bytes = readFileSync(path); const string = bytes.toString(); let data = bytes.compare(Buffer.from(string)) === 0 ? string : [...bytes]; - // handle some special cases - path = path.slice(output_dir.length + 1); - if (path.endsWith('_gitignore')) path = path.slice(0, -10) + '.gitignore'; - - if (path.endsWith('index.html')) { - data = /** @type {any} */ (data).replace( - '', - '' - ); + if (path.endsWith('routes/+page.svelte')) { + data = `\n\n\n`; } - files.push({ path, data }); + files.push({ path: path.slice(output_dir.length + 1), data }); } + files.push({ + path: 'src/routes/+page.js', + data: + "// Because we don't know whether or not your playground app can run in a server environment, we disable server-side rendering.\n" + + '// Make sure to test whether or not you can re-enable it, as SSR improves perceived performance and site accessibility.\n' + + '// Read more about this option here: https://svelte.dev/docs/kit/page-options#ssr\n' + + 'export const ssr = false;\n' + }); + writeFileSync(output_file, JSON.stringify(files)); // remove output dir afterwards to prevent it messing with Vite watcher diff --git a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte index 149869747..ffb1a52aa 100644 --- a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte +++ b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte @@ -136,21 +136,10 @@ files.push( ...components.map((component) => ({ - path: `src/${component.name}`, + path: `src/routes/${component.name}`, data: (component as File).contents })) ); - files.push({ - path: `src/main.ts`, - data: `import App from './App.svelte'; -import { mount } from 'svelte'; - -const app = mount(App, { - target: document.body -}); - -export default app;` - }); const downloadBlob = (blob: any, filename: string) => { const url = URL.createObjectURL(blob); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4b6435aa2..7c572cd67 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -180,6 +180,9 @@ importers: satori-html: specifier: ^0.3.2 version: 0.3.2 + sv: + specifier: ^0.6.8 + version: 0.6.8 svelte: specifier: 5.14.0 version: 5.14.0 @@ -3000,6 +3003,10 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + sv@0.6.8: + resolution: {integrity: sha512-9+gEOIED7KzyvDVF7W4/L2Nv9ISvFrU0xp8dtEyP1QHWY/1bbz/Fp0Lo7/hgBSkVvvSXV3XMxQsTwz23AOobGw==} + hasBin: true + svelte-check@4.1.1: resolution: {integrity: sha512-NfaX+6Qtc8W/CyVGS/F7/XdiSSyXz+WGYA9ZWV3z8tso14V2vzjfXviKaTFEzB7g8TqfgO2FOzP6XT4ApSTUTw==} engines: {node: '>= 18.0.0'} @@ -5891,6 +5898,8 @@ snapshots: dependencies: has-flag: 4.0.0 + sv@0.6.8: {} + svelte-check@4.1.1(picomatch@4.0.2)(svelte@5.14.0)(typescript@5.5.4): dependencies: '@jridgewell/trace-mapping': 0.3.25 From a000bb697ce0095244fb79aec2393e716471627b Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Fri, 20 Dec 2024 18:36:01 +0100 Subject: [PATCH 5/8] integrate into menu --- apps/svelte.dev/package.json | 1 - .../(authed)/playground/[id]/+page.svelte | 48 ------------------- packages/repl/package.json | 1 + .../src/lib/Input/ComponentSelector.svelte | 4 +- packages/repl/src/lib/Repl.svelte | 47 +++++++++++++++++- pnpm-lock.yaml | 6 +-- 6 files changed, 53 insertions(+), 54 deletions(-) diff --git a/apps/svelte.dev/package.json b/apps/svelte.dev/package.json index 1db9531c6..b94daae83 100644 --- a/apps/svelte.dev/package.json +++ b/apps/svelte.dev/package.json @@ -37,7 +37,6 @@ "cookie": "^0.7.0", "d3-geo": "^3.1.0", "d3-geo-projection": "^4.0.0", - "do-not-zip": "^1.0.0", "editor": "workspace:*", "flexsearch": "^0.7.43", "flru": "^1.0.2", diff --git a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte index ffb1a52aa..f883a1ec6 100644 --- a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte +++ b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte @@ -9,8 +9,6 @@ import { compress_and_encode_text, decode_and_decompress_text } from './gzip.js'; import { page } from '$app/state'; import type { File } from 'editor'; - // @ts-expect-error this library was created way before TS conquered the world - import * as doNotZip from 'do-not-zip'; let { data } = $props(); @@ -115,46 +113,6 @@ } } - async function download() { - const { files: components, imports } = repl.toJSON(); - - const files: Array<{ path: string; data: string }> = await ( - await fetch('/svelte-template.json') - ).json(); - - if (imports.length > 0) { - const idx = files.findIndex(({ path }) => path === 'package.json'); - const pkg = JSON.parse(files[idx].data); - const { devDependencies } = pkg; - imports.forEach((mod) => { - const match = /^(@[^/]+\/)?[^@/]+/.exec(mod)!; - devDependencies[match[0]] = 'latest'; - }); - pkg.devDependencies = devDependencies; - files[idx].data = JSON.stringify(pkg, null, ' '); - } - - files.push( - ...components.map((component) => ({ - path: `src/routes/${component.name}`, - data: (component as File).contents - })) - ); - - const downloadBlob = (blob: any, filename: string) => { - const url = URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = filename; - link.style.display = 'none'; - document.body.appendChild(link); - link.click(); - URL.revokeObjectURL(url); - link.remove(); - }; - downloadBlob(doNotZip.toBlob(files), 'svelte-app.zip'); - } - async function update_hash() { // Only change hash when necessary to avoid polluting everyone's browser history if (modified) { @@ -217,12 +175,6 @@ sessionStorage.setItem(STORAGE_KEY, json); } }} - onkeydown={(e) => { - // TODO remove once dropdown from VIM UI PR is merged - if (e.ctrlKey && e.key === 'd') { - download(); - } - }} /> diff --git a/packages/repl/package.json b/packages/repl/package.json index a16b7e1df..a2c3342cf 100644 --- a/packages/repl/package.json +++ b/packages/repl/package.json @@ -80,6 +80,7 @@ "@sveltejs/site-kit": "workspace:*", "@sveltejs/svelte-json-tree": "^2.2.1", "acorn": "^8.11.3", + "do-not-zip": "^1.0.0", "editor": "workspace:*", "esm-env": "^1.0.0", "esrap": "^1.2.2", diff --git a/packages/repl/src/lib/Input/ComponentSelector.svelte b/packages/repl/src/lib/Input/ComponentSelector.svelte index 719bb5d21..4345379dd 100644 --- a/packages/repl/src/lib/Input/ComponentSelector.svelte +++ b/packages/repl/src/lib/Input/ComponentSelector.svelte @@ -10,9 +10,10 @@ workspace: Workspace; can_migrate: boolean; migrate: () => void; + download: () => void; } - let { runes, onchange, workspace, can_migrate, migrate }: Props = $props(); + let { runes, onchange, workspace, can_migrate, migrate, download }: Props = $props(); let input = $state() as HTMLInputElement; let input_value = $state(workspace.current.name); @@ -170,6 +171,7 @@ + diff --git a/packages/repl/src/lib/Repl.svelte b/packages/repl/src/lib/Repl.svelte index 3b3bd44ae..f83b926dc 100644 --- a/packages/repl/src/lib/Repl.svelte +++ b/packages/repl/src/lib/Repl.svelte @@ -1,4 +1,5 @@ \n\n\n`; + data = `\n\n\n`; } files.push({ path: path.slice(output_dir.length + 1), data }); @@ -60,6 +60,25 @@ try { 'export const ssr = false;\n' }); + // add CSS styles from playground to the project + const html = readFileSync( + join(output_dir, '../../../../packages/repl/src/lib/Output/srcdoc/index.html'), + { encoding: 'utf-8' } + ); + const css = html + .slice(html.indexOf('')) + .split('\n') + .map((line) => + // remove leading \t + line.slice(3) + ) + .join('\n') + .trimStart(); + files.push({ + path: 'src/app.css', + data: css + }); + writeFileSync(output_file, JSON.stringify(files)); // remove output dir afterwards to prevent it messing with Vite watcher