From 5211532923d727a5733d17e30780f21e15750d56 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Sat, 21 Feb 2026 15:47:17 -0600 Subject: [PATCH] Fix post detail readability and add light/dark theme toggle --- src/app/globals.css | 55 ++++++++----- src/app/page.tsx | 192 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 182 insertions(+), 65 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index 18bc052..5cd05f9 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,35 +1,48 @@ @import "tailwindcss"; +@custom-variant dark (&:where(.dark, .dark *)); :root { - --background: #ffffff; - --foreground: #171717; + --background: #f8fafc; + --foreground: #0f172a; + --markdown-heading: #0f172a; + --markdown-body: #334155; + --markdown-link: #2563eb; + --markdown-link-hover: #1d4ed8; + --markdown-rule: #cbd5e1; + color-scheme: light; +} + +:root.dark { + --background: #020617; + --foreground: #e2e8f0; + --markdown-heading: #f8fafc; + --markdown-body: #cbd5e1; + --markdown-link: #60a5fa; + --markdown-link-hover: #93c5fd; + --markdown-rule: #334155; + color-scheme: dark; } @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } + --font-sans: var(--font-inter); } body { background: var(--background); color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; } /* Markdown content styles */ +.markdown-content { + color: var(--markdown-body); +} + .markdown-content h1 { font-size: 1.5rem; font-weight: 700; - color: #f4f4f5; + color: var(--markdown-heading); margin-bottom: 0.75rem; margin-top: 1rem; } @@ -37,7 +50,7 @@ body { .markdown-content h2 { font-size: 1.25rem; font-weight: 600; - color: #e4e4e7; + color: var(--markdown-heading); margin-bottom: 0.5rem; margin-top: 0.75rem; } @@ -45,13 +58,13 @@ body { .markdown-content h3 { font-size: 1.125rem; font-weight: 600; - color: #d4d4d8; + color: var(--markdown-heading); margin-bottom: 0.5rem; margin-top: 0.75rem; } .markdown-content p { - color: #a1a1aa; + color: var(--markdown-body); margin-bottom: 0.75rem; line-height: 1.625; } @@ -63,26 +76,26 @@ body { } .markdown-content li { - color: #a1a1aa; + color: var(--markdown-body); margin-bottom: 0.25rem; } .markdown-content a { - color: #60a5fa; + color: var(--markdown-link); text-decoration: none; } .markdown-content a:hover { - color: #93c5fd; + color: var(--markdown-link-hover); text-decoration: underline; } .markdown-content hr { - border-color: #3f3f46; + border-color: var(--markdown-rule); margin: 1rem 0; } .markdown-content strong { - color: #e4e4e7; + color: var(--markdown-heading); font-weight: 600; } diff --git a/src/app/page.tsx b/src/app/page.tsx index 1f7fbd7..1099b89 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect, useMemo } from "react"; +import { Suspense, useState, useEffect, useMemo } from "react"; import { useRouter, useSearchParams } from "next/navigation"; import { format } from "date-fns"; import ReactMarkdown from "react-markdown"; @@ -16,19 +16,53 @@ interface Message { tags?: string[]; } +type Theme = "light" | "dark"; + export default function BlogPage() { + return ( + +
+
+ } + > + +
+ ); +} + +function BlogPageContent() { const router = useRouter(); const searchParams = useSearchParams(); const selectedTag = searchParams.get("tag"); + const selectedPostId = searchParams.get("post"); const [messages, setMessages] = useState([]); const [loading, setLoading] = useState(true); const [searchQuery, setSearchQuery] = useState(""); + const [theme, setTheme] = useState("light"); useEffect(() => { fetchMessages(); }, []); + useEffect(() => { + const storedTheme = localStorage.getItem("theme"); + const initialTheme: Theme = + storedTheme === "light" || storedTheme === "dark" + ? storedTheme + : window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"; + setTheme(initialTheme); + }, []); + + useEffect(() => { + document.documentElement.classList.toggle("dark", theme === "dark"); + localStorage.setItem("theme", theme); + }, [theme]); + async function fetchMessages() { try { const res = await fetch("/api/messages"); @@ -71,6 +105,13 @@ export default function BlogPage() { // Get featured post (most recent) const featuredPost = filteredMessages[0]; const regularPosts = filteredMessages.slice(1); + const selectedPost = useMemo( + () => + selectedPostId + ? messages.find((message) => message.id === selectedPostId) ?? null + : null, + [messages, selectedPostId] + ); // Parse title from content function getTitle(content: string): string { @@ -92,7 +133,7 @@ export default function BlogPage() { if (loading) { return ( -
+
); @@ -105,25 +146,33 @@ export default function BlogPage() { -
+
{/* Header */} -
+
📓
- Daily Digest + Daily Digest -
@@ -133,17 +182,68 @@ export default function BlogPage() {
{/* Main Content */}
+ {selectedPostId ? ( + selectedPost ? ( +
+ + +
+ {selectedPost.tags && selectedPost.tags.length > 0 && ( +
+ {selectedPost.tags.map((tag) => ( + + ))} +
+ )} +

+ {getTitle(selectedPost.content)} +

+

+ {format(new Date(selectedPost.date), "MMMM d, yyyy")} +

+
+ +
+ + {selectedPost.content} + +
+
+ ) : ( +
+

Post not found.

+ +
+ ) + ) : ( + <> {/* Page Title */}
-

+

{selectedTag ? `Posts tagged "${selectedTag}"` : "Latest Posts"}

-

+

{filteredMessages.length} post{filteredMessages.length !== 1 ? "s" : ""} {selectedTag && ( @@ -155,30 +255,30 @@ export default function BlogPage() { {featuredPost && !selectedTag && !searchQuery && (

-
+
{featuredPost.tags && featuredPost.tags.length > 0 && (
{featuredPost.tags.slice(0, 3).map((tag) => ( {tag} ))}
)} - + Featured Post -

+

{getTitle(featuredPost.content)}

-

+

{getExcerpt(featuredPost.content, 200)}

-
+
{format(new Date(featuredPost.date), "MMMM d, yyyy")} · 5 min read @@ -194,14 +294,14 @@ export default function BlogPage() { {regularPosts.map((post) => (
{/* Date Column */}
-
+
{format(new Date(post.date), "d")}
-
+
{format(new Date(post.date), "MMM")}
@@ -214,7 +314,7 @@ export default function BlogPage() { @@ -222,15 +322,17 @@ export default function BlogPage() {
)} -

- {getTitle(post.content)} +

+ + {getTitle(post.content)} +

-

+

{getExcerpt(post.content)}

-
+
{format(new Date(post.date), "MMMM d, yyyy")} · 3 min read @@ -242,27 +344,29 @@ export default function BlogPage() { {filteredMessages.length === 0 && (
-

No posts found.

+

No posts found.

{(selectedTag || searchQuery) && ( )}
)} + + )}
{/* Sidebar */}
{/* Search */} -
-