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,41 @@
import { atom, computed } from 'nanostores'
import { createFetcherStore, createMutatorStore } from './fetcher'
import type { Post } from '../types'
export const $posts = createFetcherStore<Post[]>(['/api/studio/posts'])
export const $search = atom('')
export const $filterStatus = atom<'all' | 'published' | 'draft'>('all')
export const $filteredPosts = computed(
[$posts, $search, $filterStatus],
(postsStore, search, status) => {
const posts = postsStore.data ?? []
return posts.filter(p => {
const searchLower = search.toLowerCase()
if (search && !p.title.toLowerCase().includes(searchLower) && !p.slug.toLowerCase().includes(searchLower)) {
return false
}
if (status === 'published' && p.draft) return false
if (status === 'draft' && !p.draft) return false
return true
})
}
)
export const $postCounts = computed([$posts], (postsStore) => {
const posts = postsStore.data ?? []
return {
all: posts.length,
published: posts.filter(p => !p.draft).length,
draft: posts.filter(p => p.draft).length,
}
})
export const $deletePost = createMutatorStore<string>(
async ({ data: slug, invalidate }) => {
const res = await fetch(`/api/studio/posts/${slug}`, { method: 'DELETE' })
if (!res.ok) throw new Error('Failed to delete post')
invalidate('/api/studio/posts')
}
)