diff --git a/README.md b/README.md
index c6bfaa5..0798d1a 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,7 @@ npm run sync:prod # production
- Logo gallery with continuous marquee scroll
- Static raw markdown files at `/raw/{slug}.md`
- Dedicated blog page with configurable navigation order
+- Markdown writing page at `/write` with frontmatter reference
### SEO and Discovery
@@ -571,6 +572,45 @@ body {
Replace the `font-family` property with your preferred font stack.
+### Font Sizes
+
+All font sizes use CSS variables defined in `:root`. Customize sizes by editing the variables:
+
+```css
+:root {
+ /* Base size scale */
+ --font-size-base: 16px;
+ --font-size-sm: 13px;
+ --font-size-lg: 17px;
+ --font-size-xl: 18px;
+ --font-size-2xl: 20px;
+ --font-size-3xl: 24px;
+
+ /* Component-specific (examples) */
+ --font-size-blog-content: 17px;
+ --font-size-post-title: 32px;
+ --font-size-nav-link: 14px;
+}
+```
+
+Mobile responsive sizes are defined in a `@media (max-width: 768px)` block with smaller values.
+
+## Write Page
+
+A public markdown writing page at `/write` (not linked in navigation). Features:
+
+- Three-column Cursor docs-style layout
+- Content type selector (Blog Post or Page) with dynamic frontmatter templates
+- Frontmatter reference panel with copy buttons for each field
+- Font switcher (Serif/Sans-serif) with localStorage persistence
+- Theme toggle matching the site themes (Moon, Sun, Half2Icon, Cloud)
+- Word, line, and character counts
+- localStorage persistence for content, content type, and font preference
+- Works with Grammarly and browser spellcheck
+- Warning message about refresh losing content
+
+Access directly at `yourdomain.com/write`. Content is stored in localStorage only (not synced to database). Use it to draft posts, then copy the content to a markdown file in `content/blog/` or `content/pages/` and run `npm run sync`.
+
## Source
Fork this project: [github.com/waynesutton/markdown-site](https://github.com/waynesutton/markdown-site)
diff --git a/TASK.md b/TASK.md
index 82d8166..fadd7ab 100644
--- a/TASK.md
+++ b/TASK.md
@@ -2,17 +2,43 @@
## To Do
-- [ ] Add markdown write page with copy option
- [ ] add github code block
- [ ] create a ui site config page
-- [ ] create a prompt formator or skill or agent to change everything at once after forking
+- [ ] create a prompt formator or checklidst or skill or agent to change everything at once after forking
## Current Status
-v1.12.1 deployed. OG images now use post/page image from frontmatter instead of always defaulting.
+v1.16.0 deployed. Added public /write page with three-column Cursor docs-style layout, font switcher, theme toggle, and localStorage persistence for markdown writing.
## Completed
+- [x] Public /write page with three-column layout (not linked in nav)
+- [x] Left sidebar: Home link, content type selector, actions (Clear, Theme, Font)
+- [x] Center: Writing area with Copy All button and borderless textarea
+- [x] Right sidebar: Frontmatter reference with per-field copy buttons
+- [x] Font switcher to toggle between Serif and Sans-serif fonts
+- [x] Font preference persistence in localStorage
+- [x] Theme toggle icons matching ThemeToggle.tsx (Moon, Sun, Half2Icon, Cloud)
+- [x] Content type switching (Blog Post/Page) updates writing area template
+- [x] Word, line, and character counts in status bar
+- [x] Warning banner about refresh losing content
+- [x] localStorage persistence for content, type, and font
+- [x] Redesign /write page with three-column Cursor docs-style layout
+- [x] Add per-field copy icons to frontmatter reference panel
+- [x] Add refresh warning message in left sidebar
+- [x] Left sidebar with home link, content type selector, and actions
+- [x] Right sidebar with frontmatter fields and copy buttons
+- [x] Center area with title, Copy All button, and borderless textarea
+- [x] Theme toggle with matching icons for all four themes
+- [x] Redesign /write page with wider layout and modern Notion-like UI
+- [x] Remove header from /write page (standalone writing experience)
+- [x] Add inline theme toggle and home link to Write page toolbar
+- [x] Collapsible frontmatter fields panel
+- [x] Add markdown write page with copy option at /write
+- [x] Centralized font-size CSS variables in global.css
+- [x] Base size scale with semantic naming (3xs to hero)
+- [x] Component-specific font-size variables
+- [x] Mobile responsive font-size overrides
- [x] Open Graph image fix for posts and pages with frontmatter images
- [x] Dedicated blog page with configurable display options
- [x] Blog page navigation order via siteConfig.blogPage.order
diff --git a/changelog.md b/changelog.md
index c83b55e..997be45 100644
--- a/changelog.md
+++ b/changelog.md
@@ -4,6 +4,152 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+## [1.16.0] - 2025-12-21
+
+### Added
+
+- Public markdown writing page at `/write` (not linked in navigation)
+ - Three-column Cursor docs-style layout
+ - Left sidebar: Home link, content type selector (Blog Post/Page), actions (Clear, Theme, Font)
+ - Center: Full-height writing area with title, Copy All button, and borderless textarea
+ - Right sidebar: Frontmatter reference with copy icon for each field
+- Font switcher in Actions section
+ - Toggle between Serif and Sans-serif fonts
+ - Font preference saved to localStorage
+- Theme toggle matching the rest of the app (Moon, Sun, Half2Icon, Cloud)
+- localStorage persistence for content, type, and font preference
+- Word, line, and character counts in status bar
+- Warning banner: "Refresh loses content"
+- Grammarly and browser spellcheck compatible
+- Works with all four themes (dark, light, tan, cloud)
+
+### Technical
+
+- New component: `src/pages/Write.tsx`
+- Route: `/write` (added to `src/App.tsx`)
+- Three localStorage keys: `markdown_write_content`, `markdown_write_type`, `markdown_write_font`
+- CSS Grid layout (220px | 1fr | 280px)
+- Uses Phosphor icons: House, Article, File, Trash, CopySimple, Warning, Check
+- Uses lucide-react and radix-ui icons for theme toggle (consistent with ThemeToggle.tsx)
+
+## [1.15.1] - 2025-12-21
+
+### Fixed
+
+- Theme toggle icons on `/write` page now match `ThemeToggle.tsx` component
+ - dark: Moon icon (lucide-react)
+ - light: Sun icon (lucide-react)
+ - tan: Half2Icon (radix-ui) - consistent with rest of app
+ - cloud: Cloud icon (lucide-react)
+- Content type switching (Blog Post/Page) now always updates writing area template
+
+### Technical
+
+- Replaced Phosphor icons (Moon, Sun, Leaf, CloudSun) with lucide-react and radix-ui icons
+- `handleTypeChange` now always regenerates template when switching types
+
+## [1.15.0] - 2025-12-21
+
+### Changed
+
+- Redesigned `/write` page with three-column Cursor docs-style layout
+ - Left sidebar: Home link, content type selector (Blog Post/Page), actions (Clear, Theme)
+ - Center: Full-height writing area with title, Copy All button, and borderless textarea
+ - Right sidebar: Frontmatter reference with copy icon for each field
+- Frontmatter fields panel with per-field copy buttons
+ - Each frontmatter field shows name, example value, and copy icon
+ - Click to copy individual field syntax to clipboard
+ - Required fields marked with red asterisk
+ - Fields update dynamically when switching between Blog Post and Page
+- Warning banner for unsaved content
+ - "Refresh loses content" warning in left sidebar with warning icon
+ - Helps users remember localStorage persistence limitations
+- Enhanced status bar
+ - Word, line, and character counts in sticky footer
+ - Save hint with content directory path
+
+### Technical
+
+- Three-column CSS Grid layout (220px sidebar | 1fr main | 280px right sidebar)
+- Theme toggle cycles through dark, light, tan, cloud with matching icons
+- Collapsible sidebars on mobile (stacked layout)
+- Uses Phosphor icons: House, Article, File, Trash, CopySimple, Warning, Check
+
+## [1.14.0] - 2025-12-20
+
+### Changed
+
+- Redesigned `/write` page with Notion-like minimal UI
+ - Full-screen distraction-free writing experience
+ - Removed site header for focused writing environment
+ - Wider writing area (900px max-width centered)
+ - Borderless textarea with transparent background
+ - Own minimal header with home link, type selector, and icon buttons
+- Improved toolbar design
+ - Home icon link to return to main site
+ - Clean dropdown for content type selection (no borders)
+ - Collapsible frontmatter fields panel (hidden by default)
+ - Theme toggle in toolbar (cycles through dark, light, tan, cloud)
+ - Icon buttons with subtle hover states
+ - Copy button with inverted theme colors
+- Enhanced status bar
+ - Sticky footer with word/line/character counts
+ - Save hint with content directory path
+ - Dot separators between stats
+
+### Technical
+
+- Write page now renders without Layout component wrapper
+- Added Phosphor icons: House, Sun, Moon, CloudSun, Leaf, Info, X
+- CSS restructured for minimal aesthetic (`.write-wrapper`, `.write-header`, etc.)
+- Mobile responsive with hidden copy text and save hint on small screens
+
+## [1.13.0] - 2025-12-20
+
+### Added
+
+- Public markdown writing page at `/write` (not linked in navigation)
+ - Dropdown to select between "Blog Post" and "Page" content types
+ - Frontmatter fields reference panel with required/optional indicators
+ - Copy button using Phosphor CopySimple icon
+ - Clear button to reset content to template
+ - Status bar showing lines, words, and characters count
+ - Usage hint with instructions for saving content
+- localStorage persistence for writing session
+ - Content persists across page refreshes within same browser
+ - Each browser has isolated content (session privacy)
+ - Content type selection saved separately
+- Auto-generated frontmatter templates
+ - Blog post template with all common fields
+ - Page template with navigation fields
+ - Current date auto-populated in templates
+
+### Technical
+
+- New component: `src/pages/Write.tsx`
+- Route: `/write` (added to `src/App.tsx`)
+- CSS styles added to `src/styles/global.css`
+- Works with all four themes (dark, light, tan, cloud)
+- Plain textarea for Grammarly and browser spellcheck compatibility
+- Mobile responsive design with adjusted layout for smaller screens
+- No Convex backend required (localStorage only)
+
+## [1.12.2] - 2025-12-20
+
+### Added
+
+- Centralized font-size configuration using CSS variables in `global.css`
+ - Base size scale from 10px to 64px with semantic names
+ - Component-specific variables for consistent sizing
+ - Mobile responsive overrides at 768px breakpoint
+- All hardcoded font sizes converted to CSS variables for easier customization
+
+### Technical
+
+- Font sizes defined in `:root` selector with `--font-size-*` naming convention
+- Mobile breakpoint uses same variables with smaller values
+- Base scale: 3xs (10px), 2xs (11px), xs (12px), sm (13px), md (14px), base (16px), lg (17px), xl (18px), 2xl (20px), 3xl (24px), 4xl (28px), 5xl (32px), 6xl (36px), hero (64px)
+
## [1.12.1] - 2025-12-20
### Fixed
diff --git a/content/blog/setup-guide.md b/content/blog/setup-guide.md
index d74af97..1434203 100644
--- a/content/blog/setup-guide.md
+++ b/content/blog/setup-guide.md
@@ -703,6 +703,29 @@ body {
}
```
+### Change Font Sizes
+
+All font sizes use CSS variables defined in `:root`. Customize sizes by editing these variables in `src/styles/global.css`:
+
+```css
+:root {
+ /* Base size scale */
+ --font-size-base: 16px;
+ --font-size-sm: 13px;
+ --font-size-lg: 17px;
+ --font-size-xl: 18px;
+ --font-size-2xl: 20px;
+ --font-size-3xl: 24px;
+
+ /* Component-specific (examples) */
+ --font-size-blog-content: 17px;
+ --font-size-post-title: 32px;
+ --font-size-nav-link: 14px;
+}
+```
+
+Mobile responsive sizes are defined in a `@media (max-width: 768px)` block.
+
### Add Static Pages (Optional)
Create optional pages like About, Projects, or Contact. These appear as navigation links in the top right corner.
@@ -944,6 +967,32 @@ markdown-site/
└── package.json # Dependencies
```
+## Write Page
+
+A markdown writing page is available at `/write` (not linked in navigation). Use it to draft content before saving to your markdown files.
+
+**Features:**
+
+- Three-column Cursor docs-style layout
+- Content type selector (Blog Post or Page) with dynamic frontmatter templates
+- Frontmatter field reference with individual copy buttons
+- Font switcher (Serif/Sans-serif)
+- Theme toggle matching site themes
+- Word, line, and character counts
+- localStorage persistence for content, type, and font preference
+- Works with Grammarly and browser spellcheck
+
+**Workflow:**
+
+1. Go to `yourdomain.com/write`
+2. Select content type (Blog Post or Page)
+3. Write your content using the frontmatter reference
+4. Click "Copy All" to copy the markdown
+5. Save to `content/blog/` or `content/pages/`
+6. Run `npm run sync` or `npm run sync:prod`
+
+Content is stored in localStorage only and not synced to the database. Refreshing the page preserves your content, but clearing browser data will lose it.
+
## Next Steps
After deploying:
diff --git a/content/pages/about.md b/content/pages/about.md
index 5bdcef0..97e535f 100644
--- a/content/pages/about.md
+++ b/content/pages/about.md
@@ -63,6 +63,7 @@ It's a hybrid: developer workflow for publishing + real-time delivery like a dyn
- Copy to ChatGPT, Claude, and Perplexity sharing
- Generate Skill option for AI agent training
- View as Markdown option in share dropdown
+- Markdown writing page at `/write` with frontmatter reference
## Who this is for
diff --git a/content/pages/changelog-page.md b/content/pages/changelog-page.md
index cac514e..cea1e92 100644
--- a/content/pages/changelog-page.md
+++ b/content/pages/changelog-page.md
@@ -7,6 +7,82 @@ order: 5
All notable changes to this project.
+## v1.15.2
+
+Released December 20, 2025
+
+**Write page font switcher**
+
+- Font switcher in `/write` page Actions section
+- Toggle between Serif and Sans-serif fonts in the writing area
+- Font preference saved to localStorage and persists across sessions
+- Uses same font families defined in global.css
+
+## v1.15.1
+
+Released December 20, 2025
+
+**Write page theme and content fixes**
+
+- Fixed theme toggle icons on `/write` page to match `ThemeToggle.tsx` (Moon, Sun, Half2Icon, Cloud)
+- Content type switching now always updates the template in the writing area
+
+## v1.15.0
+
+Released December 20, 2025
+
+**Write page three-column layout**
+
+- Redesigned `/write` page with Cursor docs-style three-column layout
+- Left sidebar: content type selector (Blog Post/Page) and action buttons (Clear, Theme)
+- Center: full-screen writing area with Copy All button
+- Right sidebar: frontmatter field reference with individual copy buttons for each field
+- Warning message about refresh losing content
+- Stats bar showing words, lines, and characters
+
+## v1.14.0
+
+Released December 20, 2025
+
+**Write page Notion-like UI**
+
+- Redesigned `/write` page with full-screen, distraction-free writing experience
+- Floating header with home link, type selector, and action buttons
+- Collapsible frontmatter panel on the right
+- Removed borders from writing area for cleaner look
+- Improved typography and spacing
+
+## v1.13.0
+
+Released December 20, 2025
+
+**Markdown write page**
+
+- New `/write` page for drafting markdown content (not linked in navigation)
+- Content type selector for Blog Post or Page with appropriate frontmatter templates
+- Frontmatter reference with copy buttons for each field
+- Theme toggle matching site themes
+- Word, line, and character counts
+- localStorage persistence for content, type, and font preference
+- Works with Grammarly and browser spellcheck
+- Copy all button for easy content transfer
+- Clear button to reset content
+
+Access at `yourdomain.com/write`. Content stored in localStorage only.
+
+## v1.12.2
+
+Released December 20, 2025
+
+**Centralized font-size CSS variables**
+
+- All font sizes now use CSS variables for easier customization
+- Base scale from `--font-size-3xs` (10px) to `--font-size-hero` (64px)
+- Component-specific variables for blog headings, navigation, search, stats, and more
+- Mobile responsive overrides at 768px breakpoint
+
+Edit `src/styles/global.css` to customize font sizes across the entire site by changing the `:root` variables.
+
## v1.12.1
Released December 20, 2025
diff --git a/content/pages/docs.md b/content/pages/docs.md
index f881f4f..425dc38 100644
--- a/content/pages/docs.md
+++ b/content/pages/docs.md
@@ -394,6 +394,22 @@ body {
}
```
+### Font Sizes
+
+All font sizes use CSS variables in `:root`. Customize by editing:
+
+```css
+:root {
+ --font-size-base: 16px;
+ --font-size-sm: 13px;
+ --font-size-lg: 17px;
+ --font-size-blog-content: 17px;
+ --font-size-post-title: 32px;
+}
+```
+
+Mobile sizes defined in `@media (max-width: 768px)` block.
+
### Images
| Image | Location | Size |
diff --git a/files.md b/files.md
index 3046e82..8b867c5 100644
--- a/files.md
+++ b/files.md
@@ -41,6 +41,7 @@ A brief description of each file in the codebase.
| `Blog.tsx` | Dedicated blog page with post list (configurable via siteConfig.blogPage) |
| `Post.tsx` | Individual blog post view (update SITE_URL/SITE_NAME when forking) |
| `Stats.tsx` | Real-time analytics dashboard with visitor stats |
+| `Write.tsx` | Three-column markdown writing page with Cursor docs-style UI, frontmatter reference with copy buttons, theme toggle, font switcher (serif/sans-serif), and localStorage persistence (not linked in nav) |
### Components (`src/components/`)
@@ -71,9 +72,9 @@ A brief description of each file in the codebase.
### Styles (`src/styles/`)
-| File | Description |
-| ------------ | ---------------------------------------------------------------- |
-| `global.css` | Global CSS with theme variables, font config for all four themes |
+| File | Description |
+| ------------ | ------------------------------------------------------------------------------------ |
+| `global.css` | Global CSS with theme variables, centralized font-size CSS variables for all themes |
## Convex Backend (`convex/`)
diff --git a/public/raw/about.md b/public/raw/about.md
index 0ef31b2..ac88266 100644
--- a/public/raw/about.md
+++ b/public/raw/about.md
@@ -62,6 +62,7 @@ It's a hybrid: developer workflow for publishing + real-time delivery like a dyn
- Copy to ChatGPT, Claude, and Perplexity sharing
- Generate Skill option for AI agent training
- View as Markdown option in share dropdown
+- Markdown writing page at `/write` with frontmatter reference
## Who this is for
diff --git a/public/raw/changelog.md b/public/raw/changelog.md
index f2d823c..02cb8ba 100644
--- a/public/raw/changelog.md
+++ b/public/raw/changelog.md
@@ -7,6 +7,82 @@ Date: 2025-12-21
All notable changes to this project.
+## v1.15.2
+
+Released December 20, 2025
+
+**Write page font switcher**
+
+- Font switcher in `/write` page Actions section
+- Toggle between Serif and Sans-serif fonts in the writing area
+- Font preference saved to localStorage and persists across sessions
+- Uses same font families defined in global.css
+
+## v1.15.1
+
+Released December 20, 2025
+
+**Write page theme and content fixes**
+
+- Fixed theme toggle icons on `/write` page to match `ThemeToggle.tsx` (Moon, Sun, Half2Icon, Cloud)
+- Content type switching now always updates the template in the writing area
+
+## v1.15.0
+
+Released December 20, 2025
+
+**Write page three-column layout**
+
+- Redesigned `/write` page with Cursor docs-style three-column layout
+- Left sidebar: content type selector (Blog Post/Page) and action buttons (Clear, Theme)
+- Center: full-screen writing area with Copy All button
+- Right sidebar: frontmatter field reference with individual copy buttons for each field
+- Warning message about refresh losing content
+- Stats bar showing words, lines, and characters
+
+## v1.14.0
+
+Released December 20, 2025
+
+**Write page Notion-like UI**
+
+- Redesigned `/write` page with full-screen, distraction-free writing experience
+- Floating header with home link, type selector, and action buttons
+- Collapsible frontmatter panel on the right
+- Removed borders from writing area for cleaner look
+- Improved typography and spacing
+
+## v1.13.0
+
+Released December 20, 2025
+
+**Markdown write page**
+
+- New `/write` page for drafting markdown content (not linked in navigation)
+- Content type selector for Blog Post or Page with appropriate frontmatter templates
+- Frontmatter reference with copy buttons for each field
+- Theme toggle matching site themes
+- Word, line, and character counts
+- localStorage persistence for content, type, and font preference
+- Works with Grammarly and browser spellcheck
+- Copy all button for easy content transfer
+- Clear button to reset content
+
+Access at `yourdomain.com/write`. Content stored in localStorage only.
+
+## v1.12.2
+
+Released December 20, 2025
+
+**Centralized font-size CSS variables**
+
+- All font sizes now use CSS variables for easier customization
+- Base scale from `--font-size-3xs` (10px) to `--font-size-hero` (64px)
+- Component-specific variables for blog headings, navigation, search, stats, and more
+- Mobile responsive overrides at 768px breakpoint
+
+Edit `src/styles/global.css` to customize font sizes across the entire site by changing the `:root` variables.
+
## v1.12.1
Released December 20, 2025
diff --git a/public/raw/docs.md b/public/raw/docs.md
index 23ddc60..f7db3f0 100644
--- a/public/raw/docs.md
+++ b/public/raw/docs.md
@@ -394,6 +394,22 @@ body {
}
```
+### Font Sizes
+
+All font sizes use CSS variables in `:root`. Customize by editing:
+
+```css
+:root {
+ --font-size-base: 16px;
+ --font-size-sm: 13px;
+ --font-size-lg: 17px;
+ --font-size-blog-content: 17px;
+ --font-size-post-title: 32px;
+}
+```
+
+Mobile sizes defined in `@media (max-width: 768px)` block.
+
### Images
| Image | Location | Size |
diff --git a/public/raw/setup-guide.md b/public/raw/setup-guide.md
index cfd65b1..60b9060 100644
--- a/public/raw/setup-guide.md
+++ b/public/raw/setup-guide.md
@@ -700,6 +700,29 @@ body {
}
```
+### Change Font Sizes
+
+All font sizes use CSS variables defined in `:root`. Customize sizes by editing these variables in `src/styles/global.css`:
+
+```css
+:root {
+ /* Base size scale */
+ --font-size-base: 16px;
+ --font-size-sm: 13px;
+ --font-size-lg: 17px;
+ --font-size-xl: 18px;
+ --font-size-2xl: 20px;
+ --font-size-3xl: 24px;
+
+ /* Component-specific (examples) */
+ --font-size-blog-content: 17px;
+ --font-size-post-title: 32px;
+ --font-size-nav-link: 14px;
+}
+```
+
+Mobile responsive sizes are defined in a `@media (max-width: 768px)` block.
+
### Add Static Pages (Optional)
Create optional pages like About, Projects, or Contact. These appear as navigation links in the top right corner.
@@ -941,6 +964,32 @@ markdown-site/
└── package.json # Dependencies
```
+## Write Page
+
+A markdown writing page is available at `/write` (not linked in navigation). Use it to draft content before saving to your markdown files.
+
+**Features:**
+
+- Three-column Cursor docs-style layout
+- Content type selector (Blog Post or Page) with dynamic frontmatter templates
+- Frontmatter field reference with individual copy buttons
+- Font switcher (Serif/Sans-serif)
+- Theme toggle matching site themes
+- Word, line, and character counts
+- localStorage persistence for content, type, and font preference
+- Works with Grammarly and browser spellcheck
+
+**Workflow:**
+
+1. Go to `yourdomain.com/write`
+2. Select content type (Blog Post or Page)
+3. Write your content using the frontmatter reference
+4. Click "Copy All" to copy the markdown
+5. Save to `content/blog/` or `content/pages/`
+6. Run `npm run sync` or `npm run sync:prod`
+
+Content is stored in localStorage only and not synced to the database. Refreshing the page preserves your content, but clearing browser data will lose it.
+
## Next Steps
After deploying:
diff --git a/src/App.tsx b/src/App.tsx
index b875f20..1cd8c17 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,8 +1,9 @@
-import { Routes, Route } from "react-router-dom";
+import { Routes, Route, useLocation } from "react-router-dom";
import Home from "./pages/Home";
import Post from "./pages/Post";
import Stats from "./pages/Stats";
import Blog from "./pages/Blog";
+import Write from "./pages/Write";
import Layout from "./components/Layout";
import { usePageTracking } from "./hooks/usePageTracking";
import siteConfig from "./config/siteConfig";
@@ -10,6 +11,12 @@ import siteConfig from "./config/siteConfig";
function App() {
// Track page views and active sessions
usePageTracking();
+ const location = useLocation();
+
+ // Write page renders without Layout (no header, full-screen writing)
+ if (location.pathname === "/write") {
+ return ;
+ }
return (
diff --git a/src/pages/Write.tsx b/src/pages/Write.tsx
new file mode 100644
index 0000000..11cb626
--- /dev/null
+++ b/src/pages/Write.tsx
@@ -0,0 +1,411 @@
+import { useState, useEffect, useCallback, useRef } from "react";
+import { Link } from "react-router-dom";
+import {
+ CopySimple,
+ Check,
+ Trash,
+ House,
+ Article,
+ File,
+ Warning,
+ TextAa,
+} from "@phosphor-icons/react";
+import { Moon, Sun, Cloud } from "lucide-react";
+import { Half2Icon } from "@radix-ui/react-icons";
+import { useTheme } from "../context/ThemeContext";
+
+// Frontmatter field definitions for blog posts
+const POST_FIELDS = [
+ { name: "title", required: true, example: '"Your Post Title"' },
+ {
+ name: "description",
+ required: true,
+ example: '"A brief description for SEO"',
+ },
+ { name: "date", required: true, example: '"2025-01-20"' },
+ { name: "slug", required: true, example: '"your-post-url"' },
+ { name: "published", required: true, example: "true" },
+ { name: "tags", required: true, example: '["tag1", "tag2"]' },
+ { name: "readTime", required: false, example: '"5 min read"' },
+ { name: "image", required: false, example: '"/images/my-image.png"' },
+ {
+ name: "excerpt",
+ required: false,
+ example: '"Short description for cards"',
+ },
+ { name: "featured", required: false, example: "true" },
+ { name: "featuredOrder", required: false, example: "1" },
+];
+
+// Frontmatter field definitions for pages
+const PAGE_FIELDS = [
+ { name: "title", required: true, example: '"Page Title"' },
+ { name: "slug", required: true, example: '"page-url"' },
+ { name: "published", required: true, example: "true" },
+ { name: "order", required: false, example: "1" },
+ { name: "excerpt", required: false, example: '"Short description"' },
+ { name: "image", required: false, example: '"/images/thumbnail.png"' },
+ { name: "featured", required: false, example: "true" },
+ { name: "featuredOrder", required: false, example: "1" },
+];
+
+// Generate frontmatter template based on content type
+function generateTemplate(type: "post" | "page"): string {
+ if (type === "post") {
+ return `---
+title: "Your Post Title"
+description: "A brief description for SEO and social sharing"
+date: "${new Date().toISOString().split("T")[0]}"
+slug: "your-post-url"
+published: true
+tags: ["tag1", "tag2"]
+readTime: "5 min read"
+---
+
+# Your Post Title
+
+Start writing your content here...
+
+## Section Heading
+
+Add your markdown content. You can use:
+
+- **Bold text** and *italic text*
+- [Links](https://example.com)
+- Code blocks with syntax highlighting
+
+\`\`\`typescript
+const greeting = "Hello, world";
+console.log(greeting);
+\`\`\`
+
+## Conclusion
+
+Wrap up your thoughts here.
+`;
+ }
+
+ return `---
+title: "Page Title"
+slug: "page-url"
+published: true
+order: 1
+---
+
+# Page Title
+
+Your page content goes here...
+
+## Section
+
+Add your markdown content.
+`;
+}
+
+// localStorage keys
+const STORAGE_KEY_CONTENT = "markdown_write_content";
+const STORAGE_KEY_TYPE = "markdown_write_type";
+const STORAGE_KEY_FONT = "markdown_write_font";
+
+// Font family definitions (matches global.css options)
+type FontType = "serif" | "sans";
+const FONTS: Record = {
+ serif:
+ '"New York", -apple-system-ui-serif, ui-serif, Georgia, Cambria, "Times New Roman", Times, serif',
+ sans: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif',
+};
+
+// Get the appropriate icon for current theme (matches ThemeToggle.tsx)
+function getThemeIcon(theme: string) {
+ switch (theme) {
+ case "dark":
+ return ;
+ case "light":
+ return ;
+ case "tan":
+ return ;
+ case "cloud":
+ return ;
+ default:
+ return ;
+ }
+}
+
+export default function Write() {
+ const { theme, toggleTheme } = useTheme();
+ const [contentType, setContentType] = useState<"post" | "page">("post");
+ const [content, setContent] = useState("");
+ const [copied, setCopied] = useState(false);
+ const [copiedField, setCopiedField] = useState(null);
+ const [font, setFont] = useState("serif");
+ const textareaRef = useRef(null);
+
+ // Load from localStorage on mount
+ useEffect(() => {
+ const savedContent = localStorage.getItem(STORAGE_KEY_CONTENT);
+ const savedType = localStorage.getItem(STORAGE_KEY_TYPE) as
+ | "post"
+ | "page"
+ | null;
+ const savedFont = localStorage.getItem(STORAGE_KEY_FONT) as FontType | null;
+
+ if (savedContent) {
+ setContent(savedContent);
+ } else {
+ setContent(generateTemplate("post"));
+ }
+
+ if (savedType) {
+ setContentType(savedType);
+ }
+
+ if (savedFont && (savedFont === "serif" || savedFont === "sans")) {
+ setFont(savedFont);
+ }
+ }, []);
+
+ // Save to localStorage on content change
+ useEffect(() => {
+ localStorage.setItem(STORAGE_KEY_CONTENT, content);
+ }, [content]);
+
+ // Save type to localStorage
+ useEffect(() => {
+ localStorage.setItem(STORAGE_KEY_TYPE, contentType);
+ }, [contentType]);
+
+ // Save font preference to localStorage
+ useEffect(() => {
+ localStorage.setItem(STORAGE_KEY_FONT, font);
+ }, [font]);
+
+ // Toggle font between serif and sans-serif
+ const toggleFont = useCallback(() => {
+ setFont((prev) => (prev === "serif" ? "sans" : "serif"));
+ }, []);
+
+ // Handle type change and update content template
+ const handleTypeChange = (newType: "post" | "page") => {
+ if (newType === contentType) return;
+
+ setContentType(newType);
+ // Always update to the new template when switching types
+ setContent(generateTemplate(newType));
+ };
+
+ // Copy content to clipboard
+ const handleCopy = useCallback(async () => {
+ try {
+ await navigator.clipboard.writeText(content);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ } catch {
+ // Fallback for older browsers
+ const textarea = document.createElement("textarea");
+ textarea.value = content;
+ document.body.appendChild(textarea);
+ textarea.select();
+ document.execCommand("copy");
+ document.body.removeChild(textarea);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ }
+ }, [content]);
+
+ // Copy a single frontmatter field to clipboard
+ const handleCopyField = useCallback(
+ async (fieldName: string, example: string) => {
+ const fieldText = `${fieldName}: ${example}`;
+ try {
+ await navigator.clipboard.writeText(fieldText);
+ setCopiedField(fieldName);
+ setTimeout(() => setCopiedField(null), 1500);
+ } catch {
+ // Fallback
+ const textarea = document.createElement("textarea");
+ textarea.value = fieldText;
+ document.body.appendChild(textarea);
+ textarea.select();
+ document.execCommand("copy");
+ document.body.removeChild(textarea);
+ setCopiedField(fieldName);
+ setTimeout(() => setCopiedField(null), 1500);
+ }
+ },
+ [],
+ );
+
+ // Clear content and reset to template
+ const handleClear = useCallback(() => {
+ setContent(generateTemplate(contentType));
+ if (textareaRef.current) {
+ textareaRef.current.focus();
+ }
+ }, [contentType]);
+
+ // Calculate stats
+ const lines = content.split("\n").length;
+ const characters = content.length;
+ const words = content.trim() ? content.trim().split(/\s+/).length : 0;
+
+ const fields = contentType === "post" ? POST_FIELDS : PAGE_FIELDS;
+
+ return (
+
+ {/* Left Sidebar: Type selector */}
+
+
+ {/* Main writing area */}
+
+