From 54e9886d428ee8178217584df9d2abec7187e595 Mon Sep 17 00:00:00 2001 From: Joe Wee Date: Thu, 21 May 2026 12:07:34 +0100 Subject: [PATCH] Initial: blog template via tAI --- .claude/settings.json | 13 ++ CLAUDE.md | 28 +++ README.md | 3 + index.html | 12 ++ src/App.tsx | 22 +++ src/components/Footer.tsx | 122 ++++++++++++ src/components/Header.tsx | 100 ++++++++++ src/index.css | 3 + src/main.tsx | 10 + src/pages/Article.tsx | 385 ++++++++++++++++++++++++++++++++++++++ src/pages/Author.tsx | 150 +++++++++++++++ src/pages/Category.tsx | 174 +++++++++++++++++ src/pages/Index.tsx | 264 ++++++++++++++++++++++++++ src/pages/Search.tsx | 179 ++++++++++++++++++ 14 files changed, 1465 insertions(+) create mode 100644 .claude/settings.json create mode 100644 CLAUDE.md create mode 100644 README.md create mode 100644 index.html create mode 100644 src/App.tsx create mode 100644 src/components/Footer.tsx create mode 100644 src/components/Header.tsx create mode 100644 src/index.css create mode 100644 src/main.tsx create mode 100644 src/pages/Article.tsx create mode 100644 src/pages/Author.tsx create mode 100644 src/pages/Category.tsx create mode 100644 src/pages/Index.tsx create mode 100644 src/pages/Search.tsx diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..dba91da --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,13 @@ +{ + "permissions": { + "allow": [ + "Read", + "Write", + "Edit", + "Bash", + "Glob", + "Grep" + ] + }, + "model": "claude-sonnet-4-20250514" +} \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..4f4ea93 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,28 @@ +# ByteSize +Tech blog with article pages, categories, author profiles, and search +Stack: React 18 / TypeScript / Vite / Tailwind CSS / shadcn/ui +Pages: Index, Article, Category, Author, Search +Palette: emerald/stone warm editorial tones + +## Files +- src/pages/Index.tsx (15KB) +- src/pages/Article.tsx (22KB) +- src/pages/Category.tsx (10KB) +- src/pages/Author.tsx (8KB) +- src/pages/Search.tsx (10KB) +- src/components/Header.tsx (4KB) +- src/components/Footer.tsx (5KB) +- src/App.tsx (1KB) + +## Imports +UI: @/components/ui/{button,card,badge,input,textarea,tabs,accordion,dialog,sheet} +Icons: lucide-react +Toast: import { toast } from "sonner" +Theme: ThemeToggle in headers (next-themes) +Router: react-router-dom BrowserRouter + +## Rules +- MODIFY existing files — never rebuild from scratch +- Pages import Header + Footer from @/components/ +- Tailwind only — no inline styles +- Use existing shadcn components — don't create custom ones diff --git a/README.md b/README.md new file mode 100644 index 0000000..f9c02ef --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# template-blog + +Template: blog \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..d5a00b6 --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ + + + + + + Blog + + +
+ + + diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..1260b64 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,22 @@ +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import IndexPage from "@/pages/Index"; +import ArticlePage from "@/pages/Article"; +import CategoryPage from "@/pages/Category"; +import AuthorPage from "@/pages/Author"; +import SearchPage from "@/pages/Search"; + +function App() { + return ( + + + } /> + } /> + } /> + } /> + } /> + + + ); +} + +export default App; diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 0000000..e72ebbe --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,122 @@ +import { useState } from "react"; +import { toast } from "sonner"; +import { Link } from "react-router-dom"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Separator } from "@/components/ui/separator"; +import { Twitter, Github, Linkedin, Rss, Mail } from "lucide-react"; + +const categoryLinks = [ + { label: "Technology", to: "/category/technology" }, + { label: "Design", to: "/category/design" }, + { label: "Business", to: "/category/business" }, + { label: "Lifestyle", to: "/category/lifestyle" }, +]; + +const quickLinks = [ + { label: "About", to: "/" }, + { label: "Contact", to: "/" }, + { label: "Privacy Policy", to: "/" }, + { label: "Terms of Service", to: "/" }, + { label: "RSS Feed", to: "/" }, +]; + +export default function Footer() { + const [email, setEmail] = useState(""); + const [subscribed, setSubscribed] = useState(false); + + return ( + + ); +} diff --git a/src/components/Header.tsx b/src/components/Header.tsx new file mode 100644 index 0000000..595746a --- /dev/null +++ b/src/components/Header.tsx @@ -0,0 +1,100 @@ +import { useState, useEffect } from "react"; +import { Link } from "react-router-dom"; +import { Button } from "@/components/ui/button"; +import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"; +import { Menu, Search } from "lucide-react"; +import { ThemeToggle } from "@/components/ThemeToggle"; + +const navLinks = [ + { label: "Technology", to: "/category/technology" }, + { label: "Design", to: "/category/design" }, + { label: "Business", to: "/category/business" }, + { label: "Lifestyle", to: "/category/lifestyle" }, +]; + +export default function Header() { + const [mobileOpen, setMobileOpen] = useState(false); + const [scrolled, setScrolled] = useState(false); + + useEffect(() => { + const onScroll = () => setScrolled(window.scrollY > 20); + window.addEventListener("scroll", onScroll); + return () => window.removeEventListener("scroll", onScroll); + }, []); + + return ( +
+
+ {/* Logo */} + +
+ B +
+ ByteSize + + + {/* Desktop Nav */} + + + {/* Right Actions */} +
+ + + + + {/* Mobile Menu */} + + + + + +
+ {navLinks.map((l) => ( + setMobileOpen(false)} + > + {l.label} + + ))} +
+ setMobileOpen(false)}> + Search + +
+
+ + +
+
+
+
+
+
+
+ ); +} diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/src/index.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..9b67590 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; +import "./index.css"; + +ReactDOM.createRoot(document.getElementById("root")!).render( + + + +); diff --git a/src/pages/Article.tsx b/src/pages/Article.tsx new file mode 100644 index 0000000..1c02140 --- /dev/null +++ b/src/pages/Article.tsx @@ -0,0 +1,385 @@ +import { useState, useEffect } from "react"; +import { Link, useParams } from "react-router-dom"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Avatar, AvatarFallback } from "@/components/ui/avatar"; +import { Textarea } from "@/components/ui/textarea"; +import { Separator } from "@/components/ui/separator"; +import { Input } from "@/components/ui/input"; +import { toast } from "sonner"; +import { + ArrowRight, Clock, Twitter, Facebook, Linkedin, Link2, + ChevronRight, MessageSquare, ThumbsUp, Bookmark, Share2, Globe, Mail +} from "lucide-react"; +import Header from "@/components/Header"; +import Footer from "@/components/Footer"; + +const categoryColors: Record = { + Technology: "bg-emerald-100 text-emerald-700", + Design: "bg-amber-100 text-amber-700", + Business: "bg-stone-200 text-stone-700", + Lifestyle: "bg-teal-100 text-teal-700", +}; + +const relatedArticles = [ + { id: 1, title: "TypeScript Best Practices for Large Codebases", category: "Technology", author: "James Liu", date: "Mar 6, 2025", gradient: "from-amber-100 to-amber-300", slug: "typescript-best-practices" }, + { id: 2, title: "Accessible UI Patterns Every Developer Should Know", category: "Design", author: "David Kim", date: "Mar 2, 2025", gradient: "from-emerald-100 to-emerald-300", slug: "accessible-ui-patterns" }, + { id: 3, title: "State Management in 2025: What Actually Works", category: "Technology", author: "Sarah Chen", date: "Feb 28, 2025", gradient: "from-stone-200 to-stone-400", slug: "state-management-2025" }, +]; + +const comments = [ + { id: 1, author: "Alex Thompson", date: "2 days ago", text: "Excellent article! The section on edge computing really resonated with the challenges we face at our company. Would love to see a follow-up on specific migration strategies.", initials: "AT" }, + { id: 2, author: "Maya Johnson", date: "1 day ago", text: "I think the shift toward server components is the most interesting trend here. It fundamentally changes how we think about component architecture.", initials: "MJ" }, + { id: 3, author: "Ryan Park", date: "5 hours ago", text: "Great read. One thing I would add is the role of WebAssembly in this evolution. It opens up possibilities for languages beyond JavaScript on the web.", initials: "RP" }, +]; + +const tocHeadings = [ + { id: "introduction", label: "Introduction" }, + { id: "getting-started", label: "Getting Started" }, + { id: "best-practices", label: "Best Practices" }, + { id: "conclusion", label: "Conclusion" }, +]; + +export default function ArticlePage() { + const { slug } = useParams(); + const [commentText, setCommentText] = useState(""); + const [nlEmail, setNlEmail] = useState(""); + const [nlSubscribed, setNlSubscribed] = useState(false); + const [scrollProgress, setScrollProgress] = useState(0); + + useEffect(() => { + const handleScroll = () => { + const totalHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight; + const progress = totalHeight > 0 ? (window.scrollY / totalHeight) * 100 : 0; + setScrollProgress(progress); + }; + window.addEventListener("scroll", handleScroll, { passive: true }); + return () => window.removeEventListener("scroll", handleScroll); + }, []); + + return ( +
+ {/* Reading Progress Bar */} +
+
+ +
+
+ {/* Breadcrumb */} + + + {/* Article Header */} +
+ Technology +

+ The Future of Web Development: What Comes After the JavaScript Era +

+

Exploring the emerging paradigms that may reshape how we build for the web.

+
+ + {/* Author row */} +
+ + SC + +
+ Sarah Chen +

+ Mar 15, 2025 + · + 5 min read +

+
+
+ + +
+
+
+ + {/* Hero Image */} +
+
+
+
+
+
+
+ + {/* Article Body with TOC */} +
+
+ {/* Table of Contents - Desktop Only */} + + + {/* Article Content */} +
+
+

+ The web development landscape is shifting. After two decades of JavaScript dominance, new paradigms are emerging that challenge our fundamental assumptions about how web applications should be built, deployed, and experienced by users. +

+ +

The Rise of Edge Computing

+

+ Edge computing has transformed the way we think about server architecture. Instead of relying on centralized data centers, applications now run closer to the user, reducing latency and improving reliability across geographically distributed systems. +

+

+ This shift has profound implications for how we structure our applications. Traditional client-server architectures are giving way to more distributed models where the boundary between frontend and backend becomes increasingly blurred. +

+ +
+

+ + The best code is the code that never has to run on the client. The future of web development is about moving computation to where it makes the most sense. +

+
+ +

Practical Implications for Developers

+

+ For developers, this means rethinking many of the patterns we have relied on. State management, data fetching, and rendering strategies all need to be reconsidered in light of these new architectural possibilities. +

+ + {/* Code Block */} +
+
+
+
+
+ component.tsx +
+
+{String.raw\`// Example: Modern component pattern
+interface ComponentProps {
+  variant?: "default" | "outline" | "ghost";
+  size?: "sm" | "md" | "lg";
+  children: React.ReactNode;
+}
+
+export function Component({
+  variant = "default",
+  size = "md",
+  children,
+}: ComponentProps) {
+  return (
+    
+ {children} +
+ ); +}\`} +
+
+ +

What This Means for the Future

+

+ Looking ahead, we can expect to see continued convergence between traditionally separate concerns. The distinction between build-time and run-time, between static and dynamic, will continue to dissolve. +

+

+ The developers who thrive will be those who embrace these changes rather than resist them, building mental models that are flexible enough to accommodate the rapid pace of innovation in our field. +

+
+ + {/* Inline Newsletter CTA */} + + + +

Join 12,000+ readers

+

Enjoyed this? Subscribe for more

+

Get articles like this delivered to your inbox every week.

+
+ Weekly insights + · + No spam + · + Unsubscribe anytime +
+ {nlSubscribed ? ( +

You are subscribed! Check your inbox.

+ ) : ( +
{ e.preventDefault(); if (nlEmail) { setNlSubscribed(true); toast.success("Subscribed! Check your inbox."); } }} className="flex gap-2 max-w-sm mx-auto"> + setNlEmail(e.target.value)} + className="border-stone-200 focus-visible:ring-emerald-500" + /> + +
+ )} +

+ + Your email is safe with us +

+
+
+ + {/* Share Buttons */} + +
+ Share this article +
+ + + + +
+
+ + {/* Author Bio */} + + +
+
+
+
+ SC +
+
+
+
+

Written by

+ Sarah Chen +

Senior Software Engineer & Technical Writer

+

+ Sarah is a senior software engineer and technical writer specializing in frontend architecture. She has been building for the web for over 10 years and loves exploring the intersection of developer experience and user experience. +

+
+ + + + + + More from this author + +
+
+
+
+
+ + {/* Related Articles */} +
+

Related Articles

+
+ {relatedArticles.map((article) => ( + + +
+
+
+
+ + + {article.category} + +

+ {article.title} +

+

{article.author} · {article.date}

+
+ + + ))} +
+
+ + {/* Comments Section */} +
+

+ Comments +

+

3 comments

+ +
+ {comments.map((comment) => ( +
+ + {comment.initials} + +
+
+ {comment.author} + {comment.date} +
+

{comment.text}

+
+ + +
+
+
+ ))} +
+ + + + {/* Comment Form */} +
+

Leave a Comment

+