mirror of
https://github.com/waynesutton/markdown-site.git
synced 2026-01-12 04:09:14 +00:00
docs: update changelog page with right sidebar feature and fixes
Add v1.30.0, v1.30.1, and v1.30.2 entries to changelog-page.md covering: - Right sidebar feature implementation - TypeScript error fixes - Right sidebar default behavior fix
This commit is contained in:
23
src/components/RightSidebar.tsx
Normal file
23
src/components/RightSidebar.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import CopyPageDropdown from "./CopyPageDropdown";
|
||||
|
||||
interface RightSidebarProps {
|
||||
title: string;
|
||||
content: string;
|
||||
url: string;
|
||||
slug: string;
|
||||
description?: string;
|
||||
date?: string;
|
||||
tags?: string[];
|
||||
readTime?: string;
|
||||
}
|
||||
|
||||
export default function RightSidebar(props: RightSidebarProps) {
|
||||
return (
|
||||
<aside className="post-sidebar-right">
|
||||
<div className="right-sidebar-content">
|
||||
<CopyPageDropdown {...props} />
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -80,6 +80,13 @@ export interface GitHubRepoConfig {
|
||||
// default font family options: "serif" (New York), "sans" (system fonts), "monospace" (IBM Plex Mono)
|
||||
export type FontFamily = "serif" | "sans" | "monospace";
|
||||
|
||||
// Right sidebar configuration
|
||||
// Shows CopyPageDropdown in a right sidebar on posts/pages at 1135px+ viewport width
|
||||
export interface RightSidebarConfig {
|
||||
enabled: boolean; // Enable/disable the right sidebar globally
|
||||
minWidth?: number; // Minimum viewport width to show sidebar (default: 1135)
|
||||
}
|
||||
|
||||
// Site configuration interface
|
||||
export interface SiteConfig {
|
||||
// Basic site info
|
||||
@@ -126,6 +133,9 @@ export interface SiteConfig {
|
||||
|
||||
// GitHub repository configuration for AI service links
|
||||
gitHubRepo: GitHubRepoConfig;
|
||||
|
||||
// Right sidebar configuration
|
||||
rightSidebar: RightSidebarConfig;
|
||||
}
|
||||
|
||||
// Default site configuration
|
||||
@@ -271,6 +281,14 @@ export const siteConfig: SiteConfig = {
|
||||
branch: "main", // Default branch
|
||||
contentPath: "public/raw", // Path to raw markdown files
|
||||
},
|
||||
|
||||
// Right sidebar configuration
|
||||
// Shows CopyPageDropdown in a right sidebar on posts/pages at 1135px+ viewport width
|
||||
// When enabled, CopyPageDropdown moves from nav to right sidebar on wide screens
|
||||
rightSidebar: {
|
||||
enabled: true, // Set to false to disable right sidebar globally
|
||||
minWidth: 1135, // Minimum viewport width in pixels to show sidebar
|
||||
},
|
||||
};
|
||||
|
||||
// Export the config as default for easy importing
|
||||
|
||||
@@ -4,11 +4,13 @@ import { api } from "../../convex/_generated/api";
|
||||
import BlogPost from "../components/BlogPost";
|
||||
import CopyPageDropdown from "../components/CopyPageDropdown";
|
||||
import PageSidebar from "../components/PageSidebar";
|
||||
import RightSidebar from "../components/RightSidebar";
|
||||
import { extractHeadings } from "../utils/extractHeadings";
|
||||
import { useSidebar } from "../context/SidebarContext";
|
||||
import { format, parseISO } from "date-fns";
|
||||
import { ArrowLeft, Link as LinkIcon, Twitter, Rss, Tag } from "lucide-react";
|
||||
import { useState, useEffect } from "react";
|
||||
import siteConfig from "../config/siteConfig";
|
||||
|
||||
// Site configuration
|
||||
const SITE_URL = "https://markdown.fast";
|
||||
@@ -185,35 +187,40 @@ export default function Post() {
|
||||
if (page) {
|
||||
// Extract headings for sidebar TOC (only for pages with layout: "sidebar")
|
||||
const headings = page.layout === "sidebar" ? extractHeadings(page.content) : [];
|
||||
const hasSidebar = headings.length > 0;
|
||||
const hasLeftSidebar = headings.length > 0;
|
||||
// Check if right sidebar is enabled (only when explicitly set in frontmatter)
|
||||
const hasRightSidebar = siteConfig.rightSidebar.enabled && page.rightSidebar === true;
|
||||
const hasAnySidebar = hasLeftSidebar || hasRightSidebar;
|
||||
|
||||
return (
|
||||
<div className={`post-page ${hasSidebar ? "post-page-with-sidebar" : ""}`}>
|
||||
<nav className={`post-nav ${hasSidebar ? "post-nav-with-sidebar" : ""}`}>
|
||||
<div className={`post-page ${hasAnySidebar ? "post-page-with-sidebar" : ""}`}>
|
||||
<nav className={`post-nav ${hasAnySidebar ? "post-nav-with-sidebar" : ""}`}>
|
||||
<button onClick={() => navigate("/")} className="back-button">
|
||||
<ArrowLeft size={16} />
|
||||
<span>Back</span>
|
||||
</button>
|
||||
{/* CopyPageDropdown in nav */}
|
||||
<CopyPageDropdown
|
||||
title={page.title}
|
||||
content={page.content}
|
||||
url={window.location.href}
|
||||
slug={page.slug}
|
||||
description={page.excerpt}
|
||||
/>
|
||||
{/* Only show CopyPageDropdown in nav if right sidebar is disabled */}
|
||||
{!hasRightSidebar && (
|
||||
<CopyPageDropdown
|
||||
title={page.title}
|
||||
content={page.content}
|
||||
url={window.location.href}
|
||||
slug={page.slug}
|
||||
description={page.excerpt}
|
||||
/>
|
||||
)}
|
||||
</nav>
|
||||
|
||||
<div className={hasSidebar ? "post-content-with-sidebar" : ""}>
|
||||
<div className={hasAnySidebar ? "post-content-with-sidebar" : ""}>
|
||||
{/* Left sidebar - TOC */}
|
||||
{hasSidebar && (
|
||||
{hasLeftSidebar && (
|
||||
<aside className="post-sidebar-wrapper post-sidebar-left">
|
||||
<PageSidebar headings={headings} activeId={location.hash.slice(1)} />
|
||||
</aside>
|
||||
)}
|
||||
|
||||
{/* Main content */}
|
||||
<article className={`post-article ${hasSidebar ? "post-article-with-sidebar" : ""}`}>
|
||||
<article className={`post-article ${hasAnySidebar ? "post-article-with-sidebar" : ""}`}>
|
||||
<header className="post-header">
|
||||
<h1 className="post-title">{page.title}</h1>
|
||||
{/* Author avatar and name for pages (optional) */}
|
||||
@@ -237,6 +244,17 @@ export default function Post() {
|
||||
|
||||
<BlogPost content={page.content} />
|
||||
</article>
|
||||
|
||||
{/* Right sidebar - CopyPageDropdown */}
|
||||
{hasRightSidebar && (
|
||||
<RightSidebar
|
||||
title={page.title}
|
||||
content={page.content}
|
||||
url={window.location.href}
|
||||
slug={page.slug}
|
||||
description={page.excerpt}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -276,38 +294,43 @@ export default function Post() {
|
||||
|
||||
// Extract headings for sidebar TOC (only for posts with layout: "sidebar")
|
||||
const headings = post?.layout === "sidebar" ? extractHeadings(post.content) : [];
|
||||
const hasSidebar = headings.length > 0;
|
||||
const hasLeftSidebar = headings.length > 0;
|
||||
// Check if right sidebar is enabled (only when explicitly set in frontmatter)
|
||||
const hasRightSidebar = siteConfig.rightSidebar.enabled && post.rightSidebar === true;
|
||||
const hasAnySidebar = hasLeftSidebar || hasRightSidebar;
|
||||
|
||||
// Render blog post with full metadata
|
||||
return (
|
||||
<div className={`post-page ${hasSidebar ? "post-page-with-sidebar" : ""}`}>
|
||||
<nav className={`post-nav ${hasSidebar ? "post-nav-with-sidebar" : ""}`}>
|
||||
<div className={`post-page ${hasAnySidebar ? "post-page-with-sidebar" : ""}`}>
|
||||
<nav className={`post-nav ${hasAnySidebar ? "post-nav-with-sidebar" : ""}`}>
|
||||
<button onClick={() => navigate("/")} className="back-button">
|
||||
<ArrowLeft size={16} />
|
||||
<span>Back</span>
|
||||
</button>
|
||||
{/* Copy page dropdown for sharing with full metadata */}
|
||||
<CopyPageDropdown
|
||||
title={post.title}
|
||||
content={post.content}
|
||||
url={window.location.href}
|
||||
slug={post.slug}
|
||||
description={post.description}
|
||||
date={post.date}
|
||||
tags={post.tags}
|
||||
readTime={post.readTime}
|
||||
/>
|
||||
{/* Only show CopyPageDropdown in nav if right sidebar is disabled */}
|
||||
{!hasRightSidebar && (
|
||||
<CopyPageDropdown
|
||||
title={post.title}
|
||||
content={post.content}
|
||||
url={window.location.href}
|
||||
slug={post.slug}
|
||||
description={post.description}
|
||||
date={post.date}
|
||||
tags={post.tags}
|
||||
readTime={post.readTime}
|
||||
/>
|
||||
)}
|
||||
</nav>
|
||||
|
||||
<div className={hasSidebar ? "post-content-with-sidebar" : ""}>
|
||||
<div className={hasAnySidebar ? "post-content-with-sidebar" : ""}>
|
||||
{/* Left sidebar - TOC */}
|
||||
{hasSidebar && (
|
||||
{hasLeftSidebar && (
|
||||
<aside className="post-sidebar-wrapper post-sidebar-left">
|
||||
<PageSidebar headings={headings} activeId={location.hash.slice(1)} />
|
||||
</aside>
|
||||
)}
|
||||
|
||||
<article className={`post-article ${hasSidebar ? "post-article-with-sidebar" : ""}`}>
|
||||
<article className={`post-article ${hasAnySidebar ? "post-article-with-sidebar" : ""}`}>
|
||||
<header className="post-header">
|
||||
<h1 className="post-title">{post.title}</h1>
|
||||
<div className="post-meta-header">
|
||||
@@ -409,6 +432,20 @@ export default function Post() {
|
||||
)}
|
||||
</footer>
|
||||
</article>
|
||||
|
||||
{/* Right sidebar - CopyPageDropdown */}
|
||||
{hasRightSidebar && (
|
||||
<RightSidebar
|
||||
title={post.title}
|
||||
content={post.content}
|
||||
url={window.location.href}
|
||||
slug={post.slug}
|
||||
description={post.description}
|
||||
date={post.date}
|
||||
tags={post.tags}
|
||||
readTime={post.readTime}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -39,6 +39,7 @@ const POST_FIELDS = [
|
||||
{ name: "authorName", required: false, example: '"Jane Doe"' },
|
||||
{ name: "authorImage", required: false, example: '"/images/authors/jane.png"' },
|
||||
{ name: "layout", required: false, example: '"sidebar"' },
|
||||
{ name: "rightSidebar", required: false, example: "true" },
|
||||
];
|
||||
|
||||
// Frontmatter field definitions for pages
|
||||
@@ -55,6 +56,7 @@ const PAGE_FIELDS = [
|
||||
{ name: "authorName", required: false, example: '"Jane Doe"' },
|
||||
{ name: "authorImage", required: false, example: '"/images/authors/jane.png"' },
|
||||
{ name: "layout", required: false, example: '"sidebar"' },
|
||||
{ name: "rightSidebar", required: false, example: "true" },
|
||||
];
|
||||
|
||||
// Generate frontmatter template based on content type
|
||||
|
||||
@@ -871,7 +871,20 @@ body {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Sidebar wrapper - docs-style with alt background and borders */
|
||||
/* Three-column layout when right sidebar is enabled */
|
||||
@media (min-width: 1135px) {
|
||||
.post-content-with-sidebar:has(.post-sidebar-right) {
|
||||
grid-template-columns: 240px 1fr 280px;
|
||||
}
|
||||
|
||||
/* Adjust main content padding when right sidebar exists */
|
||||
.post-content-with-sidebar:has(.post-sidebar-right)
|
||||
.post-article-with-sidebar {
|
||||
padding-right: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Left sidebar wrapper - docs-style with alt background and borders */
|
||||
.post-sidebar-wrapper {
|
||||
position: sticky;
|
||||
top: 80px;
|
||||
@@ -884,10 +897,11 @@ body {
|
||||
background-color: var(--bg-sidebar);
|
||||
margin-left: -24px;
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
padding-top: 24px;
|
||||
padding-bottom: 24px;
|
||||
margin-top: -24px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
/* Extend background to fill height */
|
||||
min-height: calc(100vh - 80px);
|
||||
/* Top border using CSS variable for theme consistency */
|
||||
@@ -903,10 +917,50 @@ body {
|
||||
}
|
||||
|
||||
/* Left sidebar - flush left with internal padding */
|
||||
.post-sidebar-left {
|
||||
/* All styles inherited from .post-sidebar-wrapper */
|
||||
|
||||
/* Right sidebar - complete styles based on left sidebar wrapper */
|
||||
.post-sidebar-right {
|
||||
position: sticky;
|
||||
top: 80px;
|
||||
align-self: flex-start;
|
||||
max-height: calc(100vh - 100px);
|
||||
overflow-y: auto;
|
||||
/* Hide scrollbar while keeping scroll functionality */
|
||||
-ms-overflow-style: none; /* IE */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
background-color: var(--bg-sidebar);
|
||||
margin-right: -24px;
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
padding-top: 24px;
|
||||
padding-bottom: 24px;
|
||||
margin-top: -24px;
|
||||
border-radius: 6px;
|
||||
/* Extend background to fill height */
|
||||
min-height: calc(100vh - 80px);
|
||||
/* Top border using CSS variable for theme consistency */
|
||||
border-top: 1px solid var(--border-sidebar);
|
||||
padding-right: 24px;
|
||||
/* Left border using box-shadow for consistent 1px width regardless of scrollbar */
|
||||
box-shadow: inset 1px 0 0 var(--border-sidebar);
|
||||
}
|
||||
|
||||
/* Hide scrollbar for Chrome/Safari/Edge */
|
||||
.post-sidebar-right::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.right-sidebar-content {
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
/* Hide right sidebar below 1135px */
|
||||
@media (max-width: 1134px) {
|
||||
.post-sidebar-right {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Content area - flexible width with left padding for gap from sidebar */
|
||||
@@ -1040,11 +1094,16 @@ body {
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
/* Hide sidebar on mobile - it's now in the hamburger menu */
|
||||
/* Hide sidebars on mobile - left sidebar is now in the hamburger menu */
|
||||
.post-sidebar-wrapper {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Ensure right sidebar is hidden on mobile */
|
||||
.post-sidebar-right {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Reset sidebar styles for mobile (when shown in hamburger) */
|
||||
.post-sidebar-left {
|
||||
position: static;
|
||||
|
||||
Reference in New Issue
Block a user