ui redesign, markdown fix + metadata and auth header

This commit is contained in:
2026-05-09 05:09:07 +02:00
parent 7f8a66f360
commit bc6a34cf1f
42 changed files with 3093 additions and 517 deletions
+45 -18
View File
@@ -1,14 +1,22 @@
---
import Layout from '../../layouts/Layout.astro';
import PostEnhancer from '../../components/react/PostEnhancer';
import { marked } from 'marked';
import { renderMarkdown } from '../../lib/markdown';
const { slug } = Astro.params;
const API_URL = (typeof process !== 'undefined' ? process.env.PUBLIC_API_URL : import.meta.env.PUBLIC_API_URL) || 'http://localhost:3000';
interface PostDetail {
slug: string;
date: string;
content: string;
summary?: string;
tags: string[];
draft: boolean;
reading_time: number;
}
function formatDate(d: string) {
return new Date(d).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
}
let post: PostDetail | null = null;
@@ -19,7 +27,7 @@ try {
const response = await fetch(`${API_URL}/api/posts/${slug}`);
if (response.ok) {
post = await response.json();
html = await marked.parse(post!.content);
html = renderMarkdown(post!.content);
} else {
error = 'Post not found';
}
@@ -34,10 +42,14 @@ function formatSlug(s: string) {
return s.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
}
const isAdmin = Astro.cookies.has('admin_token');
const isAdmin = Astro.cookies.get('admin_session')?.value === '1';
---
<Layout title={post ? formatSlug(post.slug) : 'Post'}>
<Layout
title={post ? formatSlug(post.slug) : 'Post'}
description={post?.summary}
type="article"
>
<article class="glass p-6 md:p-12 mb-8 md:mb-12 animate-in fade-in slide-in-from-bottom-4 duration-700">
{error && (
<div class="text-red text-center py-12">
@@ -58,30 +70,45 @@ const isAdmin = Astro.cookies.has('admin_token');
Back to list
</a>
<div class="flex flex-col md:flex-row md:justify-between md:items-start mt-2 md:mt-4 gap-4">
<h1 class="text-3xl md:text-5xl font-extrabold text-mauve">
{formatSlug(post.slug)}
</h1>
<div class="flex-1 min-w-0">
<h1 class="text-3xl md:text-5xl font-extrabold text-mauve mb-3">
{formatSlug(post.slug)}
</h1>
<div class="flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-subtext0">
<time datetime={post.date}>{formatDate(post.date)}</time>
<span class="opacity-50">·</span>
<span>{post.reading_time} min read</span>
{post.draft && (
<>
<span class="opacity-50">·</span>
<span class="text-peach uppercase tracking-wide font-semibold">Draft</span>
</>
)}
{post.tags?.length > 0 && (
<>
<span class="opacity-50">·</span>
<div class="flex flex-wrap gap-1.5">
{post.tags.map(tag => (
<span class="text-[10px] uppercase tracking-wider px-2 py-0.5 rounded-full bg-surface0 text-subtext0 border border-surface1">{tag}</span>
))}
</div>
</>
)}
</div>
</div>
<a
id="edit-link"
href={`/admin/editor?edit=${post.slug}`}
class="bg-surface0 hover:bg-surface1 text-blue px-3 py-1.5 md:px-4 md:py-2 rounded border border-surface1 transition-colors inline-flex items-center gap-2 text-sm md:text-base self-start hidden"
style="color: var(--blue);"
class={`bg-surface0 hover:bg-surface1 text-blue px-3 py-1.5 md:px-4 md:py-2 rounded border border-surface1 transition-colors inline-flex items-center gap-2 text-sm md:text-base self-start ${isAdmin ? '' : 'hidden'}`}
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="md:w-4 md:h-4"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/></svg>
Edit
</a>
</div>
</header>
<div id="post-content" class="prose max-w-none" set:html={html} />
<PostEnhancer client:only="react" containerId="post-content" />
<div id="post-content" class="prose" set:html={html} />
</>
)}
</article>
</Layout>
<script>
if (localStorage.getItem('admin_token')) {
const el = document.getElementById('edit-link');
if (el) el.classList.remove('hidden');
}
</script>