fix: docs css sidebar fixes

This commit is contained in:
Wayne Sutton
2026-01-09 14:54:00 -08:00
parent 7a8a1c61e3
commit 1323928341
17 changed files with 153 additions and 20 deletions

View File

@@ -69,6 +69,17 @@ Expert full-stack and AI developer specializing in React, Vite, Bun, Clerk, Work
- PRD files end in `.MD` and go in `prds/` folder - PRD files end in `.MD` and go in `prds/` folder
- Do NOT create README, CONTRIBUTING, SUMMARY, or USAGE_GUIDELINES unless explicitly asked - Do NOT create README, CONTRIBUTING, SUMMARY, or USAGE_GUIDELINES unless explicitly asked
## Git safety
Follow all rules in `.claude/skills/gitrules.md`:
- Never use `git checkout` to revert changes without examining what will be destroyed
- Always use `git diff <file>` before any destructive operation
- Never run destructive commands (`git reset --hard`, `git checkout -- .`, `git clean -fd`, `git stash drop`) without explicit user approval
- Always run `git status` first before any git operation
- When asked to "undo" changes, manually edit files instead of using checkout
- If uncommitted changes exist, stop and ask user before proceeding
## Communication ## Communication
- Give answers immediately, explain after - Give answers immediately, explain after

View File

@@ -102,6 +102,16 @@ Don't write any code until you're very confident (98% or more) in what needs to
If unclear, ask for more information. If unclear, ask for more information.
## 7. Git safety
Follow all rules in `.claude/skills/gitrules.md`:
- Never use `git checkout` to revert changes without examining what will be destroyed
- Always use `git diff <file>` before any destructive operation
- Never run `git reset --hard`, `git checkout -- .`, `git clean -fd`, or `git stash drop` without explicit user approval
- Always run `git status` first to check for uncommitted changes
- When user asks to "undo" changes, manually edit files to revert specific sections instead of using checkout
## Quick reference checklist ## Quick reference checklist
Before writing code: Before writing code:
@@ -119,3 +129,10 @@ When uncertain:
- [ ] Don't assume - [ ] Don't assume
- [ ] Reference documentation - [ ] Reference documentation
- [ ] Narrow down to 1-2 most likely solutions - [ ] Narrow down to 1-2 most likely solutions
Before git operations:
- [ ] Have I run `git status` first?
- [ ] Am I about to run a destructive command?
- [ ] Have I shown the user what will be affected?
- [ ] Do I have explicit user approval for destructive operations?
- [ ] Am I following `.claude/skills/gitrules.md`?

View File

@@ -19,7 +19,7 @@ alwaysApply: true
-Do you understand, what Im asking? Never assume anything on your own, if anything isnt clear, please ask questions and clarify your doubts. -Do you understand, what Im asking? Never assume anything on your own, if anything isnt clear, please ask questions and clarify your doubts.
- reference @dev2.mdc @help.mdc @files.md if needed - reference @dev2.mdc @help.mdc @gitruels.mdc @files.md if needed
- do not use use emoji or emojis in the readme or app unless instructed - do not use use emoji or emojis in the readme or app unless instructed
- always create type-safe code - always create type-safe code
- you understand when to use Effect and when not to use Effect https://react.dev/learn/you-might-not-need-an-effect - you understand when to use Effect and when not to use Effect https://react.dev/learn/you-might-not-need-an-effect
@@ -82,3 +82,4 @@ alwaysApply: true
- you never use placeholder text or images in code because everything is realtime sync with convex database - you never use placeholder text or images in code because everything is realtime sync with convex database
- you don't ship code with placeholder text or images - you don't ship code with placeholder text or images
- **!IMPORTANT**: **DO NOT** externalize or document your work, usage guidelines, or benchmarks (e.g. `README.md`, `CONTRIBUTING.md`, `SUMMARY.md`, `USAGE_GUIDELINES.md` after completing the task, unless explicitly instructed to do so. You may include a brief summary of your work, but do not create separate documentation files for it. - **!IMPORTANT**: **DO NOT** externalize or document your work, usage guidelines, or benchmarks (e.g. `README.md`, `CONTRIBUTING.md`, `SUMMARY.md`, `USAGE_GUIDELINES.md` after completing the task, unless explicitly instructed to do so. You may include a brief summary of your work, but do not create separate documentation files for it.
- **!IMPORTANT**: Follow all git safety rules in @gitruels.mdc - never use destructive git commands without explicit user approval, always run `git status` first, and manually edit files instead of using `git checkout` to revert changes.

View File

@@ -85,3 +85,16 @@ When making changes to the codebase:
Don't write any code until you're very confident (98% or more) in what needs to be done. Don't write any code until you're very confident (98% or more) in what needs to be done.
If unclear, ask for more info. If unclear, ask for more info.
## 7. Git Safety
Follow all rules in @gitruels.mdc:
- Never use `git checkout` to revert changes without examining what will be destroyed
- Always use `git diff <file>` before any destructive operation
- Never run destructive commands (`git reset --hard`, `git checkout -- .`, `git clean -fd`, `git stash drop`) without explicit user approval
- Always run `git status` first before any git operation
- When asked to "undo" changes, manually edit files instead of using checkout
- If uncommitted changes exist, stop and ask user before proceeding

View File

@@ -19,10 +19,10 @@ Your content is instantly available to browsers, LLMs, and AI agents.. Write mar
- **Site Name**: markdown - **Site Name**: markdown
- **Site Title**: markdown sync framework - **Site Title**: markdown sync framework
- **Site URL**: https://yoursite.example.com - **Site URL**: https://yoursite.example.com
- **Total Posts**: 17 - **Total Posts**: 18
- **Total Pages**: 4 - **Total Pages**: 4
- **Latest Post**: 2025-12-29 - **Latest Post**: 2026-01-07
- **Last Updated**: 2026-01-07T06:23:37.520Z - **Last Updated**: 2026-01-09T07:02:12.472Z
## Tech stack ## Tech stack

View File

@@ -5,7 +5,7 @@ Project instructions for Claude Code.
## Project context ## Project context
<!-- Auto-updated by sync:discovery --> <!-- Auto-updated by sync:discovery -->
<!-- Site: markdown | Posts: 17 | Pages: 4 | Updated: 2026-01-07T06:23:37.521Z --> <!-- Site: markdown | Posts: 18 | Pages: 4 | Updated: 2026-01-09T07:02:12.473Z -->
Markdown sync framework. Write markdown in `content/`, run sync commands, content appears instantly via Convex real-time database. Built for developers and AI agents. Markdown sync framework. Write markdown in `content/`, run sync commands, content appears instantly via Convex real-time database. Built for developers and AI agents.

10
TASK.md
View File

@@ -4,10 +4,18 @@
## Current Status ## Current Status
v2.15.1 ready. Additional Core Web Vitals CLS and INP improvements. v2.15.3 ready. Fixed footer not displaying on docs landing page.
## Completed ## Completed
- [x] Footer not displaying on /docs landing page fix (v2.15.3)
- [x] DocsPage.tsx was missing Footer component entirely
- [x] Added Footer import and footerPage query to DocsPage.tsx
- [x] Added footer rendering logic after BlogPost (same pattern as Post.tsx)
- [x] Updated getDocsLandingPage query to return showFooter, footer, excerpt, aiChat fields
- [x] Updated getDocsLandingPost query to return showFooter, footer, aiChat fields
- [x] Added aiChatEnabled and pageContent props to DocsLayout
- [x] Additional Core Web Vitals CLS and INP improvements (v2.15.1) - [x] Additional Core Web Vitals CLS and INP improvements (v2.15.1)
- [x] Added aspect-ratio to blog images and header images to prevent layout shift - [x] Added aspect-ratio to blog images and header images to prevent layout shift
- [x] Added CSS containment to main content areas - [x] Added CSS containment to main content areas

View File

@@ -4,6 +4,21 @@ 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/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [2.15.3] - 2026-01-09
### Fixed
- Footer not displaying on `/docs` landing page when `showFooter: true` in frontmatter
- `DocsPage.tsx` was missing the Footer component entirely
- Added Footer import, footerPage query, and footer rendering logic to DocsPage.tsx
- Footer now respects `showFooter` frontmatter field on docs landing pages
- AI chat support added to DocsLayout via `aiChatEnabled` and `pageContent` props
### Changed
- Updated `getDocsLandingPage` query in `convex/pages.ts` to return `showFooter`, `footer`, `excerpt`, and `aiChat` fields
- Updated `getDocsLandingPost` query in `convex/posts.ts` to return `showFooter`, `footer`, and `aiChat` fields
## [2.15.2] - 2026-01-08 ## [2.15.2] - 2026-01-08
### Fixed ### Fixed

View File

@@ -11,6 +11,35 @@ docsSectionOrder: 4
All notable changes to this project. All notable changes to this project.
## v2.15.3
Released January 9, 2026
**Footer not displaying on /docs landing page fix**
Fixed an issue where the footer was not displaying on the `/docs` landing page even when `showFooter: true` was set in the frontmatter. The `DocsPage.tsx` component (which handles the `/docs` route with `docsLanding: true`) was missing the Footer component entirely.
**Fixes:**
- Added Footer component to DocsPage.tsx
- Footer now respects `showFooter` frontmatter field on docs landing pages
- Added AI chat support to docs landing page via `aiChatEnabled` and `pageContent` props
**Technical:**
- Added `Footer` import and `footerPage` query to fetch footer content
- Added footer rendering logic after BlogPost component (same pattern as Post.tsx)
- Updated `getDocsLandingPage` query in `convex/pages.ts` to return `showFooter`, `footer`, `excerpt`, and `aiChat` fields
- Updated `getDocsLandingPost` query in `convex/posts.ts` to return `showFooter`, `footer`, and `aiChat` fields
**Files changed:**
- `src/pages/DocsPage.tsx` - Added Footer component and rendering logic
- `convex/pages.ts` - Updated getDocsLandingPage query return fields
- `convex/posts.ts` - Updated getDocsLandingPost query return fields
---
## v2.15.2 ## v2.15.2
Released January 8, 2026 Released January 8, 2026

View File

@@ -283,12 +283,16 @@ export const getDocsLandingPage = query({
slug: v.string(), slug: v.string(),
title: v.string(), title: v.string(),
content: v.string(), content: v.string(),
excerpt: v.optional(v.string()),
image: v.optional(v.string()), image: v.optional(v.string()),
showImageAtTop: v.optional(v.boolean()), showImageAtTop: v.optional(v.boolean()),
authorName: v.optional(v.string()), authorName: v.optional(v.string()),
authorImage: v.optional(v.string()), authorImage: v.optional(v.string()),
docsSectionGroup: v.optional(v.string()), docsSectionGroup: v.optional(v.string()),
docsSectionOrder: v.optional(v.number()), docsSectionOrder: v.optional(v.number()),
showFooter: v.optional(v.boolean()),
footer: v.optional(v.string()),
aiChat: v.optional(v.boolean()),
}), }),
v.null(), v.null(),
), ),
@@ -308,12 +312,16 @@ export const getDocsLandingPage = query({
slug: landing.slug, slug: landing.slug,
title: landing.title, title: landing.title,
content: landing.content, content: landing.content,
excerpt: landing.excerpt,
image: landing.image, image: landing.image,
showImageAtTop: landing.showImageAtTop, showImageAtTop: landing.showImageAtTop,
authorName: landing.authorName, authorName: landing.authorName,
authorImage: landing.authorImage, authorImage: landing.authorImage,
docsSectionGroup: landing.docsSectionGroup, docsSectionGroup: landing.docsSectionGroup,
docsSectionOrder: landing.docsSectionOrder, docsSectionOrder: landing.docsSectionOrder,
showFooter: landing.showFooter,
footer: landing.footer,
aiChat: landing.aiChat,
}; };
}, },
}); });

View File

@@ -977,6 +977,9 @@ export const getDocsLandingPost = query({
authorImage: v.optional(v.string()), authorImage: v.optional(v.string()),
docsSectionGroup: v.optional(v.string()), docsSectionGroup: v.optional(v.string()),
docsSectionOrder: v.optional(v.number()), docsSectionOrder: v.optional(v.number()),
showFooter: v.optional(v.boolean()),
footer: v.optional(v.string()),
aiChat: v.optional(v.boolean()),
}), }),
v.null(), v.null(),
), ),
@@ -1006,6 +1009,9 @@ export const getDocsLandingPost = query({
authorImage: landing.authorImage, authorImage: landing.authorImage,
docsSectionGroup: landing.docsSectionGroup, docsSectionGroup: landing.docsSectionGroup,
docsSectionOrder: landing.docsSectionOrder, docsSectionOrder: landing.docsSectionOrder,
showFooter: landing.showFooter,
footer: landing.footer,
aiChat: landing.aiChat,
}; };
}, },
}); });

View File

@@ -45,6 +45,7 @@ A brief description of each file in the codebase.
| `Blog.tsx` | Dedicated blog page with featured layout: hero post (first blogFeatured), featured row (remaining blogFeatured in 2 columns with excerpts), and regular posts (3 columns without excerpts). Supports list/card view toggle. Includes back button in navigation | | `Blog.tsx` | Dedicated blog page with featured layout: hero post (first blogFeatured), featured row (remaining blogFeatured in 2 columns with excerpts), and regular posts (3 columns without excerpts). Supports list/card view toggle. Includes back button in navigation |
| `Post.tsx` | Individual blog post or page view with optional left sidebar (TOC) and right sidebar (CopyPageDropdown). Includes back button (hidden when used as homepage), tag links, related posts section in footer for blog posts, footer component with markdown support (fetches footer.md content from Convex), and social footer. Supports 3-column layout at 1135px+. Can display image at top when showImageAtTop: true. Can be used as custom homepage via siteConfig.homepage (update SITE_URL/SITE_NAME when forking). SEO: Dynamic canonical URL, hreflang tags, og:url consistency, and twitter:site meta tags. DOM order optimized for SEO (article before sidebar, CSS order for visual layout). | | `Post.tsx` | Individual blog post or page view with optional left sidebar (TOC) and right sidebar (CopyPageDropdown). Includes back button (hidden when used as homepage), tag links, related posts section in footer for blog posts, footer component with markdown support (fetches footer.md content from Convex), and social footer. Supports 3-column layout at 1135px+. Can display image at top when showImageAtTop: true. Can be used as custom homepage via siteConfig.homepage (update SITE_URL/SITE_NAME when forking). SEO: Dynamic canonical URL, hreflang tags, og:url consistency, and twitter:site meta tags. DOM order optimized for SEO (article before sidebar, CSS order for visual layout). |
| `Stats.tsx` | Real-time analytics dashboard with visitor stats and GitHub stars. Configurable via `siteConfig.statsPage` to enable/disable public access and navigation visibility. Shows disabled message when `enabled: false` (similar to NewsletterAdmin pattern). | | `Stats.tsx` | Real-time analytics dashboard with visitor stats and GitHub stars. Configurable via `siteConfig.statsPage` to enable/disable public access and navigation visibility. Shows disabled message when `enabled: false` (similar to NewsletterAdmin pattern). |
| `DocsPage.tsx` | Docs landing page component for `/docs` route. Renders the page/post with `docsLanding: true` in DocsLayout. Fetches landing content via `getDocsLandingPage` and `getDocsLandingPost` queries. Includes Footer component (respects showFooter frontmatter), AI chat support (aiChatEnabled), and fallback to first docs item if no landing page is set. |
| `TagPage.tsx` | Tag archive page displaying posts filtered by a specific tag. Includes view mode toggle (list/cards) with localStorage persistence | | `TagPage.tsx` | Tag archive page displaying posts filtered by a specific tag. Includes view mode toggle (list/cards) with localStorage persistence |
| `AuthorPage.tsx` | Author archive page displaying posts by a specific author. Includes view mode toggle (list/cards) with localStorage persistence. Author name clickable in posts links to this page. | | `AuthorPage.tsx` | Author archive page displaying posts by a specific author. Includes view mode toggle (list/cards) with localStorage persistence. Author name clickable in posts links to this page. |
| `Write.tsx` | Three-column markdown writing page with Cursor docs-style UI, frontmatter reference with copy buttons, theme toggle, font switcher (serif/sans/monospace), localStorage persistence, and optional AI Agent mode (toggleable via siteConfig.aiChat.enabledOnWritePage). When enabled, Agent replaces the textarea with AIChatView component. Includes scroll prevention when switching to Agent mode to prevent page jump. Title changes to "Agent" when in AI chat mode. | | `Write.tsx` | Three-column markdown writing page with Cursor docs-style UI, frontmatter reference with copy buttons, theme toggle, font switcher (serif/sans/monospace), localStorage persistence, and optional AI Agent mode (toggleable via siteConfig.aiChat.enabledOnWritePage). When enabled, Agent replaces the textarea with AIChatView component. Includes scroll prevention when switching to Agent mode to prevent page jump. Title changes to "Agent" when in AI chat mode. |

View File

@@ -10,6 +10,8 @@
<!-- Preconnect for Convex site endpoints --> <!-- Preconnect for Convex site endpoints -->
<link rel="preconnect" href="https://convex.site" crossorigin /> <link rel="preconnect" href="https://convex.site" crossorigin />
<link rel="dns-prefetch" href="https://convex.site" /> <link rel="dns-prefetch" href="https://convex.site" />
<!-- Preload critical LCP image -->
<link rel="preload" href="/images/logo.svg" as="image" type="image/svg+xml" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- SEO Meta Tags --> <!-- SEO Meta Tags -->

View File

@@ -1,6 +1,6 @@
# llms.txt - Information for AI assistants and LLMs # llms.txt - Information for AI assistants and LLMs
# Learn more: https://llmstxt.org/ # Learn more: https://llmstxt.org/
# Last updated: 2026-01-07T06:23:37.522Z # Last updated: 2026-01-09T07:02:12.474Z
> Your content is instantly available to browsers, LLMs, and AI agents. > Your content is instantly available to browsers, LLMs, and AI agents.
@@ -9,8 +9,8 @@
- URL: https://yoursite.example.com - URL: https://yoursite.example.com
- Description: Your content is instantly available to browsers, LLMs, and AI agents. Write markdown, sync from the terminal. Your content is instantly available to browsers, LLMs, and AI agents. Built on Convex and Netlify. - Description: Your content is instantly available to browsers, LLMs, and AI agents. Write markdown, sync from the terminal. Your content is instantly available to browsers, LLMs, and AI agents. Built on Convex and Netlify.
- Topics: Markdown, Convex, React, TypeScript, Netlify, Open Source, AI, LLM, AEO, GEO - Topics: Markdown, Convex, React, TypeScript, Netlify, Open Source, AI, LLM, AEO, GEO
- Total Posts: 17 - Total Posts: 18
- Latest Post: 2025-12-29 - Latest Post: 2026-01-07
- GitHub: https://github.com/waynesutton/markdown-site - GitHub: https://github.com/waynesutton/markdown-site
# API Endpoints # API Endpoints

View File

@@ -5,6 +5,7 @@ import { api } from "../../convex/_generated/api";
import DocsLayout from "../components/DocsLayout"; import DocsLayout from "../components/DocsLayout";
import BlogPost from "../components/BlogPost"; import BlogPost from "../components/BlogPost";
import CopyPageDropdown from "../components/CopyPageDropdown"; import CopyPageDropdown from "../components/CopyPageDropdown";
import Footer from "../components/Footer";
import { extractHeadings } from "../utils/extractHeadings"; import { extractHeadings } from "../utils/extractHeadings";
import siteConfig from "../config/siteConfig"; import siteConfig from "../config/siteConfig";
import { ArrowRight } from "lucide-react"; import { ArrowRight } from "lucide-react";
@@ -21,6 +22,9 @@ export default function DocsPage() {
const docsPosts = useQuery(api.posts.getDocsPosts); const docsPosts = useQuery(api.posts.getDocsPosts);
const docsPages = useQuery(api.pages.getDocsPages); const docsPages = useQuery(api.pages.getDocsPages);
// Fetch footer content from Convex (synced via markdown)
const footerPage = useQuery(api.pages.getPageBySlug, { slug: "footer" });
// Determine which content to use: page takes priority over post // Determine which content to use: page takes priority over post
const landingContent = landingPage || landingPost; const landingContent = landingPage || landingPost;
@@ -76,7 +80,12 @@ export default function DocsPage() {
: undefined; : undefined;
return ( return (
<DocsLayout headings={headings} currentSlug={landingContent.slug}> <DocsLayout
headings={headings}
currentSlug={landingContent.slug}
aiChatEnabled={landingContent.aiChat}
pageContent={landingContent.content}
>
<article className="docs-article"> <article className="docs-article">
<div className="docs-article-actions"> <div className="docs-article-actions">
<CopyPageDropdown <CopyPageDropdown
@@ -103,6 +112,15 @@ export default function DocsPage() {
slug={landingContent.slug} slug={landingContent.slug}
pageType={"date" in landingContent ? "post" : "page"} pageType={"date" in landingContent ? "post" : "page"}
/> />
{/* Footer - respects showFooter frontmatter field */}
{siteConfig.footer.enabled &&
(landingContent.showFooter !== undefined
? landingContent.showFooter
: "date" in landingContent
? siteConfig.footer.showOnPosts
: siteConfig.footer.showOnPages) && (
<Footer content={landingContent.footer || footerPage?.content} />
)}
</article> </article>
</DocsLayout> </DocsLayout>
); );

View File

@@ -170,6 +170,9 @@ export default function Home() {
src={siteConfig.logo} src={siteConfig.logo}
alt={siteConfig.name} alt={siteConfig.name}
className="home-logo" className="home-logo"
width={48}
height={48}
fetchPriority="high"
/> />
)} )}
<h1 className="home-name">{siteConfig.name}</h1> <h1 className="home-name">{siteConfig.name}</h1>

View File

@@ -12941,6 +12941,7 @@ body {
min-height: calc(100vh - 60px); min-height: calc(100vh - 60px);
margin: 0; margin: 0;
padding: 0; padding: 0;
contain: layout style; /* CLS fix: isolate layout recalculations */
} }
/* Docs layout without TOC (two-column) */ /* Docs layout without TOC (two-column) */
@@ -12948,19 +12949,19 @@ body {
/* Same as default - sidebars are fixed */ /* Same as default - sidebars are fixed */
} }
/* Left sidebar for docs navigation - flush left */ /* Left sidebar for docs navigation - flush left, full height */
.docs-sidebar-left { .docs-sidebar-left {
position: fixed; position: fixed;
top: 20px; top: 0;
bottom: 0;
left: 0; left: 0;
width: 280px; width: 280px;
height: calc(100vh - 80px); height: 100%;
overflow-y: auto; overflow-y: auto;
background-color: var(--bg-sidebar); background-color: var(--bg-sidebar);
padding: 24px; padding: 24px;
padding-top: 32px;
border-right: 1px solid var(--border-sidebar); border-right: 1px solid var(--border-sidebar);
border-radius: 6px;
border-top: 1px solid var(--border-sidebar);
z-index: 10; z-index: 10;
} }
@@ -12981,19 +12982,19 @@ body {
background-color: var(--text-muted); background-color: var(--text-muted);
} }
/* Right sidebar for table of contents - flush right */ /* Right sidebar for table of contents - flush right, full height */
.docs-sidebar-right { .docs-sidebar-right {
position: fixed; position: fixed;
top: 20px; top: 0;
bottom: 0;
right: 0; right: 0;
width: 280px; width: 280px;
height: calc(100vh - 80px); height: 100%;
overflow-y: auto; overflow-y: auto;
background-color: var(--bg-sidebar); background-color: var(--bg-sidebar);
padding: 24px; padding: 24px;
padding-top: 32px;
border-left: 1px solid var(--border-sidebar); border-left: 1px solid var(--border-sidebar);
border-radius: 6px;
border-top: 1px solid var(--border-sidebar);
z-index: 10; z-index: 10;
} }