feat: initial HELIX scaffold — R&D showcase platform
SvelteKit 2 + Svelte 5 + TypeScript site. SQLite via Drizzle. Gitea OAuth for authoring (RnD org-gated). Pure SVG + CSS DNA helix on landing. What lands - Landing hero with animated two-strand SVG helix + tagline - /projects + /projects/[slug] (markdown body, dashboard embed allowlist) - /posts + /posts/[slug] - Auth-gated /projects/new + /posts/new forms - Gitea OAuth flow (state, code exchange, org-membership check, sessions) - Sliding-window cookie sessions (SHA-256 hashed token storage) - Dockerfile + docker-compose with named-volume SQLite - Idempotent seed (EVOLV + HELIX projects, welcome post) Stack notes - Tailwind v3 (Node 18 compat; v4 needs Node 20+) - drizzle-orm 0.45+ (patched, no SQL-identifier escape vuln) - marked for markdown; iframe embeds gated by DASHBOARD_ALLOWED_HOSTS Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
84
src/routes/posts/[slug]/+page.svelte
Normal file
84
src/routes/posts/[slug]/+page.svelte
Normal file
@@ -0,0 +1,84 @@
|
||||
<script lang="ts">
|
||||
let { data } = $props();
|
||||
const published = $derived(
|
||||
data.post.publishedAt
|
||||
? new Date(data.post.publishedAt).toLocaleDateString('en-GB', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
})
|
||||
: ''
|
||||
);
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{data.post.title} · HELIX</title>
|
||||
<meta name="description" content={data.post.summary || data.post.title} />
|
||||
</svelte:head>
|
||||
|
||||
<article class="post">
|
||||
<header class="head">
|
||||
<a href="/posts" class="back">← Posts</a>
|
||||
<h1>{data.post.title}</h1>
|
||||
<div class="meta">
|
||||
{#if data.author}
|
||||
<span class="author">
|
||||
{#if data.author.avatarUrl}
|
||||
<img src={data.author.avatarUrl} alt="" />
|
||||
{/if}
|
||||
{data.author.name ?? data.author.username}
|
||||
</span>
|
||||
<span class="dot">·</span>
|
||||
{/if}
|
||||
<time>{published}</time>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="prose-helix">
|
||||
{@html data.bodyHtml}
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<style>
|
||||
.post {
|
||||
max-width: 700px;
|
||||
margin: 0 auto;
|
||||
padding: 3rem 1.5rem 2rem;
|
||||
}
|
||||
.head {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.back {
|
||||
color: var(--color-helix-ink-dim);
|
||||
text-decoration: none;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.back:hover {
|
||||
color: var(--color-helix-accent);
|
||||
}
|
||||
h1 {
|
||||
margin: 1rem 0 0.5rem;
|
||||
font-size: clamp(1.8rem, 4.5vw, 2.6rem);
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 1.15;
|
||||
}
|
||||
.meta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-helix-ink-faint);
|
||||
}
|
||||
.author {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
.author img {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--color-helix-border);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user