Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b4132b5
fix for empty layers toggle showing small circle
cycle4passion Jan 11, 2026
56945c5
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 11, 2026
3aaa686
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 14, 2026
07b33de
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 16, 2026
26c0b12
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 19, 2026
e5b8d25
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 19, 2026
617112a
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 21, 2026
20f4b33
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 24, 2026
60ca72b
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 25, 2026
077da76
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 25, 2026
3268020
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 25, 2026
b1057d2
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 26, 2026
20e5cf5
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 26, 2026
ad1d5c1
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 27, 2026
555775e
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 31, 2026
9c170a6
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Jan 31, 2026
658f85e
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Feb 1, 2026
f8e3a88
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Feb 1, 2026
1bd9609
Merge remote-tracking branch 'upstream/docs-v2' into docs-v2
cycle4passion Feb 1, 2026
7fd7068
Layerchart Playground
cycle4passion Feb 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@
"@types/d3-scale-chromatic": "^3.1.0",
"@types/d3-shape": "^3.1.8",
"@types/d3-time": "^3.0.4",
"@types/file-saver": "^2.0.7",
"@types/hast": "^3.0.4",
"@types/jszip": "^3.4.1",
"@types/node": "^25.2.0",
"@types/shapefile": "^0.6.4",
"@types/sharp": "^0.32.0",
Expand All @@ -84,6 +86,7 @@
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.14.0",
"file-saver": "^2.0.5",
"github-slugger": "^2.0.0",
"globals": "^17.3.0",
"layerchart": "workspace:*",
Expand Down Expand Up @@ -128,6 +131,7 @@
"@uiw/codemirror-theme-github": "^4.25.4",
"@webcontainer/api": "^1.6.1",
"ansi_up": "^6.0.6",
"codemirror": "^6.0.2"
"codemirror": "^6.0.2",
"jszip": "^3.10.1"
}
}
82 changes: 75 additions & 7 deletions docs/src/routes/docs/playground/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,84 @@
await loadFileContent(filepath);
}

// Save Project Locally
// Recursively collect all files from the WebContainer as a flat map
async function collectFiles(dir: string = ''): Promise<Record<string, string>> {
if (!webcontainerInstance) return {};

const files: Record<string, string> = {};
const entries = await webcontainerInstance.fs.readdir(dir || '/', { withFileTypes: true });

for (const entry of entries) {
const fullPath = dir ? `${dir}/${entry.name}` : entry.name;

// Skip node_modules, .git, and lock files
if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === 'pnpm-lock.yaml')
continue;

if (entry.isDirectory()) {
Object.assign(files, await collectFiles(fullPath));
} else {
try {
files[fullPath] = await webcontainerInstance.fs.readFile(fullPath, 'utf-8');
} catch {
// Skip binary/unreadable files
}
}
}

return files;
}

// Save Project Locally (downloads ZIP to Downloads folder)
async function saveProject() {
// This needs wired up
if (!webcontainerInstance) return;

try {
const JSZip = (await import('jszip')).default;
const zip = new JSZip();

const now = new Date();
const timestamp = now.toISOString().replace(/[:.]/g, '-');
const folderName = `layerchart-${timestamp}`;
const filename = `${folderName}.zip`;

const rootFolder = zip.folder(folderName)!;
const files = await collectFiles();

for (const [path, content] of Object.entries(files)) {
rootFolder.file(path, content);
}

const { saveAs } = await import('file-saver');
const blob = await zip.generateAsync({ type: 'blob' });
saveAs(blob, filename);
} catch (err) {
console.error('Failed to save project:', err);
alert('Failed to save project. Check console for details.');
}
}

// Open Project in StackBlitz
async function openInStackBlitz() {
// This needs wired up
if (!webcontainerInstance) return;

try {
const sdk = (await import('@stackblitz/sdk')).default;
const files = await collectFiles();

sdk.openProject(
{
title: 'LayerChart Playground',
files,
template: 'node'
},
{
newWindow: true,
openFile: 'src/routes/+page.svelte'
}
);
} catch (err) {
console.error('Failed to open in StackBlitz:', err);
}
}

// Open Project in REPL
Expand Down Expand Up @@ -400,12 +470,10 @@
</div>
<Tooltip title="Open in StackBlitz" placement="top" offset={6}>
<Button
href="https://stackblitz.com"
icon={SimpleIconsStackblitz}
size="sm"
variant="fill-light"
target="_blank"
onclick={openInStackBlitz()}
onclick={openInStackBlitz}
/>
</Tooltip>
<Tooltip title="Open in REPL" placement="top" offset={6}>
Expand Down
Loading