Raw index.md now includes home.md and footer.md content

This commit is contained in:
Wayne Sutton
2026-01-03 20:46:55 -08:00
parent cb2875a830
commit f377a3dde2
11 changed files with 236 additions and 8 deletions

View File

@@ -0,0 +1,78 @@
# Docs Navigation Performance - Pinned for Later
## Problem
Slight delay when switching docs groups on the live site (https://www.markdown.fast/docs) - blank middle screen appears while loading docs-content before showing the actual content.
## Root Cause
When navigating between docs pages, `useQuery` in Post.tsx returns `undefined` for the new slug while loading, causing a loading skeleton flash.
---
## Option A: React Stale-While-Revalidate (Already Implemented)
**Status:** Implemented but can be reverted if Option B preferred
**Files Modified:**
- `src/pages/Post.tsx` - Added client-side cache to show previous content during navigation
- `src/styles/global.css` - Added 150ms fade-in animation to `.docs-article`
**How it works:**
- Cache last successfully loaded docs content in a React ref
- When navigating, show cached (previous) content while new content loads
- Once new data arrives, swap it in seamlessly
**Pros:**
- Minimal change, doesn't touch Convex backend
- Fast initial page load (metadata-only sidebar)
- Low memory usage
**Cons:**
- Brief moment showing "stale" content from previous page
- Not a Convex-native pattern (React UI workaround)
---
## Option B: Prefetch All Docs Content (Future Consideration)
**Status:** Not implemented - requires more planning
**Files to Modify:**
- `convex/posts.ts` - Modify `getDocsPosts` to return full content
- `convex/pages.ts` - Modify `getDocsPages` to return full content
- `src/components/DocsSidebar.tsx` or parent - Store all content
- `src/pages/Post.tsx` - Use prefetched content instead of individual queries
**How it would work:**
- Sidebar (or parent component) fetches ALL docs with FULL content upfront
- Store in React context or state
- When navigating, content is already in memory - instant render
**Pros:**
- Truly instant navigation (no network request)
- More "Convex-native" - single query, real-time updates for all docs
**Cons:**
- Slower initial page load (loading all content upfront)
- Higher memory usage
- Higher bandwidth cost
- May not scale well for large docs sites (50+ pages)
---
## Decision Criteria
Choose Option B if:
- Small docs site (10-20 pages)
- Users typically browse multiple docs per session
- Content is relatively short
Stick with Option A if:
- Larger docs site (50+ pages)
- Users often visit just 1-2 pages
- Long-form content
---
## Current State
- Option A is implemented and working
- Revisit Option B when docs site grows or if instant navigation becomes a priority

10
TASK.md
View File

@@ -4,10 +4,18 @@
## Current Status
v2.8.2 ready. Fixed footer not displaying on docs section pages.
v2.8.3 ready. Updated raw/index.md to include home.md and footer.md content.
## Completed
- [x] Update raw/index.md to include home.md and footer.md content
- [x] Updated `generateHomepageIndex` function in `scripts/sync-posts.ts`
- [x] Home intro content (slug: home-intro) now displays at top of index.md
- [x] Footer content (slug: footer) now displays at bottom of index.md
- [x] Horizontal rule separators between sections
- [x] Falls back to generic message if home-intro page not found
- [x] Mirrors actual homepage structure for AI agents reading raw markdown
- [x] Fix footer not displaying on docs section pages with showFooter: true
- [x] Added footer.md content query to Post.tsx (matching Home.tsx and Blog.tsx pattern)
- [x] Updated all 4 Footer component calls to use `post.footer || footerPage?.content` pattern

View File

@@ -4,6 +4,22 @@ 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.3] - 2026-01-03
### Changed
- `raw/index.md` now includes home.md and footer.md content
- Home intro content from `content/pages/home.md` (slug: home-intro) displays at top
- Footer content from `content/pages/footer.md` (slug: footer) displays at bottom
- Mirrors the actual homepage structure for AI agents reading raw markdown
- Falls back to generic message if home-intro page not found
### Technical
- Updated `generateHomepageIndex` function in `scripts/sync-posts.ts`
- Finds home-intro and footer pages from published pages array
- Adds horizontal rule separators between sections
## [2.8.2] - 2026-01-03
### Fixed

View File

@@ -12,6 +12,26 @@ docsSectionOrder: 4
All notable changes to this project.
![](https://img.shields.io/badge/License-MIT-yellow.svg)
## v2.8.3
Released January 3, 2026
**Raw index.md now includes home.md and footer.md content**
- `raw/index.md` now mirrors the actual homepage structure
- Home intro content from `content/pages/home.md` displays at top
- Footer content from `content/pages/footer.md` displays at bottom
- Horizontal rule separators between sections
- Falls back to generic message if home-intro page not found
- AI agents reading `/raw/index.md` now get the full homepage experience
**Technical details:**
- Updated `generateHomepageIndex` function in `scripts/sync-posts.ts`
- Finds home-intro and footer pages from published pages array by slug
Updated files: `scripts/sync-posts.ts`
## v2.8.2
Released January 3, 2026

View File

@@ -222,7 +222,7 @@ Markdown files for static pages like About, Projects, Contact, Changelog.
| File | Description |
| ------------------------- | ----------------------------------------------------- |
| `sync-posts.ts` | Syncs markdown files to Convex at build time (markdown sync v2) |
| `sync-posts.ts` | Syncs markdown files to Convex at build time (markdown sync v2). Generates `raw/index.md` with home.md content at top, posts/pages list, and footer.md content at bottom |
| `sync-discovery-files.ts` | Updates AGENTS.md, CLAUDE.md, and llms.txt with current app data |
| `import-url.ts` | Imports external URLs as markdown posts (Firecrawl) |
| `configure-fork.ts` | Automated fork configuration (reads fork-config.json). ES module compatible using fileURLToPath for __dirname equivalent. |

View File

@@ -8,6 +8,26 @@ Date: 2026-01-04
All notable changes to this project.
![](https://img.shields.io/badge/License-MIT-yellow.svg)
## v2.8.3
Released January 3, 2026
**Raw index.md now includes home.md and footer.md content**
- `raw/index.md` now mirrors the actual homepage structure
- Home intro content from `content/pages/home.md` displays at top
- Footer content from `content/pages/footer.md` displays at bottom
- Horizontal rule separators between sections
- Falls back to generic message if home-intro page not found
- AI agents reading `/raw/index.md` now get the full homepage experience
**Technical details:**
- Updated `generateHomepageIndex` function in `scripts/sync-posts.ts`
- Finds home-intro and footer pages from published pages array by slug
Updated files: `scripts/sync-posts.ts`
## v2.8.2
Released January 3, 2026

View File

@@ -1,6 +1,30 @@
# Homepage
This is the homepage index of all published content.
An open-source publishing framework built for AI agents and developers to ship **[docs](/docs)**, or **[blogs](/blog)** or **[websites](/)**.
Write markdown, sync from the terminal. **[Fork it](https://github.com/waynesutton/markdown-site)**, customize it, ship it.
<!-- This is a comments
Your content is instantly available to browsers, LLMs, and AI
agents. -->
## Features
**AI agent integration** — API endpoints, raw markdown files, skills.md and MCP server included.
**File-based publishing** — Write markdown locally, run `npm run sync`, content syncs everywhere.
**URL content import** — Import urls to scrape any webpage into markdown with Firecrawl.
**Newsletter automation** — Built-in subscription forms and admin dashboard powered by AgentMail.
**Multiple output formats** — JSON via API endpoints, raw .md files, and RSS feeds.
**Real-time team sync** — Multiple developers run npm run sync from different machines.
**Sync Commands** - Sync discovery commands to update AGENTS.md, CLAUDE.md, and llms.txt
---
## Blog Posts (18)
@@ -57,3 +81,9 @@ This is the homepage index of all published content.
**Total Content:** 18 posts, 8 pages
All content is available as raw markdown files at `/raw/{slug}.md`
---
Built with [Convex](https://convex.dev) for real-time sync and deployed on [Netlify](https://netlify.com). Read the [project on GitHub](https://github.com/waynesutton/markdown-site) to fork and deploy your own. View [real-time site stats](/stats).
Created by [Wayne](https://x.com/waynesutton) with Convex, Cursor, and Claude Opus 4.5. Follow on [Twitter/X](https://x.com/waynesutton), [LinkedIn](https://www.linkedin.com/in/waynesutton/), and [GitHub](https://github.com/waynesutton). This project is licensed under the MIT [License](https://github.com/waynesutton/markdown-site?tab=MIT-1-ov-file).

View File

@@ -476,9 +476,21 @@ function generateHomepageIndex(posts: ParsedPost[], pages: ParsedPage[]): void {
return new Date(b.date).getTime() - new Date(a.date).getTime();
});
// Find the home-intro page for homepage content
const homeIntroPage = publishedPages.find((p) => p.slug === "home-intro");
// Find the footer page for footer content
const footerPage = publishedPages.find((p) => p.slug === "footer");
// Build markdown content
let markdown = `# Homepage\n\n`;
// Include home intro content if available
if (homeIntroPage && homeIntroPage.content) {
markdown += `${homeIntroPage.content}\n\n`;
markdown += `---\n\n`;
} else {
markdown += `This is the homepage index of all published content.\n\n`;
}
// Add posts section
if (sortedPosts.length > 0) {
@@ -528,6 +540,12 @@ function generateHomepageIndex(posts: ParsedPost[], pages: ParsedPage[]): void {
markdown += `**Total Content:** ${sortedPosts.length} posts, ${publishedPages.length} pages\n`;
markdown += `\nAll content is available as raw markdown files at \`/raw/{slug}.md\`\n`;
// Add footer content if available
if (footerPage && footerPage.content) {
markdown += `\n---\n\n`;
markdown += `${footerPage.content}\n`;
}
// Write index.md file
const indexPath = path.join(RAW_OUTPUT_DIR, "index.md");
fs.writeFileSync(indexPath, markdown);

View File

@@ -454,7 +454,7 @@ export const siteConfig: SiteConfig = {
// Visitor map configuration
// Displays real-time visitor locations on the stats page
visitorMap: {
enabled: true, // Set to false to hide the visitor map
enabled: false, // Set to false to hide the visitor map
title: "Live Visitors", // Optional title above the map
},

View File

@@ -15,7 +15,7 @@ import { useSidebar } from "../context/SidebarContext";
import { format, parseISO } from "date-fns";
import { ArrowLeft, Link as LinkIcon, Rss, Tag } from "lucide-react";
import { XLogo, LinkedinLogo } from "@phosphor-icons/react";
import { useState, useEffect } from "react";
import { useState, useEffect, useRef } from "react";
import siteConfig from "../config/siteConfig";
// Site configuration - update these for your site (or run npm run configure)
@@ -43,8 +43,36 @@ export default function Post({
const slug = propSlug || routeSlug;
// Check for page first, then post
const page = useQuery(api.pages.getPageBySlug, slug ? { slug } : "skip");
const post = useQuery(api.posts.getPostBySlug, slug ? { slug } : "skip");
const pageQuery = useQuery(api.pages.getPageBySlug, slug ? { slug } : "skip");
const postQuery = useQuery(api.posts.getPostBySlug, slug ? { slug } : "skip");
// Cache last loaded docs content to prevent flash during navigation
// This implements stale-while-revalidate for seamless transitions
type DocsCache = { page: typeof pageQuery; post: typeof postQuery };
const lastDocsContentRef = useRef<DocsCache | null>(null);
// Determine if this is a docs section page (for caching logic)
const isDocsContent = siteConfig.docsSection?.enabled && slug;
// Check if queries are still loading
const isLoading = pageQuery === undefined || postQuery === undefined;
const isLoaded = pageQuery !== undefined && postQuery !== undefined;
// Update cache when both queries have resolved and we have displayable content
useEffect(() => {
if (isDocsContent && isLoaded) {
const hasContent = pageQuery !== null || postQuery !== null;
if (hasContent) {
lastDocsContentRef.current = { page: pageQuery, post: postQuery };
}
}
}, [pageQuery, postQuery, isDocsContent, isLoaded]);
// Use cached data while loading new docs content (stale-while-revalidate)
// This prevents the blank flash when navigating between docs pages
const useCache = isDocsContent && isLoading && lastDocsContentRef.current !== null;
const page = useCache ? lastDocsContentRef.current!.page : pageQuery;
const post = useCache ? lastDocsContentRef.current!.post : postQuery;
// Fetch related posts based on current post's tags (only for blog posts, not pages)
const relatedPosts = useQuery(

View File

@@ -12385,6 +12385,16 @@ body {
.docs-article {
max-width: 800px;
margin: 0 auto;
animation: docs-content-fade-in 150ms ease-out;
}
@keyframes docs-content-fade-in {
from {
opacity: 0.7;
}
to {
opacity: 1;
}
}
/* Docs loading skeleton - prevents flash when navigating between docs pages */