Add page/post management UI: editors, admin pages, and preview routes
This commit is contained in:
39
src/pages/admin/pages/new.astro
Normal file
39
src/pages/admin/pages/new.astro
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
// Admin: Create New Page
|
||||
import AdminLayout from '@/layouts/AdminLayout.astro';
|
||||
import PageEditor from '@/components/shim/PageEditor';
|
||||
|
||||
// Get first site ID (for demo, you'd select from a dropdown)
|
||||
const { rows: sites } = await (await import('@/lib/db')).pool.query<{id: string}>('SELECT id FROM sites LIMIT 1');
|
||||
const siteId = sites[0]?.id;
|
||||
|
||||
if (!siteId) {
|
||||
return Astro.redirect('/admin/sites');
|
||||
}
|
||||
---
|
||||
|
||||
<AdminLayout title="Create New Page">
|
||||
<div class="space-y-6">
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-white">Create New Page</h1>
|
||||
<p class="text-slate-400 mt-1">Add a new static page to your site</p>
|
||||
</div>
|
||||
<a href="/admin/pages" class="px-4 py-2 bg-slate-700 hover:bg-slate-600 text-white rounded-lg">
|
||||
← Back to Pages
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="bg-slate-800 rounded-lg border border-slate-700 p-6">
|
||||
<PageEditor
|
||||
client:load
|
||||
siteId={siteId}
|
||||
onSave={(page) => {
|
||||
window.location.href = `/admin/pages/${page.id}/edit`;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</AdminLayout>
|
||||
39
src/pages/admin/posts/new.astro
Normal file
39
src/pages/admin/posts/new.astro
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
// Admin: Create New Post
|
||||
import AdminLayout from '@/layouts/AdminLayout.astro';
|
||||
import PostEditor from '@/components/shim/PostEditor';
|
||||
|
||||
// Get first site ID
|
||||
const { rows: sites } = await (await import('@/lib/db')).pool.query<{id: string}>('SELECT id FROM sites LIMIT 1');
|
||||
const siteId = sites[0]?.id;
|
||||
|
||||
if (!siteId) {
|
||||
return Astro.redirect('/admin/sites');
|
||||
}
|
||||
---
|
||||
|
||||
<AdminLayout title="Create New Post">
|
||||
<div class="space-y-6">
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-white">Create New Post</h1>
|
||||
<p class="text-slate-400 mt-1">Add a new blog post</p>
|
||||
</div>
|
||||
<a href="/admin/posts" class="px-4 py-2 bg-slate-700 hover:bg-slate-600 text-white rounded-lg">
|
||||
← Back to Posts
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="bg-slate-800 rounded-lg border border-slate-700 p-6">
|
||||
<PostEditor
|
||||
client:load
|
||||
siteId={siteId}
|
||||
onSave={(post) => {
|
||||
window.location.href = `/admin/posts/${post.id}/edit`;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</AdminLayout>
|
||||
49
src/pages/preview/page/[id].astro
Normal file
49
src/pages/preview/page/[id].astro
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
// Preview Page by ID
|
||||
import { getPageById } from '@/lib/shim/pages';
|
||||
|
||||
const { id } = Astro.params;
|
||||
const page = await getPageById(id!);
|
||||
|
||||
if (!page) {
|
||||
return Astro.redirect('/404');
|
||||
}
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{page.meta_title || page.name}</title>
|
||||
<meta name="description" content={page.meta_description || ''} />
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
|
||||
.preview-banner {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 12px 20px;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
z-index: 9999;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
||||
}
|
||||
.content { margin-top: 60px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="preview-banner">
|
||||
🔍 PREVIEW MODE - Page: {page.name} - Status: {page.status}
|
||||
</div>
|
||||
<div class="content">
|
||||
<Fragment set:html={page.html_content || '<p>No content yet</p>'} />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
53
src/pages/preview/post/[id].astro
Normal file
53
src/pages/preview/post/[id].astro
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
// Preview Post by ID
|
||||
import { getPostById } from '@/lib/shim/posts';
|
||||
|
||||
const { id } = Astro.params;
|
||||
const post = await getPostById(id!);
|
||||
|
||||
if (!post) {
|
||||
return Astro.redirect('/404');
|
||||
}
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{post.meta_title || post.title}</title>
|
||||
<meta name="description" content={post.meta_description || post.excerpt || ''} />
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; }
|
||||
.preview-banner {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 12px 20px;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
z-index: 9999;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
||||
}
|
||||
.content { max-width: 800px; margin: 80px auto 40px; padding: 0 20px; }
|
||||
.content h1 { font-size: 2.5rem; margin-bottom: 1rem; color: #1a1a1a; }
|
||||
.content p { margin-bottom: 1rem; color: #4a4a4a; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="preview-banner">
|
||||
🔍 PREVIEW MODE - Post: {post.title} - Status: {post.status}
|
||||
</div>
|
||||
<article class="content">
|
||||
<h1>{post.title}</h1>
|
||||
{post.excerpt && <p class="excerpt" style="font-size: 1.2rem; color: #666;">{post.excerpt}</p>}
|
||||
<div set:html={post.content || '<p>No content yet</p>'} />
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user