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 */} +
+
+

+ {contentType === "post" ? "Blog Post" : "Page"} +

+ +
+ +