diff --git a/.claude/skills/frontmatter.md b/.claude/skills/frontmatter.md index cf7058d..c65ef5c 100644 --- a/.claude/skills/frontmatter.md +++ b/.claude/skills/frontmatter.md @@ -164,6 +164,43 @@ showFooter: true footer: "Custom footer text in **markdown**" ``` +## Docs section navigation + +Posts and pages can appear in the docs sidebar navigation using these fields: + +| Field | Type | Description | +|-------|------|-------------| +| docsSection | boolean | Include in docs navigation | +| docsSectionGroup | string | Sidebar group name | +| docsSectionOrder | number | Order within group (lower = first) | +| docsSectionGroupOrder | number | Order of group itself (lower = first) | +| docsSectionGroupIcon | string | Phosphor icon name for group (e.g., "Rocket", "Book") | +| docsLanding | boolean | Use as /docs landing page | + +### Example docs post + +```yaml +--- +title: "Getting Started" +slug: "getting-started" +published: true +docsSection: true +docsSectionGroup: "Quick Start" +docsSectionOrder: 1 +docsSectionGroupOrder: 1 +docsSectionGroupIcon: "Rocket" +layout: "sidebar" +--- +``` + +### Supported icons + +The following Phosphor icon names are supported for `docsSectionGroupIcon`: + +House, Book, Gear, Folder, Code, FileText, Question, Lightbulb, Rocket, Star, Heart, Bell, Calendar, User, ArrowRight, Check, Warning, Info, Lightning, Database, Globe, Lock, Key, Shield, Terminal, Package, PuzzlePiece, Flag, Target, Compass, MapPin, Bookmark, Tag, Hash, Link, At, Play, Pause, Plus, Minus, X, List, MagnifyingGlass, FunnelSimple, SortAscending, Download, Upload, Share, Copy, Clipboard, PencilSimple, Trash, Archive, Eye, EyeClosed + +Only one item per group needs to specify the icon. If multiple items in a group have different icons, the first one found will be used. + ## Validation The sync script validates: diff --git a/TASK.md b/TASK.md index d3a493b..874ffbd 100644 --- a/TASK.md +++ b/TASK.md @@ -9,10 +9,23 @@ ## Current Status -v2.6.0 ready. Multi-model AI chat and image generation in Dashboard. +v2.8.0 ready. Docs sidebar group icons via frontmatter. ## Completed +- [x] Docs sidebar group icons via frontmatter + - [x] Added `docsSectionGroupIcon` frontmatter field for posts and pages + - [x] Icon appears left of the group title expand/collapse chevron + - [x] Uses Phosphor Icons (55 supported icon names) + - [x] Icon weight: regular, size: 16px + - [x] Only one item per group needs to specify the icon + - [x] Graceful fallback if icon name not recognized + - [x] Updated sync-posts.ts, schema.ts, posts.ts, pages.ts + - [x] Updated DocsSidebar.tsx with icon mapping and rendering + - [x] Added CSS styles for group icons + - [x] Updated frontmatter.md skill with icon documentation + - [x] Updated docs.md, files.md, setup-guide.md with new field + - [x] Multi-model AI chat and image generation in Dashboard - [x] AI Agent section with tab-based UI (Chat and Image Generation tabs) - [x] Multi-model selector for text chat (Claude Sonnet 4, GPT-4o, Gemini 2.0 Flash) diff --git a/changelog.md b/changelog.md index 6e4f22b..c783a91 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,27 @@ 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/). +## [2.8.0] - 2026-01-03 + +### Added + +- `docsSectionGroupIcon` frontmatter field for docs sidebar group icons + - Display Phosphor icons next to docs sidebar group titles + - Icon appears left of the expand/collapse chevron + - 55 supported icon names (Rocket, Book, PuzzlePiece, Gear, Code, etc.) + - Icon weight: regular, size: 16px + - Only one item per group needs to specify the icon + - Graceful fallback if icon name not recognized + +### Technical + +- Updated `convex/schema.ts` to include `docsSectionGroupIcon` field in posts and pages tables +- Updated `convex/posts.ts` and `convex/pages.ts` queries and mutations to handle `docsSectionGroupIcon` +- Updated `scripts/sync-posts.ts` to parse `docsSectionGroupIcon` from frontmatter +- Updated `src/components/DocsSidebar.tsx` with Phosphor icon imports and rendering +- Added CSS styles for `.docs-sidebar-group-icon` in `src/styles/global.css` +- Updated `.claude/skills/frontmatter.md` with icon documentation and supported icon list + ## [2.7.0] - 2026-01-02 ### Added diff --git a/content/blog/how-to-publish.md b/content/blog/how-to-publish.md index 2f69f99..9ed518a 100644 --- a/content/blog/how-to-publish.md +++ b/content/blog/how-to-publish.md @@ -17,6 +17,7 @@ excerpt: "Quick guide to writing and publishing markdown posts with npm run sync aiChat: true docsSection: true docsSectionGroup: "Publishing" +docsSectionGroupIcon: "User" docsSectionOrder: 3 docsSectionGroupOrder: 3 --- diff --git a/content/blog/how-to-setup-workos.md b/content/blog/how-to-setup-workos.md index 068ab13..5301cbe 100644 --- a/content/blog/how-to-setup-workos.md +++ b/content/blog/how-to-setup-workos.md @@ -14,6 +14,7 @@ excerpt: "Complete guide to setting up WorkOS AuthKit authentication for your da docsSection: true docsSectionOrder: 2 docsSectionGroup: "Components" +docsSectionGroupIcon: "PuzzlePiece" docsLanding: true --- diff --git a/content/blog/how-to-use-mcp-server.md b/content/blog/how-to-use-mcp-server.md index 59b4b07..68e3efe 100644 --- a/content/blog/how-to-use-mcp-server.md +++ b/content/blog/how-to-use-mcp-server.md @@ -11,6 +11,7 @@ tags: ["mcp", "cursor", "ai", "tutorial", "netlify"] docsSection: true docsSectionOrder: 2 docsSectionGroup: "Components" +docsSectionGroupIcon: "PuzzlePiece" docsLanding: true --- diff --git a/content/blog/setup-guide.md b/content/blog/setup-guide.md index 222de64..34e8d1d 100644 --- a/content/blog/setup-guide.md +++ b/content/blog/setup-guide.md @@ -369,6 +369,7 @@ Your markdown content here... | `docsSectionGroup` | No | Group name for docs sidebar. Posts with the same group name appear together. | | `docsSectionOrder` | No | Order within docs group. Lower numbers appear first within the group. | | `docsSectionGroupOrder` | No | Order of the group in docs sidebar. Lower numbers make the group appear first. Groups without this field sort alphabetically. | +| `docsSectionGroupIcon` | No | Phosphor icon name for docs sidebar group (e.g., "Rocket", "Book", "PuzzlePiece"). Icon appears left of the group title. See [Phosphor Icons](https://phosphoricons.com) for available icons. | ### How Frontmatter Works diff --git a/content/pages/changelog-page.md b/content/pages/changelog-page.md index 8d7ce93..5e3482f 100644 --- a/content/pages/changelog-page.md +++ b/content/pages/changelog-page.md @@ -12,6 +12,43 @@ docsSectionOrder: 4 All notable changes to this project. ![](https://img.shields.io/badge/License-MIT-yellow.svg) +## v2.8.0 + +Released January 3, 2026 + +**Docs sidebar group icons via frontmatter** + +- New `docsSectionGroupIcon` frontmatter field for docs sidebar group icons + - Display Phosphor icons next to docs sidebar group titles + - Icon appears left of the expand/collapse chevron + - 55 supported icon names (Rocket, Book, PuzzlePiece, Gear, Code, etc.) + - Icon weight: regular, size: 16px + - Only one item per group needs to specify the icon + - Graceful fallback if icon name not recognized + +**Example usage:** + +```yaml +--- +docsSection: true +docsSectionGroup: "Getting Started" +docsSectionGroupOrder: 1 +docsSectionGroupIcon: "Rocket" +docsSectionOrder: 1 +--- +``` + +**Technical details:** + +- Updated `convex/schema.ts` with `docsSectionGroupIcon` field in posts and pages tables +- Updated `convex/posts.ts` and `convex/pages.ts` queries and mutations +- Updated `scripts/sync-posts.ts` to parse `docsSectionGroupIcon` from frontmatter +- Updated `src/components/DocsSidebar.tsx` with Phosphor icon imports and rendering +- Added CSS styles for `.docs-sidebar-group-icon` +- Updated `.claude/skills/frontmatter.md` with icon documentation + +Updated files: `convex/schema.ts`, `convex/posts.ts`, `convex/pages.ts`, `scripts/sync-posts.ts`, `src/components/DocsSidebar.tsx`, `src/styles/global.css`, `.claude/skills/frontmatter.md`, `files.md`, `TASK.md`, `changelog.md`, `content/pages/docs.md`, `public/raw/setup-guide.md` + ## v2.7.0 Released January 2, 2026 diff --git a/content/pages/docs.md b/content/pages/docs.md index e284a98..d26ed0f 100644 --- a/content/pages/docs.md +++ b/content/pages/docs.md @@ -11,6 +11,7 @@ showFooter: true docsSection: true docsSectionOrder: 1 docsSectionGroup: "Setup" +docsSectionGroupIcon: "Rocket" docsLanding: true --- @@ -109,37 +110,38 @@ image: "/images/og-image.png" Content here... ``` -| Field | Required | Description | -| ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `title` | Yes | Post title | -| `description` | Yes | SEO description | -| `date` | Yes | YYYY-MM-DD format | -| `slug` | Yes | URL path (unique) | -| `published` | Yes | `true` to show | -| `tags` | Yes | Array of strings | -| `readTime` | No | Display time estimate | -| `image` | No | OG image and featured card thumbnail. See [Using Images in Blog Posts](/using-images-in-posts) for markdown and HTML syntax | -| `showImageAtTop` | No | Set `true` to display the image at the top of the post above the header (default: `false`) | -| `excerpt` | No | Short text for card view | -| `featured` | No | `true` to show in featured section | -| `featuredOrder` | No | Order in featured (lower = first) | -| `authorName` | No | Author display name shown next to date | -| `authorImage` | No | Round author avatar image URL | -| `layout` | No | Set to `"sidebar"` for docs-style layout with TOC | -| `rightSidebar` | No | Enable right sidebar with CopyPageDropdown (opt-in, requires explicit `true`) | -| `showFooter` | No | Show footer on this post (overrides siteConfig default) | -| `footer` | No | Per-post footer markdown (overrides `footer.md` and siteConfig.defaultContent) | -| `showSocialFooter` | No | Show social footer on this post (overrides siteConfig default) | -| `aiChat` | No | Enable AI chat in right sidebar. Set `true` to enable (requires `rightSidebar: true` and `siteConfig.aiChat.enabledOnContent: true`). Set `false` to explicitly hide even if global config is enabled. | -| `blogFeatured` | No | Show as featured on blog page (first becomes hero, rest in 2-column row) | -| `newsletter` | No | Override newsletter signup display (`true` to show, `false` to hide) | -| `contactForm` | No | Enable contact form on this post | -| `unlisted` | No | Hide from listings but allow direct access via slug. Set `true` to hide from blog listings, featured sections, tag pages, search results, and related posts. Post remains accessible via direct link. | -| `docsSection` | No | Include in docs sidebar. Set `true` to show in the docs section navigation. | -| `docsSectionGroup` | No | Group name for docs sidebar. Posts with the same group name appear together. | -| `docsSectionOrder` | No | Order within docs group. Lower numbers appear first within the group. | -| `docsSectionGroupOrder` | No | Order of the group in docs sidebar. Lower numbers make the group appear first. Groups without this field sort alphabetically. | -| `showImageAtTop` | No | Set `true` to display the `image` field at the top of the post above the header (default: `false`) | +| Field | Required | Description | +| ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `title` | Yes | Post title | +| `description` | Yes | SEO description | +| `date` | Yes | YYYY-MM-DD format | +| `slug` | Yes | URL path (unique) | +| `published` | Yes | `true` to show | +| `tags` | Yes | Array of strings | +| `readTime` | No | Display time estimate | +| `image` | No | OG image and featured card thumbnail. See [Using Images in Blog Posts](/using-images-in-posts) for markdown and HTML syntax | +| `showImageAtTop` | No | Set `true` to display the image at the top of the post above the header (default: `false`) | +| `excerpt` | No | Short text for card view | +| `featured` | No | `true` to show in featured section | +| `featuredOrder` | No | Order in featured (lower = first) | +| `authorName` | No | Author display name shown next to date | +| `authorImage` | No | Round author avatar image URL | +| `layout` | No | Set to `"sidebar"` for docs-style layout with TOC | +| `rightSidebar` | No | Enable right sidebar with CopyPageDropdown (opt-in, requires explicit `true`) | +| `showFooter` | No | Show footer on this post (overrides siteConfig default) | +| `footer` | No | Per-post footer markdown (overrides `footer.md` and siteConfig.defaultContent) | +| `showSocialFooter` | No | Show social footer on this post (overrides siteConfig default) | +| `aiChat` | No | Enable AI chat in right sidebar. Set `true` to enable (requires `rightSidebar: true` and `siteConfig.aiChat.enabledOnContent: true`). Set `false` to explicitly hide even if global config is enabled. | +| `blogFeatured` | No | Show as featured on blog page (first becomes hero, rest in 2-column row) | +| `newsletter` | No | Override newsletter signup display (`true` to show, `false` to hide) | +| `contactForm` | No | Enable contact form on this post | +| `unlisted` | No | Hide from listings but allow direct access via slug. Set `true` to hide from blog listings, featured sections, tag pages, search results, and related posts. Post remains accessible via direct link. | +| `docsSection` | No | Include in docs sidebar. Set `true` to show in the docs section navigation. | +| `docsSectionGroup` | No | Group name for docs sidebar. Posts with the same group name appear together. | +| `docsSectionOrder` | No | Order within docs group. Lower numbers appear first within the group. | +| `docsSectionGroupOrder` | No | Order of the group in docs sidebar. Lower numbers make the group appear first. Groups without this field sort alphabetically. | +| `docsSectionGroupIcon` | No | Phosphor icon name for docs sidebar group (e.g., "Rocket", "Book", "PuzzlePiece"). Icon appears left of the group title. See [Phosphor Icons](https://phosphoricons.com) for available icons. | +| `showImageAtTop` | No | Set `true` to display the `image` field at the top of the post above the header (default: `false`) | ### Static pages @@ -158,34 +160,35 @@ Content here... ### Frontmatter options -| Field | Required | Description | -| ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `title` | Yes | Nav link text | -| `slug` | Yes | URL path | -| `published` | Yes | `true` to show | -| `order` | No | Nav order (lower = first) | -| `showInNav` | No | Show in navigation menu (default: `true`) | -| `excerpt` | No | Short text for card view | -| `image` | No | Thumbnail for featured card view | -| `showImageAtTop` | No | Set `true` to display the image at the top of the page above the header (default: `false`) | -| `featured` | No | `true` to show in featured section | -| `featuredOrder` | No | Order in featured (lower = first) | -| `authorName` | No | Author display name shown next to date | -| `authorImage` | No | Round author avatar image URL | -| `layout` | No | Set to `"sidebar"` for docs-style layout with TOC | -| `rightSidebar` | No | Enable right sidebar with CopyPageDropdown (opt-in, requires explicit `true`) | -| `showFooter` | No | Show footer on this page (overrides siteConfig default) | -| `footer` | No | Per-page footer markdown (overrides `footer.md` and siteConfig.defaultContent) | -| `showSocialFooter` | No | Show social footer on this page (overrides siteConfig default) | -| `aiChat` | No | Enable AI chat in right sidebar. Set `true` to enable (requires `rightSidebar: true` and `siteConfig.aiChat.enabledOnContent: true`). Set `false` to explicitly hide even if global config is enabled. | -| `newsletter` | No | Override newsletter signup display (`true` to show, `false` to hide) | -| `contactForm` | No | Enable contact form on this page | -| `showImageAtTop` | No | Set `true` to display the `image` field at the top of the page above the header (default: `false`) | -| `textAlign` | No | Text alignment: "left" (default), "center", or "right". Used by `home.md` for home intro alignment | -| `docsSection` | No | Include in docs sidebar. Set `true` to show in the docs section navigation. | -| `docsSectionGroup` | No | Group name for docs sidebar. Pages with the same group name appear together. | -| `docsSectionOrder` | No | Order within docs group. Lower numbers appear first within the group. | -| `docsSectionGroupOrder` | No | Order of the group in docs sidebar. Lower numbers make the group appear first. Groups without this field sort alphabetically. | +| Field | Required | Description | +| ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `title` | Yes | Nav link text | +| `slug` | Yes | URL path | +| `published` | Yes | `true` to show | +| `order` | No | Nav order (lower = first) | +| `showInNav` | No | Show in navigation menu (default: `true`) | +| `excerpt` | No | Short text for card view | +| `image` | No | Thumbnail for featured card view | +| `showImageAtTop` | No | Set `true` to display the image at the top of the page above the header (default: `false`) | +| `featured` | No | `true` to show in featured section | +| `featuredOrder` | No | Order in featured (lower = first) | +| `authorName` | No | Author display name shown next to date | +| `authorImage` | No | Round author avatar image URL | +| `layout` | No | Set to `"sidebar"` for docs-style layout with TOC | +| `rightSidebar` | No | Enable right sidebar with CopyPageDropdown (opt-in, requires explicit `true`) | +| `showFooter` | No | Show footer on this page (overrides siteConfig default) | +| `footer` | No | Per-page footer markdown (overrides `footer.md` and siteConfig.defaultContent) | +| `showSocialFooter` | No | Show social footer on this page (overrides siteConfig default) | +| `aiChat` | No | Enable AI chat in right sidebar. Set `true` to enable (requires `rightSidebar: true` and `siteConfig.aiChat.enabledOnContent: true`). Set `false` to explicitly hide even if global config is enabled. | +| `newsletter` | No | Override newsletter signup display (`true` to show, `false` to hide) | +| `contactForm` | No | Enable contact form on this page | +| `showImageAtTop` | No | Set `true` to display the `image` field at the top of the page above the header (default: `false`) | +| `textAlign` | No | Text alignment: "left" (default), "center", or "right". Used by `home.md` for home intro alignment | +| `docsSection` | No | Include in docs sidebar. Set `true` to show in the docs section navigation. | +| `docsSectionGroup` | No | Group name for docs sidebar. Pages with the same group name appear together. | +| `docsSectionOrder` | No | Order within docs group. Lower numbers appear first within the group. | +| `docsSectionGroupOrder` | No | Order of the group in docs sidebar. Lower numbers make the group appear first. Groups without this field sort alphabetically. | +| `docsSectionGroupIcon` | No | Phosphor icon name for docs sidebar group (e.g., "Rocket", "Book", "PuzzlePiece"). Icon appears left of the group title. See [Phosphor Icons](https://phosphoricons.com) for available icons. | **Hide pages from navigation:** Set `showInNav: false` to keep a page published and accessible via direct URL, but hidden from the navigation menu. Pages with `showInNav: false` remain searchable and available via API endpoints. Useful for pages you want to link directly but not show in the main nav. diff --git a/convex/pages.ts b/convex/pages.ts index d246e27..2150739 100644 --- a/convex/pages.ts +++ b/convex/pages.ts @@ -239,6 +239,7 @@ export const getDocsPages = query({ docsSectionGroup: v.optional(v.string()), docsSectionOrder: v.optional(v.number()), docsSectionGroupOrder: v.optional(v.number()), + docsSectionGroupIcon: v.optional(v.string()), }), ), handler: async (ctx) => { @@ -265,6 +266,7 @@ export const getDocsPages = query({ docsSectionGroup: page.docsSectionGroup, docsSectionOrder: page.docsSectionOrder, docsSectionGroupOrder: page.docsSectionGroupOrder, + docsSectionGroupIcon: page.docsSectionGroupIcon, })); }, }); @@ -345,6 +347,7 @@ export const syncPagesPublic = mutation({ docsSectionGroup: v.optional(v.string()), docsSectionOrder: v.optional(v.number()), docsSectionGroupOrder: v.optional(v.number()), + docsSectionGroupIcon: v.optional(v.string()), docsLanding: v.optional(v.boolean()), }), ), @@ -398,6 +401,7 @@ export const syncPagesPublic = mutation({ docsSectionGroup: page.docsSectionGroup, docsSectionOrder: page.docsSectionOrder, docsSectionGroupOrder: page.docsSectionGroupOrder, + docsSectionGroupIcon: page.docsSectionGroupIcon, docsLanding: page.docsLanding, lastSyncedAt: now, }); diff --git a/convex/posts.ts b/convex/posts.ts index de7b88d..e93fdef 100644 --- a/convex/posts.ts +++ b/convex/posts.ts @@ -390,6 +390,7 @@ export const syncPosts = internalMutation({ docsSectionGroup: v.optional(v.string()), docsSectionOrder: v.optional(v.number()), docsSectionGroupOrder: v.optional(v.number()), + docsSectionGroupIcon: v.optional(v.string()), docsLanding: v.optional(v.boolean()), }), ), @@ -446,6 +447,7 @@ export const syncPosts = internalMutation({ docsSectionGroup: post.docsSectionGroup, docsSectionOrder: post.docsSectionOrder, docsSectionGroupOrder: post.docsSectionGroupOrder, + docsSectionGroupIcon: post.docsSectionGroupIcon, docsLanding: post.docsLanding, lastSyncedAt: now, }); @@ -506,6 +508,7 @@ export const syncPostsPublic = mutation({ docsSectionGroup: v.optional(v.string()), docsSectionOrder: v.optional(v.number()), docsSectionGroupOrder: v.optional(v.number()), + docsSectionGroupIcon: v.optional(v.string()), docsLanding: v.optional(v.boolean()), }), ), @@ -562,6 +565,7 @@ export const syncPostsPublic = mutation({ docsSectionGroup: post.docsSectionGroup, docsSectionOrder: post.docsSectionOrder, docsSectionGroupOrder: post.docsSectionGroupOrder, + docsSectionGroupIcon: post.docsSectionGroupIcon, docsLanding: post.docsLanding, lastSyncedAt: now, }); @@ -909,6 +913,7 @@ export const getDocsPosts = query({ docsSectionGroup: v.optional(v.string()), docsSectionOrder: v.optional(v.number()), docsSectionGroupOrder: v.optional(v.number()), + docsSectionGroupIcon: v.optional(v.string()), }), ), handler: async (ctx) => { @@ -935,6 +940,7 @@ export const getDocsPosts = query({ docsSectionGroup: post.docsSectionGroup, docsSectionOrder: post.docsSectionOrder, docsSectionGroupOrder: post.docsSectionGroupOrder, + docsSectionGroupIcon: post.docsSectionGroupIcon, })); }, }); diff --git a/convex/schema.ts b/convex/schema.ts index 8fb9715..93439c8 100644 --- a/convex/schema.ts +++ b/convex/schema.ts @@ -33,6 +33,7 @@ export default defineSchema({ docsSectionGroup: v.optional(v.string()), // Sidebar group name in docs docsSectionOrder: v.optional(v.number()), // Order within group (lower = first) docsSectionGroupOrder: v.optional(v.number()), // Order of group itself (lower = first) + docsSectionGroupIcon: v.optional(v.string()), // Phosphor icon name for sidebar group docsLanding: v.optional(v.boolean()), // Use as /docs landing page lastSyncedAt: v.number(), }) @@ -80,6 +81,7 @@ export default defineSchema({ docsSectionGroup: v.optional(v.string()), // Sidebar group name in docs docsSectionOrder: v.optional(v.number()), // Order within group (lower = first) docsSectionGroupOrder: v.optional(v.number()), // Order of group itself (lower = first) + docsSectionGroupIcon: v.optional(v.string()), // Phosphor icon name for sidebar group docsLanding: v.optional(v.boolean()), // Use as /docs landing page lastSyncedAt: v.number(), }) diff --git a/files.md b/files.md index 5138803..ebf8d41 100644 --- a/files.md +++ b/files.md @@ -176,6 +176,7 @@ Markdown files with frontmatter for blog posts. Each file becomes a blog post. | `docsSectionGroup` | Group name for docs sidebar (optional). Posts with the same group name appear together. | | `docsSectionOrder` | Order within docs group (optional). Lower numbers appear first within the group. | | `docsSectionGroupOrder` | Order of the group in docs sidebar (optional). Lower numbers make the group appear first. Groups without this field sort alphabetically. | +| `docsSectionGroupIcon` | Phosphor icon name for docs sidebar group (optional, e.g., "Rocket", "Book", "PuzzlePiece"). Icon appears left of the group title. See [Phosphor Icons](https://phosphoricons.com) for available icons. | ## Static Pages (`content/pages/`) @@ -211,6 +212,7 @@ Markdown files for static pages like About, Projects, Contact, Changelog. | `docsSectionGroup` | Group name for docs sidebar (optional). Pages with the same group name appear together. | | `docsSectionOrder` | Order within docs group (optional). Lower numbers appear first within the group. | | `docsSectionGroupOrder` | Order of the group in docs sidebar (optional). Lower numbers make the group appear first. Groups without this field sort alphabetically. | +| `docsSectionGroupIcon` | Phosphor icon name for docs sidebar group (optional, e.g., "Rocket", "Book", "PuzzlePiece"). Icon appears left of the group title. See [Phosphor Icons](https://phosphoricons.com) for available icons. | ## Scripts (`scripts/`) diff --git a/public/raw/changelog.md b/public/raw/changelog.md index 8963a93..6f48798 100644 --- a/public/raw/changelog.md +++ b/public/raw/changelog.md @@ -8,6 +8,43 @@ Date: 2026-01-03 All notable changes to this project. ![](https://img.shields.io/badge/License-MIT-yellow.svg) +## v2.8.0 + +Released January 3, 2026 + +**Docs sidebar group icons via frontmatter** + +- New `docsSectionGroupIcon` frontmatter field for docs sidebar group icons + - Display Phosphor icons next to docs sidebar group titles + - Icon appears left of the expand/collapse chevron + - 55 supported icon names (Rocket, Book, PuzzlePiece, Gear, Code, etc.) + - Icon weight: regular, size: 16px + - Only one item per group needs to specify the icon + - Graceful fallback if icon name not recognized + +**Example usage:** + +```yaml +--- +docsSection: true +docsSectionGroup: "Getting Started" +docsSectionGroupOrder: 1 +docsSectionGroupIcon: "Rocket" +docsSectionOrder: 1 +--- +``` + +**Technical details:** + +- Updated `convex/schema.ts` with `docsSectionGroupIcon` field in posts and pages tables +- Updated `convex/posts.ts` and `convex/pages.ts` queries and mutations +- Updated `scripts/sync-posts.ts` to parse `docsSectionGroupIcon` from frontmatter +- Updated `src/components/DocsSidebar.tsx` with Phosphor icon imports and rendering +- Added CSS styles for `.docs-sidebar-group-icon` +- Updated `.claude/skills/frontmatter.md` with icon documentation + +Updated files: `convex/schema.ts`, `convex/posts.ts`, `convex/pages.ts`, `scripts/sync-posts.ts`, `src/components/DocsSidebar.tsx`, `src/styles/global.css`, `.claude/skills/frontmatter.md`, `files.md`, `TASK.md`, `changelog.md`, `content/pages/docs.md`, `public/raw/setup-guide.md` + ## v2.7.0 Released January 2, 2026 diff --git a/public/raw/documentation.md b/public/raw/documentation.md index 3127646..c756e16 100644 --- a/public/raw/documentation.md +++ b/public/raw/documentation.md @@ -100,37 +100,38 @@ image: "/images/og-image.png" Content here... ``` -| Field | Required | Description | -| ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `title` | Yes | Post title | -| `description` | Yes | SEO description | -| `date` | Yes | YYYY-MM-DD format | -| `slug` | Yes | URL path (unique) | -| `published` | Yes | `true` to show | -| `tags` | Yes | Array of strings | -| `readTime` | No | Display time estimate | -| `image` | No | OG image and featured card thumbnail. See [Using Images in Blog Posts](/using-images-in-posts) for markdown and HTML syntax | -| `showImageAtTop` | No | Set `true` to display the image at the top of the post above the header (default: `false`) | -| `excerpt` | No | Short text for card view | -| `featured` | No | `true` to show in featured section | -| `featuredOrder` | No | Order in featured (lower = first) | -| `authorName` | No | Author display name shown next to date | -| `authorImage` | No | Round author avatar image URL | -| `layout` | No | Set to `"sidebar"` for docs-style layout with TOC | -| `rightSidebar` | No | Enable right sidebar with CopyPageDropdown (opt-in, requires explicit `true`) | -| `showFooter` | No | Show footer on this post (overrides siteConfig default) | -| `footer` | No | Per-post footer markdown (overrides `footer.md` and siteConfig.defaultContent) | -| `showSocialFooter` | No | Show social footer on this post (overrides siteConfig default) | -| `aiChat` | No | Enable AI chat in right sidebar. Set `true` to enable (requires `rightSidebar: true` and `siteConfig.aiChat.enabledOnContent: true`). Set `false` to explicitly hide even if global config is enabled. | -| `blogFeatured` | No | Show as featured on blog page (first becomes hero, rest in 2-column row) | -| `newsletter` | No | Override newsletter signup display (`true` to show, `false` to hide) | -| `contactForm` | No | Enable contact form on this post | -| `unlisted` | No | Hide from listings but allow direct access via slug. Set `true` to hide from blog listings, featured sections, tag pages, search results, and related posts. Post remains accessible via direct link. | -| `docsSection` | No | Include in docs sidebar. Set `true` to show in the docs section navigation. | -| `docsSectionGroup` | No | Group name for docs sidebar. Posts with the same group name appear together. | -| `docsSectionOrder` | No | Order within docs group. Lower numbers appear first within the group. | -| `docsSectionGroupOrder` | No | Order of the group in docs sidebar. Lower numbers make the group appear first. Groups without this field sort alphabetically. | -| `showImageAtTop` | No | Set `true` to display the `image` field at the top of the post above the header (default: `false`) | +| Field | Required | Description | +| ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `title` | Yes | Post title | +| `description` | Yes | SEO description | +| `date` | Yes | YYYY-MM-DD format | +| `slug` | Yes | URL path (unique) | +| `published` | Yes | `true` to show | +| `tags` | Yes | Array of strings | +| `readTime` | No | Display time estimate | +| `image` | No | OG image and featured card thumbnail. See [Using Images in Blog Posts](/using-images-in-posts) for markdown and HTML syntax | +| `showImageAtTop` | No | Set `true` to display the image at the top of the post above the header (default: `false`) | +| `excerpt` | No | Short text for card view | +| `featured` | No | `true` to show in featured section | +| `featuredOrder` | No | Order in featured (lower = first) | +| `authorName` | No | Author display name shown next to date | +| `authorImage` | No | Round author avatar image URL | +| `layout` | No | Set to `"sidebar"` for docs-style layout with TOC | +| `rightSidebar` | No | Enable right sidebar with CopyPageDropdown (opt-in, requires explicit `true`) | +| `showFooter` | No | Show footer on this post (overrides siteConfig default) | +| `footer` | No | Per-post footer markdown (overrides `footer.md` and siteConfig.defaultContent) | +| `showSocialFooter` | No | Show social footer on this post (overrides siteConfig default) | +| `aiChat` | No | Enable AI chat in right sidebar. Set `true` to enable (requires `rightSidebar: true` and `siteConfig.aiChat.enabledOnContent: true`). Set `false` to explicitly hide even if global config is enabled. | +| `blogFeatured` | No | Show as featured on blog page (first becomes hero, rest in 2-column row) | +| `newsletter` | No | Override newsletter signup display (`true` to show, `false` to hide) | +| `contactForm` | No | Enable contact form on this post | +| `unlisted` | No | Hide from listings but allow direct access via slug. Set `true` to hide from blog listings, featured sections, tag pages, search results, and related posts. Post remains accessible via direct link. | +| `docsSection` | No | Include in docs sidebar. Set `true` to show in the docs section navigation. | +| `docsSectionGroup` | No | Group name for docs sidebar. Posts with the same group name appear together. | +| `docsSectionOrder` | No | Order within docs group. Lower numbers appear first within the group. | +| `docsSectionGroupOrder` | No | Order of the group in docs sidebar. Lower numbers make the group appear first. Groups without this field sort alphabetically. | +| `docsSectionGroupIcon` | No | Phosphor icon name for docs sidebar group (e.g., "Rocket", "Book", "PuzzlePiece"). Icon appears left of the group title. See [Phosphor Icons](https://phosphoricons.com) for available icons. | +| `showImageAtTop` | No | Set `true` to display the `image` field at the top of the post above the header (default: `false`) | ### Static pages @@ -149,34 +150,35 @@ Content here... ### Frontmatter options -| Field | Required | Description | -| ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `title` | Yes | Nav link text | -| `slug` | Yes | URL path | -| `published` | Yes | `true` to show | -| `order` | No | Nav order (lower = first) | -| `showInNav` | No | Show in navigation menu (default: `true`) | -| `excerpt` | No | Short text for card view | -| `image` | No | Thumbnail for featured card view | -| `showImageAtTop` | No | Set `true` to display the image at the top of the page above the header (default: `false`) | -| `featured` | No | `true` to show in featured section | -| `featuredOrder` | No | Order in featured (lower = first) | -| `authorName` | No | Author display name shown next to date | -| `authorImage` | No | Round author avatar image URL | -| `layout` | No | Set to `"sidebar"` for docs-style layout with TOC | -| `rightSidebar` | No | Enable right sidebar with CopyPageDropdown (opt-in, requires explicit `true`) | -| `showFooter` | No | Show footer on this page (overrides siteConfig default) | -| `footer` | No | Per-page footer markdown (overrides `footer.md` and siteConfig.defaultContent) | -| `showSocialFooter` | No | Show social footer on this page (overrides siteConfig default) | -| `aiChat` | No | Enable AI chat in right sidebar. Set `true` to enable (requires `rightSidebar: true` and `siteConfig.aiChat.enabledOnContent: true`). Set `false` to explicitly hide even if global config is enabled. | -| `newsletter` | No | Override newsletter signup display (`true` to show, `false` to hide) | -| `contactForm` | No | Enable contact form on this page | -| `showImageAtTop` | No | Set `true` to display the `image` field at the top of the page above the header (default: `false`) | -| `textAlign` | No | Text alignment: "left" (default), "center", or "right". Used by `home.md` for home intro alignment | -| `docsSection` | No | Include in docs sidebar. Set `true` to show in the docs section navigation. | -| `docsSectionGroup` | No | Group name for docs sidebar. Pages with the same group name appear together. | -| `docsSectionOrder` | No | Order within docs group. Lower numbers appear first within the group. | -| `docsSectionGroupOrder` | No | Order of the group in docs sidebar. Lower numbers make the group appear first. Groups without this field sort alphabetically. | +| Field | Required | Description | +| ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `title` | Yes | Nav link text | +| `slug` | Yes | URL path | +| `published` | Yes | `true` to show | +| `order` | No | Nav order (lower = first) | +| `showInNav` | No | Show in navigation menu (default: `true`) | +| `excerpt` | No | Short text for card view | +| `image` | No | Thumbnail for featured card view | +| `showImageAtTop` | No | Set `true` to display the image at the top of the page above the header (default: `false`) | +| `featured` | No | `true` to show in featured section | +| `featuredOrder` | No | Order in featured (lower = first) | +| `authorName` | No | Author display name shown next to date | +| `authorImage` | No | Round author avatar image URL | +| `layout` | No | Set to `"sidebar"` for docs-style layout with TOC | +| `rightSidebar` | No | Enable right sidebar with CopyPageDropdown (opt-in, requires explicit `true`) | +| `showFooter` | No | Show footer on this page (overrides siteConfig default) | +| `footer` | No | Per-page footer markdown (overrides `footer.md` and siteConfig.defaultContent) | +| `showSocialFooter` | No | Show social footer on this page (overrides siteConfig default) | +| `aiChat` | No | Enable AI chat in right sidebar. Set `true` to enable (requires `rightSidebar: true` and `siteConfig.aiChat.enabledOnContent: true`). Set `false` to explicitly hide even if global config is enabled. | +| `newsletter` | No | Override newsletter signup display (`true` to show, `false` to hide) | +| `contactForm` | No | Enable contact form on this page | +| `showImageAtTop` | No | Set `true` to display the `image` field at the top of the page above the header (default: `false`) | +| `textAlign` | No | Text alignment: "left" (default), "center", or "right". Used by `home.md` for home intro alignment | +| `docsSection` | No | Include in docs sidebar. Set `true` to show in the docs section navigation. | +| `docsSectionGroup` | No | Group name for docs sidebar. Pages with the same group name appear together. | +| `docsSectionOrder` | No | Order within docs group. Lower numbers appear first within the group. | +| `docsSectionGroupOrder` | No | Order of the group in docs sidebar. Lower numbers make the group appear first. Groups without this field sort alphabetically. | +| `docsSectionGroupIcon` | No | Phosphor icon name for docs sidebar group (e.g., "Rocket", "Book", "PuzzlePiece"). Icon appears left of the group title. See [Phosphor Icons](https://phosphoricons.com) for available icons. | **Hide pages from navigation:** Set `showInNav: false` to keep a page published and accessible via direct URL, but hidden from the navigation menu. Pages with `showInNav: false` remain searchable and available via API endpoints. Useful for pages you want to link directly but not show in the main nav. diff --git a/public/raw/setup-guide.md b/public/raw/setup-guide.md index b18932e..35c4e28 100644 --- a/public/raw/setup-guide.md +++ b/public/raw/setup-guide.md @@ -358,6 +358,7 @@ Your markdown content here... | `docsSectionGroup` | No | Group name for docs sidebar. Posts with the same group name appear together. | | `docsSectionOrder` | No | Order within docs group. Lower numbers appear first within the group. | | `docsSectionGroupOrder` | No | Order of the group in docs sidebar. Lower numbers make the group appear first. Groups without this field sort alphabetically. | +| `docsSectionGroupIcon` | No | Phosphor icon name for docs sidebar group (e.g., "Rocket", "Book", "PuzzlePiece"). Icon appears left of the group title. See [Phosphor Icons](https://phosphoricons.com) for available icons. | ### How Frontmatter Works diff --git a/scripts/sync-posts.ts b/scripts/sync-posts.ts index 5c108a0..9e5489b 100644 --- a/scripts/sync-posts.ts +++ b/scripts/sync-posts.ts @@ -50,6 +50,7 @@ interface PostFrontmatter { docsSectionGroup?: string; // Sidebar group name in docs docsSectionOrder?: number; // Order within group (lower = first) docsSectionGroupOrder?: number; // Order of group itself (lower = first) + docsSectionGroupIcon?: string; // Phosphor icon name for sidebar group docsLanding?: boolean; // Use as /docs landing page } @@ -83,6 +84,7 @@ interface ParsedPost { docsSectionGroup?: string; // Sidebar group name in docs docsSectionOrder?: number; // Order within group (lower = first) docsSectionGroupOrder?: number; // Order of group itself (lower = first) + docsSectionGroupIcon?: string; // Phosphor icon name for sidebar group docsLanding?: boolean; // Use as /docs landing page } @@ -113,6 +115,7 @@ interface PageFrontmatter { docsSectionGroup?: string; // Sidebar group name in docs docsSectionOrder?: number; // Order within group (lower = first) docsSectionGroupOrder?: number; // Order of group itself (lower = first) + docsSectionGroupIcon?: string; // Phosphor icon name for sidebar group docsLanding?: boolean; // Use as /docs landing page } @@ -143,6 +146,7 @@ interface ParsedPage { docsSectionGroup?: string; // Sidebar group name in docs docsSectionOrder?: number; // Order within group (lower = first) docsSectionGroupOrder?: number; // Order of group itself (lower = first) + docsSectionGroupIcon?: string; // Phosphor icon name for sidebar group docsLanding?: boolean; // Use as /docs landing page } @@ -198,6 +202,7 @@ function parseMarkdownFile(filePath: string): ParsedPost | null { docsSectionGroup: frontmatter.docsSectionGroup, // Sidebar group name docsSectionOrder: frontmatter.docsSectionOrder, // Order within group docsSectionGroupOrder: frontmatter.docsSectionGroupOrder, // Order of group itself + docsSectionGroupIcon: frontmatter.docsSectionGroupIcon, // Phosphor icon name for sidebar group docsLanding: frontmatter.docsLanding, // Use as docs landing page }; } catch (error) { @@ -263,6 +268,7 @@ function parsePageFile(filePath: string): ParsedPage | null { docsSectionGroup: frontmatter.docsSectionGroup, // Sidebar group name docsSectionOrder: frontmatter.docsSectionOrder, // Order within group docsSectionGroupOrder: frontmatter.docsSectionGroupOrder, // Order of group itself + docsSectionGroupIcon: frontmatter.docsSectionGroupIcon, // Phosphor icon name for sidebar group docsLanding: frontmatter.docsLanding, // Use as docs landing page }; } catch (error) { diff --git a/src/components/DocsSidebar.tsx b/src/components/DocsSidebar.tsx index 08c4963..80bd6c9 100644 --- a/src/components/DocsSidebar.tsx +++ b/src/components/DocsSidebar.tsx @@ -4,6 +4,123 @@ import { Link, useLocation } from "react-router-dom"; import { ChevronRight } from "lucide-react"; import { useState, useEffect, useMemo } from "react"; import siteConfig from "../config/siteConfig"; +import { + House, + Book, + Gear, + Folder, + Code, + FileText, + Question, + Lightbulb, + Rocket, + Star, + Heart, + Bell, + Calendar, + User, + ArrowRight, + Check, + Warning, + Info, + Lightning, + Database, + Globe, + Lock, + Key, + Shield, + Terminal, + Package, + PuzzlePiece, + Flag, + Target, + Compass, + MapPin, + Bookmark, + Tag, + Hash, + Link as LinkIcon, + At, + Play, + Pause, + Plus, + Minus, + X, + List, + MagnifyingGlass, + FunnelSimple, + SortAscending, + Download, + Upload, + Share, + Copy, + Clipboard, + PencilSimple, + Trash, + Archive, + Eye, + EyeClosed, + type Icon, +} from "@phosphor-icons/react"; + +// Map of supported Phosphor icon names to components +const docsSectionIcons: Record = { + House, + Book, + Gear, + Folder, + Code, + FileText, + Question, + Lightbulb, + Rocket, + Star, + Heart, + Bell, + Calendar, + User, + ArrowRight, + Check, + Warning, + Info, + Lightning, + Database, + Globe, + Lock, + Key, + Shield, + Terminal, + Package, + PuzzlePiece, + Flag, + Target, + Compass, + MapPin, + Bookmark, + Tag, + Hash, + Link: LinkIcon, + At, + Play, + Pause, + Plus, + Minus, + X, + List, + MagnifyingGlass, + FunnelSimple, + SortAscending, + Download, + Upload, + Share, + Copy, + Clipboard, + PencilSimple, + Trash, + Archive, + Eye, + EyeClosed, +}; // Docs item from query interface DocsItem { @@ -13,12 +130,14 @@ interface DocsItem { docsSectionGroup?: string; docsSectionOrder?: number; docsSectionGroupOrder?: number; + docsSectionGroupIcon?: string; } // Grouped docs structure interface DocsGroup { name: string; items: DocsItem[]; + icon?: string; } interface DocsSidebarProps { @@ -86,7 +205,9 @@ export default function DocsSidebar({ currentSlug, isMobile }: DocsSidebarProps) for (const name of sortedGroupNames) { const items = groupMap.get(name)!; items.sort(sortItems); - result.push({ name, items }); + // Get the first icon found in the group (allows any item to define the group icon) + const icon = items.find(i => i.docsSectionGroupIcon)?.docsSectionGroupIcon; + result.push({ name, items, icon }); } // Add ungrouped items at the end if any @@ -186,6 +307,12 @@ export default function DocsSidebar({ currentSlug, isMobile }: DocsSidebarProps) onClick={() => toggleGroup(group.name)} type="button" > + {group.icon && docsSectionIcons[group.icon] && ( + (() => { + const IconComponent = docsSectionIcons[group.icon]; + return ; + })() + )} {group.name} diff --git a/src/styles/global.css b/src/styles/global.css index 8db8e70..f13a3d8 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -12213,7 +12213,21 @@ body { color: var(--text-muted); } -.docs-sidebar-group-title.expanded svg { +/* Phosphor icon for group - no rotation */ +.docs-sidebar-group-title .docs-sidebar-group-icon { + width: 16px; + height: 16px; + transform: none !important; + color: var(--text-secondary); +} + +.docs-sidebar-group-title.expanded .docs-sidebar-group-icon { + transform: none !important; + color: var(--text-primary); +} + +/* Only rotate the chevron, not the group icon */ +.docs-sidebar-group-title.expanded svg:not(.docs-sidebar-group-icon) { transform: rotate(90deg); color: var(--text-primary); }