diff --git a/src/components/Comments.astro b/src/components/Comments.astro
new file mode 100644
index 0000000..56280a8
--- /dev/null
+++ b/src/components/Comments.astro
@@ -0,0 +1,33 @@
+---
+interface Props {
+ id: string
+}
+
+const { id } = Astro.props
+---
+
+
diff --git a/src/content/blog/.gitkeep b/src/content/blog/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/src/layouts/Base.astro b/src/layouts/Base.astro
index 6160198..6ca4767 100644
--- a/src/layouts/Base.astro
+++ b/src/layouts/Base.astro
@@ -1,12 +1,13 @@
---
import Icon from '../components/icon.astro'
+import './layout.css'
interface Props {
title: string
description?: string
}
-const { title, description = 'Dunky — DX tools that unlock powerful UIs.' } = Astro.props
+const { title, description = 'Dunky: DX tools that unlock powerful UIs.' } = Astro.props
const pathname = Astro.url.pathname
const isHome = pathname === '/'
---
@@ -20,7 +21,6 @@ const isHome = pathname === '/'
{title}
-
diff --git a/src/layouts/layout.css b/src/layouts/layout.css
new file mode 100644
index 0000000..d7e2182
--- /dev/null
+++ b/src/layouts/layout.css
@@ -0,0 +1,136 @@
+*,
+*::before,
+*::after {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+::selection {
+ background: #f0f;
+ color: white;
+ text-shadow: 1px 1px black;
+}
+
+html {
+ -webkit-text-size-adjust: 100%;
+ text-size-adjust: 100%;
+}
+
+img,
+picture,
+video,
+canvas,
+svg {
+ display: block;
+ max-width: 100%;
+}
+
+input,
+button,
+textarea,
+select {
+ font: inherit;
+}
+
+p,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ overflow-wrap: break-word;
+}
+
+:root {
+ color-scheme: dark;
+}
+
+body {
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ line-height: 1.5;
+ -webkit-font-smoothing: antialiased;
+ font-family:
+ system-ui,
+ -apple-system,
+ 'Segoe UI',
+ sans-serif;
+ color: #fff;
+ /* premium dark background: subtle radial glow over near-black */
+ background-color: #08090d;
+ background-image: radial-gradient(120% 120% at 50% 0%, #222 0%, #111 55%, #000 100%);
+ background-attachment: fixed;
+}
+
+.topbar {
+ position: fixed;
+ top: 0;
+ right: 0;
+ width: 100%;
+ display: flex;
+ gap: 0.25rem;
+ padding: 0.75rem 1rem;
+ z-index: 10;
+ justify-content: center;
+ background: rgb(8 9 13 / 0.85);
+ backdrop-filter: blur(12px);
+ -webkit-backdrop-filter: blur(12px);
+}
+
+.topbar-link {
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+ padding: 0.35rem 0.65rem;
+ border-radius: 0.5rem;
+ color: rgb(255 255 255 / 0.55);
+ text-decoration: none;
+ font-size: 0.8rem;
+ font-weight: 500;
+ transition:
+ color 0.18s ease,
+ background 0.18s ease;
+}
+
+.topbar-link:hover,
+.topbar-link:focus-visible {
+ color: #fff;
+ background: rgb(255 255 255 / 0.08);
+ outline: none;
+}
+
+.topbar-link--active {
+ color: #fff;
+}
+
+.topbar-link--back {
+ margin-right: auto;
+}
+
+.topbar-icon {
+ width: 1rem;
+ height: 1rem;
+ flex-shrink: 0;
+}
+
+.footer {
+ padding: 1.5rem;
+ text-align: center;
+ font-size: 0.8rem;
+ color: rgb(255 255 255 / 0.35);
+}
+
+.footer-link {
+ color: rgb(255 255 255 / 0.55);
+ text-decoration: none;
+ transition: color 0.18s ease;
+}
+
+.footer-link:hover,
+.footer-link:focus-visible {
+ color: #fff;
+ outline: none;
+}
diff --git a/src/pages/blog/[id].astro b/src/pages/blog/[id].astro
new file mode 100644
index 0000000..cb7d305
--- /dev/null
+++ b/src/pages/blog/[id].astro
@@ -0,0 +1,32 @@
+---
+import { getCollection, render } from 'astro:content'
+import Base from '../../layouts/base.astro'
+import Comments from '../../components/Comments.astro'
+import './blog.css'
+
+export async function getStaticPaths() {
+ const posts = await getCollection('blog', ({ data }) => !data.draft)
+ return posts.map((post) => ({ params: { id: post.id }, props: { post } }))
+}
+
+const { post } = Astro.props
+const { Content } = await render(post)
+---
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/blog/blog.css b/src/pages/blog/blog.css
new file mode 100644
index 0000000..8105161
--- /dev/null
+++ b/src/pages/blog/blog.css
@@ -0,0 +1,243 @@
+/* ── Blog index ──────────────────────────────────────────────────────────── */
+
+.blog-page {
+ flex: 1;
+ padding: clamp(5rem, 10vw, 8rem) clamp(1.5rem, 5vw, 3rem) 3rem;
+ max-width: 1200px;
+ margin: 0 auto;
+ width: 100%;
+}
+
+.blog-title {
+ font-size: clamp(2rem, 5vw, 3rem);
+ font-weight: 700;
+ letter-spacing: -0.02em;
+ margin-bottom: clamp(2rem, 4vw, 3rem);
+}
+
+.blog-empty {
+ color: rgb(255 255 255 / 0.4);
+}
+
+.blog-list {
+ list-style: none;
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 1.25rem;
+}
+
+.blog-link {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ padding: 1.5rem;
+ border-radius: 1rem;
+ border: 1px solid rgb(255 255 255 / 0.08);
+ background: rgb(255 255 255 / 0.02);
+ color: #fff;
+ text-decoration: none;
+ height: 100%;
+ transition:
+ border-color 0.18s ease,
+ background 0.18s ease;
+}
+
+.blog-link:hover,
+.blog-link:focus-visible {
+ border-color: rgb(255 255 255 / 0.18);
+ background: rgb(255 255 255 / 0.05);
+ outline: none;
+}
+
+.blog-item-title {
+ font-size: 1rem;
+ font-weight: 600;
+ line-height: 1.3;
+}
+
+.blog-item-date {
+ font-size: 0.75rem;
+ color: rgb(255 255 255 / 0.4);
+ order: -1;
+}
+
+.blog-item-desc {
+ font-size: 0.875rem;
+ color: rgb(255 255 255 / 0.6);
+ line-height: 1.5;
+ margin-top: 0.25rem;
+}
+
+@media (width <= 900px) {
+ .blog-list {
+ grid-template-columns: repeat(3, 1fr);
+ }
+}
+
+@media (width <= 600px) {
+ .blog-list {
+ grid-template-columns: 1fr;
+ }
+}
+
+/* ── Blog post ───────────────────────────────────────────────────────────── */
+
+.post-page {
+ flex: 1;
+ padding: clamp(5rem, 10vw, 8rem) clamp(1.5rem, 5vw, 3rem) 3rem;
+ max-width: 1200px;
+ margin: 0 auto;
+ width: 100%;
+}
+
+.post-date {
+ display: block;
+ font-size: 0.8rem;
+ color: rgb(255 255 255 / 0.4);
+ margin-bottom: 0.75rem;
+}
+
+.post-title {
+ font-size: clamp(2.25rem, 5vw, 3.5rem);
+ font-weight: 700;
+ letter-spacing: -0.02em;
+ line-height: 1.15;
+ margin-bottom: 1rem;
+}
+
+.post-description {
+ font-size: 1.1rem;
+ color: rgb(255 255 255 / 0.55);
+ line-height: 1.6;
+ margin-bottom: 3rem;
+ padding-bottom: 2rem;
+ border-bottom: 1px solid rgb(255 255 255 / 0.08);
+}
+
+.post-content {
+ font-size: 1.2rem;
+ line-height: 1.8;
+ color: rgb(255 255 255 / 0.85);
+}
+
+.post-content h2 {
+ font-size: 1.65rem;
+ font-weight: 650;
+ letter-spacing: -0.01em;
+ color: #fff;
+ margin: 2.5rem 0 1rem;
+}
+
+.post-content p {
+ margin-bottom: 1.25rem;
+}
+
+.post-content ul,
+.post-content ol {
+ padding-left: 1.25rem;
+ margin-bottom: 1.25rem;
+}
+
+.post-content li {
+ margin-bottom: 0.25rem;
+}
+
+.post-content blockquote {
+ border-left: 2px solid rgb(255 255 255 / 0.2);
+ margin: 1.5rem 0;
+ padding: 0.25rem 0 0.25rem 1.25rem;
+ color: rgb(255 255 255 / 0.6);
+}
+
+.post-content pre {
+ font-family: monospace;
+ line-height: 1.4;
+ padding: 1.5rem 2rem;
+ margin: 1.5rem 0;
+ border-radius: 0.75rem;
+ background: rgb(255 255 255 / 0.03);
+ border: 1px solid rgb(255 255 255 / 0.08);
+ box-shadow:
+ 0 0 0 1px rgb(255 255 255 / 0.04),
+ inset 0 1px 0 rgb(255 255 255 / 0.06);
+ overflow-x: auto;
+ white-space: pre;
+}
+
+.post-content code {
+ font-family: inherit;
+ font-size: inherit;
+ color: rgb(255 255 255 / 0.9);
+}
+
+.code-compare {
+ display: flex;
+ align-items: stretch;
+ gap: 1rem;
+ margin: 1.5rem 0;
+}
+
+.code-compare > div {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+}
+
+.code-compare pre {
+ flex: 1;
+ margin: 0;
+ font-size: 0.75rem;
+}
+
+.code-compare > div pre + pre {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-top: none;
+}
+
+.code-compare > div pre:not(:last-child) {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+@media (width <= 600px) {
+ .code-compare {
+ flex-direction: column;
+ }
+}
+
+.code-label {
+ font-size: 0.75rem;
+ font-weight: 600;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+ color: rgb(255 255 255 / 0.35);
+ margin-bottom: 0.5rem;
+ background: none;
+ padding: 0;
+ border-radius: 0;
+}
+
+/* ── Comments ────────────────────────────────────────────────────────────── */
+
+.comments-section {
+ margin-top: 5rem;
+ padding-top: 3rem;
+ border-top: 1px solid rgb(255 255 255 / 0.08);
+}
+
+.comments-header {
+ margin-bottom: 2rem;
+}
+
+.comments-label {
+ font-size: 0.9rem;
+ font-weight: 600;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+ color: rgb(255 255 255 / 0.75);
+}
+
+.giscus-container {
+ opacity: 0.85;
+}
diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro
index 1ff7fb9..c933287 100644
--- a/src/pages/blog/index.astro
+++ b/src/pages/blog/index.astro
@@ -1,6 +1,7 @@
---
import Base from "../../layouts/base.astro";
import { getCollection } from "astro:content";
+import "./blog.css";
const posts = (await getCollection("blog", ({ data }) => !data.draft)).sort(
(a, b) => b.data.date.valueOf() - a.data.date.valueOf(),
@@ -8,8 +9,8 @@ const posts = (await getCollection("blog", ({ data }) => !data.draft)).sort(
---
Blog
diff --git a/src/pages/index.astro b/src/pages/index.astro
index 9091ac2..6ec9b3a 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -1,9 +1,10 @@
---
import Base from "../layouts/base.astro";
import Icon from "../components/icon.astro";
+import "./index.css";
---
-
+
![]()