refactor: move studio to frontends workspace

- Move studio from root to frontends/studio/
- Add owner-tools frontend for live blog admin UI
- Add shared ui component library
- Set up npm workspaces for frontends
- Add enhanced code block extension for editor

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Josh 2026-01-12 01:59:56 +02:00
parent c662e41b97
commit bef5dd4437
108 changed files with 8650 additions and 441 deletions

View file

@ -0,0 +1,106 @@
import { PageHeader } from '../components/shared'
import { Icons } from '../components/shared/Icons'
import { Button } from '../components/ui'
export default function DataPage() {
const handleExport = () => {
window.location.href = '/api/studio/export'
}
return (
<div>
<PageHeader />
{/* Panel container - full-bleed borders */}
<div className="-mx-6 lg:-mx-10 mt-6">
{/* Import */}
<div className="px-6 lg:px-10 py-5">
<div className="text-xs font-medium text-muted uppercase tracking-wide">Import</div>
<div className="text-xs text-muted mt-0.5">Import posts from other platforms</div>
</div>
<div className="px-6 lg:px-10 py-6 space-y-4">
<div className="p-4 border border-dashed border-border text-center">
<Icons.Upload className="text-2xl text-muted mb-2" />
<p className="text-sm font-medium mb-1">Upload files</p>
<p className="text-xs text-muted mb-3">
Supports Markdown files or JSON exports
</p>
<Button variant="secondary" Icon={Icons.Upload}>
Choose Files
</Button>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
<button className="p-3 border border-border text-left hover:border-muted transition-colors">
<div className="flex items-center gap-2 mb-1">
<Icons.Ghost className="text-muted" />
<span className="text-sm font-medium">Ghost</span>
</div>
<p className="text-xs text-muted">Import from Ghost JSON export</p>
</button>
<button className="p-3 border border-border text-left hover:border-muted transition-colors">
<div className="flex items-center gap-2 mb-1">
<Icons.PenTool className="text-muted" />
<span className="text-sm font-medium">Substack</span>
</div>
<p className="text-xs text-muted">Import from Substack export</p>
</button>
<button className="p-3 border border-border text-left hover:border-muted transition-colors">
<div className="flex items-center gap-2 mb-1">
<Icons.Posts className="text-muted" />
<span className="text-sm font-medium">Markdown</span>
</div>
<p className="text-xs text-muted">Import Markdown files</p>
</button>
<button className="p-3 border border-border text-left hover:border-muted transition-colors">
<div className="flex items-center gap-2 mb-1">
<Icons.WordPress className="text-muted" />
<span className="text-sm font-medium">WordPress</span>
</div>
<p className="text-xs text-muted">Import from WordPress XML</p>
</button>
</div>
</div>
<div className="border-t border-border" />
{/* Export */}
<div className="px-6 lg:px-10 py-5">
<div className="text-xs font-medium text-muted uppercase tracking-wide">Export</div>
<div className="text-xs text-muted mt-0.5">Download all your blog data</div>
</div>
<div className="px-6 lg:px-10 py-6 space-y-3">
<p className="text-sm text-muted">
Export all your posts, settings, and assets as a ZIP file. This includes:
</p>
<ul className="text-sm text-muted space-y-1 list-disc list-inside">
<li>All posts as Markdown files</li>
<li>Settings as JSON</li>
<li>Uploaded images and assets</li>
</ul>
<Button variant="secondary" Icon={Icons.Download} onClick={handleExport}>
Export All Data
</Button>
</div>
<div className="border-t border-border" />
{/* Danger Zone */}
<div className="px-6 lg:px-10 py-5">
<div className="text-xs font-medium text-muted uppercase tracking-wide">Danger Zone</div>
<div className="text-xs text-muted mt-0.5">Irreversible actions</div>
</div>
<div className="px-6 lg:px-10 py-6">
<div className="p-4 border border-danger/30 bg-danger/5">
<h4 className="text-sm font-medium text-danger mb-2">Delete All Content</h4>
<p className="text-xs text-muted mb-3">
Permanently delete all posts and assets. This cannot be undone.
</p>
<Button variant="danger" Icon={Icons.Trash}>
Delete All Content
</Button>
</div>
</div>
</div>
</div>
)
}