mirror of
https://github.com/waynesutton/markdown-site.git
synced 2026-01-12 04:09:14 +00:00
docs: update changelog page with v1.24.3 and v1.24.4 releases
- Added v1.24.4 entry documenting showInNav field and hardcodedNavItems configuration - Added v1.24.3 entry documenting inner page logo configuration - Includes configuration examples and updated file lists - Maintains consistent format with existing changelog entries
This commit is contained in:
11
TASK.md
11
TASK.md
@@ -15,7 +15,7 @@
|
||||
|
||||
## Current Status
|
||||
|
||||
v1.24.2 deployed. Mobile menu redesigned with sidebar integration and typography standardization.
|
||||
v1.24.4 deployed. Added `showInNav` field for pages and hardcoded navigation items configuration for React routes.
|
||||
|
||||
## Completed
|
||||
|
||||
@@ -172,6 +172,15 @@ v1.24.2 deployed. Mobile menu redesigned with sidebar integration and typography
|
||||
- [x] SidebarContext created to share sidebar data between components
|
||||
- [x] Mobile menu typography standardized with CSS variables
|
||||
- [x] Font-family standardized using inherit for consistency
|
||||
- [x] `showInNav` field for pages to control navigation visibility
|
||||
- [x] Pages can be published but hidden from navigation menu
|
||||
- [x] Defaults to `true` for backwards compatibility
|
||||
- [x] Pages with `showInNav: false` remain accessible via direct URL, searchable, and available via API
|
||||
- [x] Hardcoded navigation items configuration in siteConfig.ts
|
||||
- [x] Add React route pages (like /stats, /write) to navigation via hardcodedNavItems
|
||||
- [x] Configure navigation order, title, and visibility per route
|
||||
- [x] Navigation combines Blog link, hardcoded nav items, and markdown pages
|
||||
- [x] All nav items sorted by order field (lower = first)
|
||||
|
||||
## Deployment Steps
|
||||
|
||||
|
||||
55
changelog.md
55
changelog.md
@@ -4,6 +4,61 @@ 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.24.4] - 2025-12-23
|
||||
|
||||
### Added
|
||||
|
||||
- `showInNav` field for pages to control navigation visibility
|
||||
- Pages can be published and accessible but hidden from navigation menu
|
||||
- Set `showInNav: false` in page frontmatter to hide from nav
|
||||
- Defaults to `true` for backwards compatibility (all existing pages show in nav)
|
||||
- Pages with `showInNav: false` remain:
|
||||
- Published and accessible via direct URL
|
||||
- Searchable via search indexes
|
||||
- Available via API endpoints
|
||||
- Just hidden from the navigation menu
|
||||
- Matches the pattern used for `blogPage.showInNav` in siteConfig.ts
|
||||
- Hardcoded navigation items configuration for React routes
|
||||
- Add React route pages (like `/stats`, `/write`) to navigation via `siteConfig.hardcodedNavItems`
|
||||
- Configure navigation order, title, and visibility per route
|
||||
- Set `showInNav: false` to hide from nav while keeping route accessible
|
||||
- Navigation combines Blog link, hardcoded nav items, and markdown pages
|
||||
- All nav items sorted by `order` field (lower = first)
|
||||
- Example: Configure `/stats` and `/write` routes in `siteConfig.ts`
|
||||
|
||||
### Technical
|
||||
|
||||
- Updated `convex/schema.ts`: Added optional `showInNav` field to pages table
|
||||
- Updated `convex/pages.ts`: `getAllPages` query filters out pages where `showInNav === false`
|
||||
- Updated `scripts/sync-posts.ts`: Parses `showInNav` from page frontmatter
|
||||
- Updated `src/pages/Write.tsx`: Added `showInNav` field to page template and PAGE_FIELDS reference
|
||||
- Updated `src/config/siteConfig.ts`: Added `HardcodedNavItem` interface and `hardcodedNavItems` config array
|
||||
- Updated `src/components/Layout.tsx`: Reads `hardcodedNavItems` from siteConfig and combines with Blog link and pages
|
||||
|
||||
### Documentation
|
||||
|
||||
- Updated `content/pages/docs.md`: Added `showInNav` to static pages frontmatter table
|
||||
- Updated `content/blog/setup-guide.md`: Added `showInNav` to static pages frontmatter table
|
||||
|
||||
## [1.24.3] - 2025-12-23
|
||||
|
||||
### Added
|
||||
|
||||
- Inner page logo configuration
|
||||
- Logo displays in header on blog page, individual posts, and static pages
|
||||
- Desktop: logo positioned on the left (before back button)
|
||||
- Mobile: logo positioned on the right (smaller size for compact header)
|
||||
- Configurable via `siteConfig.innerPageLogo.enabled` and `siteConfig.innerPageLogo.size`
|
||||
- Does not affect homepage logo (controlled separately)
|
||||
- Logo links to homepage when clicked
|
||||
|
||||
### Technical
|
||||
|
||||
- Updated `src/config/siteConfig.ts`: Added `InnerPageLogoConfig` interface and `innerPageLogo` config option
|
||||
- Updated `src/pages/Blog.tsx`: Added logo to header navigation
|
||||
- Updated `src/pages/Post.tsx`: Added logo to header navigation for both posts and pages
|
||||
- Updated `src/styles/global.css`: Added CSS for desktop (left) and mobile (right) logo positioning with responsive sizing
|
||||
|
||||
## [1.24.2] - 2025-12-23
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -570,10 +570,12 @@ To use a different letter or icon, edit the SVG directly or replace the file.
|
||||
|
||||
### Change the Site Logo
|
||||
|
||||
The logo appears on the homepage. Edit `src/pages/Home.tsx`:
|
||||
The site uses two logo configurations:
|
||||
|
||||
**Homepage logo:** Edit `src/config/siteConfig.ts`:
|
||||
|
||||
```typescript
|
||||
const siteConfig = {
|
||||
export default {
|
||||
logo: "/images/logo.svg", // Set to null to hide the logo
|
||||
// ...
|
||||
};
|
||||
@@ -581,6 +583,17 @@ const siteConfig = {
|
||||
|
||||
Replace `public/images/logo.svg` with your own logo file. Recommended: SVG format, 512x512 pixels.
|
||||
|
||||
**Inner page logo:** Shows on blog page, individual posts, and static pages. Configure in `src/config/siteConfig.ts`:
|
||||
|
||||
```typescript
|
||||
innerPageLogo: {
|
||||
enabled: true, // Set to false to hide logo on inner pages
|
||||
size: 28, // Logo height in pixels (keeps aspect ratio)
|
||||
},
|
||||
```
|
||||
|
||||
The inner page logo appears in the top left corner on desktop and top right on mobile. It uses the same logo file as the homepage logo. Set `enabled: false` to hide it on inner pages while keeping the homepage logo.
|
||||
|
||||
### Change the Default Open Graph Image
|
||||
|
||||
The default OG image is used when a post does not have an `image` field in its frontmatter. Replace `public/images/og-default.svg` with your own image.
|
||||
@@ -601,6 +614,7 @@ Edit `src/config/siteConfig.ts` to customize:
|
||||
export default {
|
||||
name: "Your Name",
|
||||
title: "Your Title",
|
||||
logo: "/images/logo.svg", // null to hide homepage logo
|
||||
intro: "Your introduction...",
|
||||
bio: "Your bio...",
|
||||
|
||||
@@ -611,7 +625,28 @@ export default {
|
||||
title: "Blog", // Nav link and page title
|
||||
order: 0, // Nav order (lower = first)
|
||||
},
|
||||
displayOnHomepage: true, // Show posts on homepage
|
||||
|
||||
// Hardcoded navigation items for React routes
|
||||
hardcodedNavItems: [
|
||||
{
|
||||
slug: "stats",
|
||||
title: "Stats",
|
||||
order: 10,
|
||||
showInNav: true, // Set to false to hide from nav
|
||||
},
|
||||
{
|
||||
slug: "write",
|
||||
title: "Write",
|
||||
order: 20,
|
||||
showInNav: true,
|
||||
},
|
||||
],
|
||||
|
||||
// Inner page logo configuration
|
||||
innerPageLogo: {
|
||||
enabled: true, // Set to false to hide logo on inner pages
|
||||
size: 28, // Logo height in pixels (keeps aspect ratio)
|
||||
},
|
||||
|
||||
// Featured section options
|
||||
featuredViewMode: "list", // 'list' or 'cards'
|
||||
@@ -827,6 +862,39 @@ Cards display post thumbnails (from `image` frontmatter field), titles, excerpts
|
||||
|
||||
**View preference:** User's view mode choice is saved to localStorage and persists across page visits.
|
||||
|
||||
### Hardcoded Navigation Items
|
||||
|
||||
Add React route pages (like `/stats`, `/write`) to the navigation menu via `siteConfig.ts`. These pages are React components, not markdown files.
|
||||
|
||||
Configure in `src/config/siteConfig.ts`:
|
||||
|
||||
```typescript
|
||||
hardcodedNavItems: [
|
||||
{
|
||||
slug: "stats",
|
||||
title: "Stats",
|
||||
order: 10,
|
||||
showInNav: true, // Set to false to hide from nav
|
||||
},
|
||||
{
|
||||
slug: "write",
|
||||
title: "Write",
|
||||
order: 20,
|
||||
showInNav: true,
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
Navigation combines three sources in this order:
|
||||
|
||||
1. Blog link (if `blogPage.enabled` and `blogPage.showInNav` are true)
|
||||
2. Hardcoded nav items (from `hardcodedNavItems` array)
|
||||
3. Markdown pages (from `content/pages/` with `showInNav: true`)
|
||||
|
||||
All items sort by `order` field (lower numbers first), then alphabetically by title.
|
||||
|
||||
**Hide from navigation:** Set `showInNav: false` to keep a route accessible but hidden from the nav menu. The route still works at its URL, just won't appear in navigation links.
|
||||
|
||||
### Scroll-to-top button
|
||||
|
||||
A scroll-to-top button appears after scrolling down on posts and pages. Configure it in `src/components/Layout.tsx`:
|
||||
@@ -922,6 +990,7 @@ Your page content here...
|
||||
| `slug` | Yes | URL path (e.g., `/about`) |
|
||||
| `published` | Yes | Set `true` to show |
|
||||
| `order` | No | Display order (lower = first) |
|
||||
| `showInNav` | No | Show in navigation menu (default: `true`) |
|
||||
| `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 |
|
||||
@@ -930,6 +999,8 @@ Your page content here...
|
||||
|
||||
Pages appear automatically in the navigation when published.
|
||||
|
||||
**Hide pages from navigation:** Set `showInNav: false` in page frontmatter to keep a page published and accessible via direct URL, but hidden from the navigation menu. Useful for pages like `/projects` that you want to link directly but not show in the main nav. Pages with `showInNav: false` remain searchable and available via API endpoints.
|
||||
|
||||
**Sidebar layout:** Add `layout: "sidebar"` to any post or page frontmatter to enable a docs-style layout with a table of contents sidebar. The sidebar extracts headings (H1, H2, H3) automatically and provides smooth scroll navigation. Only appears if headings exist in the content.
|
||||
|
||||
### Update SEO Meta Tags
|
||||
|
||||
@@ -8,6 +8,79 @@ layout: "sidebar"
|
||||
|
||||
All notable changes to this project.
|
||||
|
||||
## v1.24.4
|
||||
|
||||
Released December 23, 2025
|
||||
|
||||
**Navigation visibility control and hardcoded nav items**
|
||||
|
||||
- `showInNav` field for pages to control navigation visibility
|
||||
- Pages can be published and accessible but hidden from navigation menu
|
||||
- Set `showInNav: false` in page frontmatter to hide from nav
|
||||
- Defaults to `true` for backwards compatibility (all existing pages show in nav)
|
||||
- Pages with `showInNav: false` remain:
|
||||
- Published and accessible via direct URL
|
||||
- Searchable via search indexes
|
||||
- Available via API endpoints
|
||||
- Just hidden from the navigation menu
|
||||
- Matches the pattern used for `blogPage.showInNav` in siteConfig.ts
|
||||
|
||||
- Hardcoded navigation items configuration for React routes
|
||||
- Add React route pages (like `/stats`, `/write`) to navigation via `siteConfig.hardcodedNavItems`
|
||||
- Configure navigation order, title, and visibility per route
|
||||
- Set `showInNav: false` to hide from nav while keeping route accessible
|
||||
- Navigation combines Blog link, hardcoded nav items, and markdown pages
|
||||
- All nav items sorted by `order` field (lower = first)
|
||||
|
||||
Example configuration:
|
||||
|
||||
```typescript
|
||||
// src/config/siteConfig.ts
|
||||
hardcodedNavItems: [
|
||||
{
|
||||
slug: "stats",
|
||||
title: "Stats",
|
||||
order: 10,
|
||||
showInNav: true,
|
||||
},
|
||||
{
|
||||
slug: "write",
|
||||
title: "Write",
|
||||
order: 20,
|
||||
showInNav: true,
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
Updated files: `convex/schema.ts`, `convex/pages.ts`, `scripts/sync-posts.ts`, `src/pages/Write.tsx`, `src/config/siteConfig.ts`, `src/components/Layout.tsx`
|
||||
|
||||
Documentation updated: `content/pages/docs.md`, `content/blog/setup-guide.md`
|
||||
|
||||
## v1.24.3
|
||||
|
||||
Released December 23, 2025
|
||||
|
||||
**Inner page logo configuration**
|
||||
|
||||
- Logo displays in header on blog page, individual posts, and static pages
|
||||
- Desktop: logo positioned on the left (before back button)
|
||||
- Mobile: logo positioned on the right (smaller size for compact header)
|
||||
- Configurable via `siteConfig.innerPageLogo.enabled` and `siteConfig.innerPageLogo.size`
|
||||
- Does not affect homepage logo (controlled separately)
|
||||
- Logo links to homepage when clicked
|
||||
|
||||
Configuration:
|
||||
|
||||
```typescript
|
||||
// src/config/siteConfig.ts
|
||||
innerPageLogo: {
|
||||
enabled: true, // Set to false to hide logo on inner pages
|
||||
size: 28, // Logo height in pixels (keeps aspect ratio)
|
||||
},
|
||||
```
|
||||
|
||||
Updated files: `src/config/siteConfig.ts`, `src/pages/Blog.tsx`, `src/pages/Post.tsx`, `src/styles/global.css`
|
||||
|
||||
## v1.24.2
|
||||
|
||||
Released December 23, 2025
|
||||
|
||||
@@ -121,6 +121,7 @@ Content here...
|
||||
| `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 |
|
||||
| `featured` | No | `true` to show in featured section |
|
||||
@@ -129,6 +130,8 @@ Content here...
|
||||
| `authorImage` | No | Round author avatar image URL |
|
||||
| `layout` | No | Set to `"sidebar"` for docs-style layout with TOC |
|
||||
|
||||
**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.
|
||||
|
||||
### Sidebar layout
|
||||
|
||||
Posts and pages can use a docs-style layout with a table of contents sidebar. Add `layout: "sidebar"` to the frontmatter:
|
||||
@@ -320,7 +323,7 @@ Edit `src/config/siteConfig.ts`:
|
||||
export default {
|
||||
name: "Site Name",
|
||||
title: "Tagline",
|
||||
logo: "/images/logo.svg", // null to hide
|
||||
logo: "/images/logo.svg", // null to hide homepage logo
|
||||
intro: "Introduction text...",
|
||||
bio: "Bio text...",
|
||||
|
||||
@@ -331,7 +334,28 @@ export default {
|
||||
title: "Blog", // Nav link and page title
|
||||
order: 0, // Nav order (lower = first)
|
||||
},
|
||||
displayOnHomepage: true, // Show posts on homepage
|
||||
|
||||
// Hardcoded navigation items for React routes
|
||||
hardcodedNavItems: [
|
||||
{
|
||||
slug: "stats",
|
||||
title: "Stats",
|
||||
order: 10,
|
||||
showInNav: true, // Set to false to hide from nav
|
||||
},
|
||||
{
|
||||
slug: "write",
|
||||
title: "Write",
|
||||
order: 20,
|
||||
showInNav: true,
|
||||
},
|
||||
],
|
||||
|
||||
// Inner page logo configuration
|
||||
innerPageLogo: {
|
||||
enabled: true, // Set to false to hide logo on inner pages
|
||||
size: 28, // Logo height in pixels (keeps aspect ratio)
|
||||
},
|
||||
|
||||
// Featured section
|
||||
featuredViewMode: "list", // 'list' or 'cards'
|
||||
@@ -355,6 +379,21 @@ export default {
|
||||
};
|
||||
```
|
||||
|
||||
**Logo configuration:**
|
||||
|
||||
- `logo`: Homepage logo path (set to `null` to hide). Uses `public/images/logo.svg` by default.
|
||||
- `innerPageLogo`: Logo shown on blog page, posts, and static pages. Desktop: top left. Mobile: top right. Set `enabled: false` to hide on inner pages while keeping homepage logo.
|
||||
|
||||
**Navigation structure:**
|
||||
|
||||
Navigation combines three sources sorted by `order`:
|
||||
|
||||
1. Blog link (if `blogPage.enabled` and `blogPage.showInNav` are true)
|
||||
2. Hardcoded nav items (React routes from `hardcodedNavItems`)
|
||||
3. Markdown pages (from `content/pages/` with `showInNav: true`)
|
||||
|
||||
All items sort by `order` (lower first), then alphabetically by title.
|
||||
|
||||
### Featured items
|
||||
|
||||
Posts and pages appear in the featured section when marked with `featured: true` in frontmatter.
|
||||
@@ -604,6 +643,11 @@ Mobile sizes defined in `@media (max-width: 768px)` block.
|
||||
|
||||
The `npm run sync` command only syncs markdown text content. Images are deployed when Netlify builds your site.
|
||||
|
||||
**Logo options:**
|
||||
|
||||
- **Homepage logo:** Configured via `logo` in `siteConfig.ts`. Set to `null` to hide.
|
||||
- **Inner page logo:** Configured via `innerPageLogo` in `siteConfig.ts`. Shows on blog page, posts, and static pages. Desktop: top left corner. Mobile: top right corner (smaller). Set `enabled: false` to hide on inner pages while keeping homepage logo.
|
||||
|
||||
## Search
|
||||
|
||||
Press `Command+K` (Mac) or `Ctrl+K` (Windows/Linux) to open the search modal. Click the search icon in the nav or use the keyboard shortcut.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
title: "Projects"
|
||||
slug: "projects"
|
||||
published: true
|
||||
showInNav: false
|
||||
order: 3
|
||||
---
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ export const getAllPages = query({
|
||||
title: v.string(),
|
||||
published: v.boolean(),
|
||||
order: v.optional(v.number()),
|
||||
showInNav: v.optional(v.boolean()),
|
||||
excerpt: v.optional(v.string()),
|
||||
image: v.optional(v.string()),
|
||||
featured: v.optional(v.boolean()),
|
||||
@@ -26,8 +27,14 @@ export const getAllPages = query({
|
||||
.withIndex("by_published", (q) => q.eq("published", true))
|
||||
.collect();
|
||||
|
||||
// Filter out pages where showInNav is explicitly false
|
||||
// Default to true for backwards compatibility (undefined/null = show in nav)
|
||||
const visiblePages = pages.filter(
|
||||
(page) => page.showInNav !== false,
|
||||
);
|
||||
|
||||
// Sort by order (lower numbers first), then by title
|
||||
const sortedPages = pages.sort((a, b) => {
|
||||
const sortedPages = visiblePages.sort((a, b) => {
|
||||
const orderA = a.order ?? 999;
|
||||
const orderB = b.order ?? 999;
|
||||
if (orderA !== orderB) return orderA - orderB;
|
||||
@@ -40,6 +47,7 @@ export const getAllPages = query({
|
||||
title: page.title,
|
||||
published: page.published,
|
||||
order: page.order,
|
||||
showInNav: page.showInNav,
|
||||
excerpt: page.excerpt,
|
||||
image: page.image,
|
||||
featured: page.featured,
|
||||
@@ -103,6 +111,7 @@ export const getPageBySlug = query({
|
||||
content: v.string(),
|
||||
published: v.boolean(),
|
||||
order: v.optional(v.number()),
|
||||
showInNav: v.optional(v.boolean()),
|
||||
excerpt: v.optional(v.string()),
|
||||
image: v.optional(v.string()),
|
||||
featured: v.optional(v.boolean()),
|
||||
@@ -130,6 +139,7 @@ export const getPageBySlug = query({
|
||||
content: page.content,
|
||||
published: page.published,
|
||||
order: page.order,
|
||||
showInNav: page.showInNav,
|
||||
excerpt: page.excerpt,
|
||||
image: page.image,
|
||||
featured: page.featured,
|
||||
@@ -151,6 +161,7 @@ export const syncPagesPublic = mutation({
|
||||
content: v.string(),
|
||||
published: v.boolean(),
|
||||
order: v.optional(v.number()),
|
||||
showInNav: v.optional(v.boolean()),
|
||||
excerpt: v.optional(v.string()),
|
||||
image: v.optional(v.string()),
|
||||
featured: v.optional(v.boolean()),
|
||||
@@ -189,6 +200,7 @@ export const syncPagesPublic = mutation({
|
||||
content: page.content,
|
||||
published: page.published,
|
||||
order: page.order,
|
||||
showInNav: page.showInNav,
|
||||
excerpt: page.excerpt,
|
||||
image: page.image,
|
||||
featured: page.featured,
|
||||
|
||||
@@ -41,6 +41,7 @@ export default defineSchema({
|
||||
content: v.string(),
|
||||
published: v.boolean(),
|
||||
order: v.optional(v.number()), // Display order in nav
|
||||
showInNav: v.optional(v.boolean()), // Show in navigation menu (default: true)
|
||||
excerpt: v.optional(v.string()), // Short excerpt for card view
|
||||
image: v.optional(v.string()), // Thumbnail/OG image URL for featured cards
|
||||
featured: v.optional(v.boolean()), // Show in featured section
|
||||
|
||||
11
files.md
11
files.md
@@ -33,7 +33,7 @@ A brief description of each file in the codebase.
|
||||
|
||||
| File | Description |
|
||||
| --------------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| `siteConfig.ts` | Centralized site configuration (name, logo, blog page, posts display, GitHub contributions, nav order) |
|
||||
| `siteConfig.ts` | Centralized site configuration (name, logo, blog page, posts display, GitHub contributions, nav order, inner page logo settings, hardcoded navigation items for React routes) |
|
||||
|
||||
### Pages (`src/pages/`)
|
||||
|
||||
@@ -49,7 +49,7 @@ A brief description of each file in the codebase.
|
||||
|
||||
| File | Description |
|
||||
| ------------------------- | ---------------------------------------------------------- |
|
||||
| `Layout.tsx` | Page wrapper with search button, theme toggle, mobile menu (left-aligned on mobile), and scroll-to-top |
|
||||
| `Layout.tsx` | Page wrapper with search button, theme toggle, mobile menu (left-aligned on mobile), and scroll-to-top. Combines Blog link, hardcoded nav items, and markdown pages for navigation |
|
||||
| `ThemeToggle.tsx` | Theme switcher (dark/light/tan/cloud) |
|
||||
| `PostList.tsx` | Year-grouped blog post list or card grid (supports list/cards view modes) |
|
||||
| `BlogPost.tsx` | Markdown renderer with syntax highlighting and collapsible sections (details/summary) |
|
||||
@@ -149,10 +149,11 @@ Markdown files for static pages like About, Projects, Contact, Changelog.
|
||||
| `slug` | URL path for the page |
|
||||
| `published` | Whether page is public |
|
||||
| `order` | Display order in navigation (lower first) |
|
||||
| `showInNav` | Show in navigation menu (default: true) |
|
||||
| `excerpt` | Short excerpt for card view (optional) |
|
||||
| `featured` | Show in featured section (optional) |
|
||||
| `featuredOrder` | Order in featured section (optional) |
|
||||
| `authorName` | Author display name (optional) |
|
||||
| `featured` | Show in featured section (optional) |
|
||||
| `featuredOrder` | Order in featured section (optional) |
|
||||
| `authorName` | Author display name (optional) |
|
||||
| `authorImage` | Round author avatar image URL (optional) |
|
||||
|
||||
## Scripts (`scripts/`)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
Type: page
|
||||
Date: 2025-12-23
|
||||
Date: 2025-12-24
|
||||
---
|
||||
|
||||
An open-source publishing framework for AI agents and developers. Write markdown, sync from the terminal. Your content is instantly available to browsers, LLMs, and AI agents. Built on Convex and Netlify.
|
||||
|
||||
@@ -2,11 +2,84 @@
|
||||
|
||||
---
|
||||
Type: page
|
||||
Date: 2025-12-23
|
||||
Date: 2025-12-24
|
||||
---
|
||||
|
||||
All notable changes to this project.
|
||||
|
||||
## v1.24.4
|
||||
|
||||
Released December 23, 2025
|
||||
|
||||
**Navigation visibility control and hardcoded nav items**
|
||||
|
||||
- `showInNav` field for pages to control navigation visibility
|
||||
- Pages can be published and accessible but hidden from navigation menu
|
||||
- Set `showInNav: false` in page frontmatter to hide from nav
|
||||
- Defaults to `true` for backwards compatibility (all existing pages show in nav)
|
||||
- Pages with `showInNav: false` remain:
|
||||
- Published and accessible via direct URL
|
||||
- Searchable via search indexes
|
||||
- Available via API endpoints
|
||||
- Just hidden from the navigation menu
|
||||
- Matches the pattern used for `blogPage.showInNav` in siteConfig.ts
|
||||
|
||||
- Hardcoded navigation items configuration for React routes
|
||||
- Add React route pages (like `/stats`, `/write`) to navigation via `siteConfig.hardcodedNavItems`
|
||||
- Configure navigation order, title, and visibility per route
|
||||
- Set `showInNav: false` to hide from nav while keeping route accessible
|
||||
- Navigation combines Blog link, hardcoded nav items, and markdown pages
|
||||
- All nav items sorted by `order` field (lower = first)
|
||||
|
||||
Example configuration:
|
||||
|
||||
```typescript
|
||||
// src/config/siteConfig.ts
|
||||
hardcodedNavItems: [
|
||||
{
|
||||
slug: "stats",
|
||||
title: "Stats",
|
||||
order: 10,
|
||||
showInNav: true,
|
||||
},
|
||||
{
|
||||
slug: "write",
|
||||
title: "Write",
|
||||
order: 20,
|
||||
showInNav: true,
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
Updated files: `convex/schema.ts`, `convex/pages.ts`, `scripts/sync-posts.ts`, `src/pages/Write.tsx`, `src/config/siteConfig.ts`, `src/components/Layout.tsx`
|
||||
|
||||
Documentation updated: `content/pages/docs.md`, `content/blog/setup-guide.md`
|
||||
|
||||
## v1.24.3
|
||||
|
||||
Released December 23, 2025
|
||||
|
||||
**Inner page logo configuration**
|
||||
|
||||
- Logo displays in header on blog page, individual posts, and static pages
|
||||
- Desktop: logo positioned on the left (before back button)
|
||||
- Mobile: logo positioned on the right (smaller size for compact header)
|
||||
- Configurable via `siteConfig.innerPageLogo.enabled` and `siteConfig.innerPageLogo.size`
|
||||
- Does not affect homepage logo (controlled separately)
|
||||
- Logo links to homepage when clicked
|
||||
|
||||
Configuration:
|
||||
|
||||
```typescript
|
||||
// src/config/siteConfig.ts
|
||||
innerPageLogo: {
|
||||
enabled: true, // Set to false to hide logo on inner pages
|
||||
size: 28, // Logo height in pixels (keeps aspect ratio)
|
||||
},
|
||||
```
|
||||
|
||||
Updated files: `src/config/siteConfig.ts`, `src/pages/Blog.tsx`, `src/pages/Post.tsx`, `src/styles/global.css`
|
||||
|
||||
## v1.24.2
|
||||
|
||||
Released December 23, 2025
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
Type: page
|
||||
Date: 2025-12-23
|
||||
Date: 2025-12-24
|
||||
---
|
||||
|
||||
You found the contact page. Nice
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
Type: page
|
||||
Date: 2025-12-23
|
||||
Date: 2025-12-24
|
||||
---
|
||||
|
||||
Reference documentation for setting up, customizing, and deploying this markdown framework.
|
||||
@@ -120,6 +120,7 @@ Content here...
|
||||
| `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 |
|
||||
| `featured` | No | `true` to show in featured section |
|
||||
@@ -128,6 +129,8 @@ Content here...
|
||||
| `authorImage` | No | Round author avatar image URL |
|
||||
| `layout` | No | Set to `"sidebar"` for docs-style layout with TOC |
|
||||
|
||||
**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.
|
||||
|
||||
### Sidebar layout
|
||||
|
||||
Posts and pages can use a docs-style layout with a table of contents sidebar. Add `layout: "sidebar"` to the frontmatter:
|
||||
@@ -319,7 +322,7 @@ Edit `src/config/siteConfig.ts`:
|
||||
export default {
|
||||
name: "Site Name",
|
||||
title: "Tagline",
|
||||
logo: "/images/logo.svg", // null to hide
|
||||
logo: "/images/logo.svg", // null to hide homepage logo
|
||||
intro: "Introduction text...",
|
||||
bio: "Bio text...",
|
||||
|
||||
@@ -330,7 +333,28 @@ export default {
|
||||
title: "Blog", // Nav link and page title
|
||||
order: 0, // Nav order (lower = first)
|
||||
},
|
||||
displayOnHomepage: true, // Show posts on homepage
|
||||
|
||||
// Hardcoded navigation items for React routes
|
||||
hardcodedNavItems: [
|
||||
{
|
||||
slug: "stats",
|
||||
title: "Stats",
|
||||
order: 10,
|
||||
showInNav: true, // Set to false to hide from nav
|
||||
},
|
||||
{
|
||||
slug: "write",
|
||||
title: "Write",
|
||||
order: 20,
|
||||
showInNav: true,
|
||||
},
|
||||
],
|
||||
|
||||
// Inner page logo configuration
|
||||
innerPageLogo: {
|
||||
enabled: true, // Set to false to hide logo on inner pages
|
||||
size: 28, // Logo height in pixels (keeps aspect ratio)
|
||||
},
|
||||
|
||||
// Featured section
|
||||
featuredViewMode: "list", // 'list' or 'cards'
|
||||
@@ -354,6 +378,21 @@ export default {
|
||||
};
|
||||
```
|
||||
|
||||
**Logo configuration:**
|
||||
|
||||
- `logo`: Homepage logo path (set to `null` to hide). Uses `public/images/logo.svg` by default.
|
||||
- `innerPageLogo`: Logo shown on blog page, posts, and static pages. Desktop: top left. Mobile: top right. Set `enabled: false` to hide on inner pages while keeping homepage logo.
|
||||
|
||||
**Navigation structure:**
|
||||
|
||||
Navigation combines three sources sorted by `order`:
|
||||
|
||||
1. Blog link (if `blogPage.enabled` and `blogPage.showInNav` are true)
|
||||
2. Hardcoded nav items (React routes from `hardcodedNavItems`)
|
||||
3. Markdown pages (from `content/pages/` with `showInNav: true`)
|
||||
|
||||
All items sort by `order` (lower first), then alphabetically by title.
|
||||
|
||||
### Featured items
|
||||
|
||||
Posts and pages appear in the featured section when marked with `featured: true` in frontmatter.
|
||||
@@ -603,6 +642,11 @@ Mobile sizes defined in `@media (max-width: 768px)` block.
|
||||
|
||||
The `npm run sync` command only syncs markdown text content. Images are deployed when Netlify builds your site.
|
||||
|
||||
**Logo options:**
|
||||
|
||||
- **Homepage logo:** Configured via `logo` in `siteConfig.ts`. Set to `null` to hide.
|
||||
- **Inner page logo:** Configured via `innerPageLogo` in `siteConfig.ts`. Shows on blog page, posts, and static pages. Desktop: top left corner. Mobile: top right corner (smaller). Set `enabled: false` to hide on inner pages while keeping homepage logo.
|
||||
|
||||
## Search
|
||||
|
||||
Press `Command+K` (Mac) or `Ctrl+K` (Windows/Linux) to open the search modal. Click the search icon in the nav or use the keyboard shortcut.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
Type: page
|
||||
Date: 2025-12-23
|
||||
Date: 2025-12-24
|
||||
---
|
||||
|
||||
This markdown framework is open source and built to be extended. Here is what ships out of the box.
|
||||
|
||||
@@ -564,10 +564,12 @@ To use a different letter or icon, edit the SVG directly or replace the file.
|
||||
|
||||
### Change the Site Logo
|
||||
|
||||
The logo appears on the homepage. Edit `src/pages/Home.tsx`:
|
||||
The site uses two logo configurations:
|
||||
|
||||
**Homepage logo:** Edit `src/config/siteConfig.ts`:
|
||||
|
||||
```typescript
|
||||
const siteConfig = {
|
||||
export default {
|
||||
logo: "/images/logo.svg", // Set to null to hide the logo
|
||||
// ...
|
||||
};
|
||||
@@ -575,6 +577,17 @@ const siteConfig = {
|
||||
|
||||
Replace `public/images/logo.svg` with your own logo file. Recommended: SVG format, 512x512 pixels.
|
||||
|
||||
**Inner page logo:** Shows on blog page, individual posts, and static pages. Configure in `src/config/siteConfig.ts`:
|
||||
|
||||
```typescript
|
||||
innerPageLogo: {
|
||||
enabled: true, // Set to false to hide logo on inner pages
|
||||
size: 28, // Logo height in pixels (keeps aspect ratio)
|
||||
},
|
||||
```
|
||||
|
||||
The inner page logo appears in the top left corner on desktop and top right on mobile. It uses the same logo file as the homepage logo. Set `enabled: false` to hide it on inner pages while keeping the homepage logo.
|
||||
|
||||
### Change the Default Open Graph Image
|
||||
|
||||
The default OG image is used when a post does not have an `image` field in its frontmatter. Replace `public/images/og-default.svg` with your own image.
|
||||
@@ -595,6 +608,7 @@ Edit `src/config/siteConfig.ts` to customize:
|
||||
export default {
|
||||
name: "Your Name",
|
||||
title: "Your Title",
|
||||
logo: "/images/logo.svg", // null to hide homepage logo
|
||||
intro: "Your introduction...",
|
||||
bio: "Your bio...",
|
||||
|
||||
@@ -605,7 +619,28 @@ export default {
|
||||
title: "Blog", // Nav link and page title
|
||||
order: 0, // Nav order (lower = first)
|
||||
},
|
||||
displayOnHomepage: true, // Show posts on homepage
|
||||
|
||||
// Hardcoded navigation items for React routes
|
||||
hardcodedNavItems: [
|
||||
{
|
||||
slug: "stats",
|
||||
title: "Stats",
|
||||
order: 10,
|
||||
showInNav: true, // Set to false to hide from nav
|
||||
},
|
||||
{
|
||||
slug: "write",
|
||||
title: "Write",
|
||||
order: 20,
|
||||
showInNav: true,
|
||||
},
|
||||
],
|
||||
|
||||
// Inner page logo configuration
|
||||
innerPageLogo: {
|
||||
enabled: true, // Set to false to hide logo on inner pages
|
||||
size: 28, // Logo height in pixels (keeps aspect ratio)
|
||||
},
|
||||
|
||||
// Featured section options
|
||||
featuredViewMode: "list", // 'list' or 'cards'
|
||||
@@ -821,6 +856,39 @@ Cards display post thumbnails (from `image` frontmatter field), titles, excerpts
|
||||
|
||||
**View preference:** User's view mode choice is saved to localStorage and persists across page visits.
|
||||
|
||||
### Hardcoded Navigation Items
|
||||
|
||||
Add React route pages (like `/stats`, `/write`) to the navigation menu via `siteConfig.ts`. These pages are React components, not markdown files.
|
||||
|
||||
Configure in `src/config/siteConfig.ts`:
|
||||
|
||||
```typescript
|
||||
hardcodedNavItems: [
|
||||
{
|
||||
slug: "stats",
|
||||
title: "Stats",
|
||||
order: 10,
|
||||
showInNav: true, // Set to false to hide from nav
|
||||
},
|
||||
{
|
||||
slug: "write",
|
||||
title: "Write",
|
||||
order: 20,
|
||||
showInNav: true,
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
Navigation combines three sources in this order:
|
||||
|
||||
1. Blog link (if `blogPage.enabled` and `blogPage.showInNav` are true)
|
||||
2. Hardcoded nav items (from `hardcodedNavItems` array)
|
||||
3. Markdown pages (from `content/pages/` with `showInNav: true`)
|
||||
|
||||
All items sort by `order` field (lower numbers first), then alphabetically by title.
|
||||
|
||||
**Hide from navigation:** Set `showInNav: false` to keep a route accessible but hidden from the nav menu. The route still works at its URL, just won't appear in navigation links.
|
||||
|
||||
### Scroll-to-top button
|
||||
|
||||
A scroll-to-top button appears after scrolling down on posts and pages. Configure it in `src/components/Layout.tsx`:
|
||||
@@ -916,6 +984,7 @@ Your page content here...
|
||||
| `slug` | Yes | URL path (e.g., `/about`) |
|
||||
| `published` | Yes | Set `true` to show |
|
||||
| `order` | No | Display order (lower = first) |
|
||||
| `showInNav` | No | Show in navigation menu (default: `true`) |
|
||||
| `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 |
|
||||
@@ -924,6 +993,8 @@ Your page content here...
|
||||
|
||||
Pages appear automatically in the navigation when published.
|
||||
|
||||
**Hide pages from navigation:** Set `showInNav: false` in page frontmatter to keep a page published and accessible via direct URL, but hidden from the navigation menu. Useful for pages like `/projects` that you want to link directly but not show in the main nav. Pages with `showInNav: false` remain searchable and available via API endpoints.
|
||||
|
||||
**Sidebar layout:** Add `layout: "sidebar"` to any post or page frontmatter to enable a docs-style layout with a table of contents sidebar. The sidebar extracts headings (H1, H2, H3) automatically and provides smooth scroll navigation. Only appears if headings exist in the content.
|
||||
|
||||
### Update SEO Meta Tags
|
||||
|
||||
@@ -63,6 +63,7 @@ interface PageFrontmatter {
|
||||
slug: string;
|
||||
published: boolean;
|
||||
order?: number; // Display order in navigation
|
||||
showInNav?: boolean; // Show in navigation menu (default: true)
|
||||
excerpt?: string; // Short excerpt for card view
|
||||
image?: string; // Thumbnail/OG image URL for featured cards
|
||||
featured?: boolean; // Show in featured section
|
||||
@@ -78,6 +79,7 @@ interface ParsedPage {
|
||||
content: string;
|
||||
published: boolean;
|
||||
order?: number;
|
||||
showInNav?: boolean; // Show in navigation menu (default: true)
|
||||
excerpt?: string; // Short excerpt for card view
|
||||
image?: string; // Thumbnail/OG image URL for featured cards
|
||||
featured?: boolean; // Show in featured section
|
||||
@@ -168,6 +170,7 @@ function parsePageFile(filePath: string): ParsedPage | null {
|
||||
content: content.trim(),
|
||||
published: frontmatter.published ?? true,
|
||||
order: frontmatter.order,
|
||||
showInNav: frontmatter.showInNav, // Show in navigation menu (default: true)
|
||||
excerpt: frontmatter.excerpt, // Short excerpt for card view
|
||||
image: frontmatter.image, // Thumbnail/OG image URL for featured cards
|
||||
featured: frontmatter.featured, // Show in featured section
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useQuery } from "convex/react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { api } from "../../convex/_generated/api";
|
||||
|
||||
// Type for featured item from Convex (used for backwards compatibility)
|
||||
@@ -142,7 +143,7 @@ export default function FeaturedCards({
|
||||
return (
|
||||
<div className="featured-cards">
|
||||
{featuredData.map((item) => (
|
||||
<a key={item.slug} href={`/${item.slug}`} className="featured-card">
|
||||
<Link key={item.slug} to={`/${item.slug}`} className="featured-card">
|
||||
{/* Thumbnail image displayed as square using object-fit: cover */}
|
||||
{item.image && (
|
||||
<div className="featured-card-image-wrapper">
|
||||
@@ -160,7 +161,7 @@ export default function FeaturedCards({
|
||||
<p className="featured-card-excerpt">{item.excerpt}</p>
|
||||
)}
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -80,8 +80,8 @@ export default function Layout({ children }: LayoutProps) {
|
||||
const showBlogInNav =
|
||||
siteConfig.blogPage.enabled && siteConfig.blogPage.showInNav;
|
||||
|
||||
// Combine Blog link with pages and sort by order
|
||||
// This allows Blog to be positioned anywhere in the nav via siteConfig.blogPage.order
|
||||
// Combine Blog link, hardcoded nav items, and pages, then sort by order
|
||||
// This allows all nav items to be positioned anywhere via order field
|
||||
type NavItem = {
|
||||
slug: string;
|
||||
title: string;
|
||||
@@ -101,6 +101,20 @@ export default function Layout({ children }: LayoutProps) {
|
||||
});
|
||||
}
|
||||
|
||||
// Add hardcoded nav items (React routes like /stats, /write)
|
||||
if (siteConfig.hardcodedNavItems && siteConfig.hardcodedNavItems.length > 0) {
|
||||
siteConfig.hardcodedNavItems.forEach((item) => {
|
||||
// Only add if showInNav is true (defaults to true)
|
||||
if (item.showInNav !== false) {
|
||||
navItems.push({
|
||||
slug: item.slug,
|
||||
title: item.title,
|
||||
order: item.order ?? 999,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add pages from Convex
|
||||
if (pages && pages.length > 0) {
|
||||
pages.forEach((page) => {
|
||||
|
||||
@@ -47,6 +47,15 @@ export interface PostsDisplayConfig {
|
||||
showOnBlogPage: boolean; // Show post list on /blog page (requires blogPage.enabled)
|
||||
}
|
||||
|
||||
// Hardcoded navigation item configuration
|
||||
// For React route pages (like /stats, /write) that aren't markdown pages
|
||||
export interface HardcodedNavItem {
|
||||
slug: string; // URL path (e.g., "stats", "write")
|
||||
title: string; // Display name in navigation
|
||||
order?: number; // Nav order (lower = first, matches page frontmatter order)
|
||||
showInNav?: boolean; // Show in navigation menu (default: true)
|
||||
}
|
||||
|
||||
// Site configuration interface
|
||||
export interface SiteConfig {
|
||||
// Basic site info
|
||||
@@ -75,6 +84,9 @@ export interface SiteConfig {
|
||||
// Blog page configuration
|
||||
blogPage: BlogPageConfig;
|
||||
|
||||
// Hardcoded navigation items for React routes (like /stats, /write)
|
||||
hardcodedNavItems: HardcodedNavItem[];
|
||||
|
||||
// Posts display configuration
|
||||
postsDisplay: PostsDisplayConfig;
|
||||
|
||||
@@ -175,6 +187,24 @@ export const siteConfig: SiteConfig = {
|
||||
showViewToggle: true, // Show toggle button to switch between list and card views
|
||||
},
|
||||
|
||||
// Hardcoded navigation items for React routes
|
||||
// Add React route pages (like /stats, /write) that should appear in navigation
|
||||
// Set showInNav: false to hide from nav while keeping the route accessible
|
||||
hardcodedNavItems: [
|
||||
{
|
||||
slug: "stats",
|
||||
title: "Stats",
|
||||
order: 10,
|
||||
showInNav: true,
|
||||
},
|
||||
{
|
||||
slug: "write",
|
||||
title: "Write",
|
||||
order: 20,
|
||||
showInNav: true,
|
||||
},
|
||||
],
|
||||
|
||||
// Posts display configuration
|
||||
// Controls where the post list appears
|
||||
// Both can be true to show posts on homepage AND blog page
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useQuery } from "convex/react";
|
||||
import { api } from "../../convex/_generated/api";
|
||||
import PostList from "../components/PostList";
|
||||
@@ -166,9 +167,9 @@ export default function Home() {
|
||||
<ul className="home-featured-list">
|
||||
{featuredList.map((item) => (
|
||||
<li key={item.slug}>
|
||||
<a href={`/${item.slug}`} className="home-featured-link">
|
||||
<Link to={`/${item.slug}`} className="home-featured-link">
|
||||
{item.title}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
@@ -229,9 +230,9 @@ export default function Home() {
|
||||
project on GitHub
|
||||
</a>{" "}
|
||||
to fork and deploy your own. View{" "}
|
||||
<a href="/stats" className="home-text-link">
|
||||
<Link to="/stats" className="home-text-link">
|
||||
real-time site stats
|
||||
</a>
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
<p></p>
|
||||
|
||||
@@ -46,6 +46,7 @@ const PAGE_FIELDS = [
|
||||
{ name: "slug", required: true, example: '"page-url"' },
|
||||
{ name: "published", required: true, example: "true" },
|
||||
{ name: "order", required: false, example: "1" },
|
||||
{ name: "showInNav", required: false, example: "true" },
|
||||
{ name: "excerpt", required: false, example: '"Short description"' },
|
||||
{ name: "image", required: false, example: '"/images/thumbnail.png"' },
|
||||
{ name: "featured", required: false, example: "true" },
|
||||
@@ -96,6 +97,7 @@ title: "Page Title"
|
||||
slug: "page-url"
|
||||
published: true
|
||||
order: 1
|
||||
showInNav: true
|
||||
layout: "sidebar"
|
||||
---
|
||||
|
||||
|
||||
@@ -300,7 +300,7 @@ body {
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
max-width: 680px;
|
||||
max-width: 800px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 40px 24px;
|
||||
|
||||
Reference in New Issue
Block a user