mirror of
https://github.com/waynesutton/markdown-site.git
synced 2026-01-12 04:09:14 +00:00
feature: Social footer icons in header navigation
This commit is contained in:
@@ -955,7 +955,7 @@ Set `showFooter: false` in post/page frontmatter to hide footer on specific page
|
||||
|
||||
## Social Footer Configuration
|
||||
|
||||
Display social icons and copyright information below the main footer.
|
||||
Display social icons and copyright information below the main footer. Icons can also appear in the header.
|
||||
|
||||
### In fork-config.json
|
||||
|
||||
@@ -967,6 +967,7 @@ Display social icons and copyright information below the main footer.
|
||||
"showOnPosts": true,
|
||||
"showOnPages": true,
|
||||
"showOnBlogPage": true,
|
||||
"showInHeader": true,
|
||||
"socialLinks": [
|
||||
{
|
||||
"platform": "github",
|
||||
@@ -996,6 +997,7 @@ socialFooter: {
|
||||
showOnPosts: true,
|
||||
showOnPages: true,
|
||||
showOnBlogPage: true,
|
||||
showInHeader: true, // Show social icons in header (left of search icon)
|
||||
socialLinks: [
|
||||
{ platform: "github", url: "https://github.com/username" },
|
||||
{ platform: "twitter", url: "https://x.com/handle" },
|
||||
@@ -1010,6 +1012,10 @@ socialFooter: {
|
||||
|
||||
**Supported Platforms:** github, twitter, linkedin, instagram, youtube, tiktok, discord, website
|
||||
|
||||
**Header Social Icons:**
|
||||
|
||||
When `showInHeader: true`, social icons appear in the navigation header to the left of the search icon on desktop. This provides additional visibility for your social links while maintaining the footer placement.
|
||||
|
||||
**Frontmatter Override:**
|
||||
|
||||
Set `showSocialFooter: false` in post/page frontmatter to hide social footer on specific pages.
|
||||
|
||||
14
TASK.md
14
TASK.md
@@ -2,15 +2,25 @@
|
||||
|
||||
## To Do
|
||||
|
||||
- [ ] site confg add header icons
|
||||
- [ ] fix site confg link
|
||||
- [ ] dashboard agent nanobanno
|
||||
- [ ] npm package
|
||||
|
||||
|
||||
## Current Status
|
||||
|
||||
v2.4.0 ready. YouTube and Twitter/X embed support with domain whitelisting.
|
||||
v2.5.0 ready. Social footer icons can now display in header navigation.
|
||||
|
||||
## Completed
|
||||
|
||||
- [x] Social footer icons in header navigation
|
||||
- [x] Added `showInHeader` option to `siteConfig.socialFooter` config
|
||||
- [x] Exported `platformIcons` from SocialFooter.tsx for reuse
|
||||
- [x] Updated Layout.tsx to render social icons in header (left of search)
|
||||
- [x] Added CSS styles for `.header-social-links` and `.header-social-link`
|
||||
- [x] Added showInHeader to configure-fork.ts for automated setup
|
||||
- [x] Updated FORK_CONFIG.md, fork-config.json.example, docs.md, setup-guide.md
|
||||
|
||||
- [x] YouTube and Twitter/X embed support with domain whitelisting
|
||||
- [x] Added `ALLOWED_IFRAME_DOMAINS` constant for whitelisted domains (YouTube, Twitter/X)
|
||||
- [x] Added `iframe` to sanitize schema with allowed attributes
|
||||
|
||||
20
changelog.md
20
changelog.md
@@ -4,6 +4,26 @@ 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.5.0] - 2026-01-01
|
||||
|
||||
### Added
|
||||
|
||||
- Social footer icons in header navigation
|
||||
- New `showInHeader` option in `siteConfig.socialFooter` to display social icons in the header
|
||||
- Social icons appear left of the search icon on desktop viewports
|
||||
- Uses same icons and links as the social footer component
|
||||
- Configurable via siteConfig, FORK_CONFIG.md, and fork-config.json
|
||||
- Disabled by default (set `showInHeader: true` to enable)
|
||||
|
||||
### Technical
|
||||
|
||||
- Exported `platformIcons` from `SocialFooter.tsx` for reuse in Layout component
|
||||
- Added social icon rendering in `Layout.tsx` header controls
|
||||
- Added `.header-social-links` and `.header-social-link` CSS styles in `global.css`
|
||||
- Updated `SocialFooterConfig` interface with `showInHeader: boolean`
|
||||
- Added socialFooter support to `configure-fork.ts` script
|
||||
- Updated documentation: FORK_CONFIG.md, fork-config.json.example, docs.md, setup-guide.md
|
||||
|
||||
## [2.4.0] - 2026-01-01
|
||||
|
||||
### Added
|
||||
|
||||
@@ -10,6 +10,28 @@ layout: "sidebar"
|
||||
All notable changes to this project.
|
||||

|
||||
|
||||
## v2.5.0
|
||||
|
||||
Released January 1, 2026
|
||||
|
||||
**Social footer icons in header navigation**
|
||||
|
||||
- New `showInHeader` option in `siteConfig.socialFooter` to display social icons in the header
|
||||
- Social icons appear left of the search icon on desktop viewports
|
||||
- Uses same icons and links as the social footer component
|
||||
- Configurable via siteConfig, FORK_CONFIG.md, and fork-config.json
|
||||
- Set `showInHeader: true` in socialFooter config to enable
|
||||
|
||||
**Technical details:**
|
||||
|
||||
- Exported `platformIcons` from `src/components/SocialFooter.tsx` for reuse
|
||||
- Added social icon rendering in `src/components/Layout.tsx` header controls
|
||||
- Added `.header-social-links` and `.header-social-link` CSS styles
|
||||
- Updated `SocialFooterConfig` interface with `showInHeader: boolean`
|
||||
- Added socialFooter support to `scripts/configure-fork.ts`
|
||||
|
||||
Updated files: `src/config/siteConfig.ts`, `src/components/SocialFooter.tsx`, `src/components/Layout.tsx`, `src/styles/global.css`, `scripts/configure-fork.ts`, `FORK_CONFIG.md`, `fork-config.json.example`, `public/raw/docs.md`, `public/raw/setup-guide.md`, `files.md`, `TASK.md`, `changelog.md`, `content/pages/changelog-page.md`
|
||||
|
||||
## v2.4.0
|
||||
|
||||
Released January 1, 2026
|
||||
|
||||
@@ -4,7 +4,8 @@ slug: "docs"
|
||||
published: true
|
||||
order: 0
|
||||
layout: "sidebar"
|
||||
aiChat: true
|
||||
aiChat: false
|
||||
rightSidebar: true
|
||||
showFooter: true
|
||||
---
|
||||
|
||||
|
||||
4
files.md
4
files.md
@@ -56,7 +56,7 @@ A brief description of each file in the codebase.
|
||||
|
||||
| File | Description |
|
||||
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `Layout.tsx` | Page wrapper with logo in header (top-left), 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. Logo reads from siteConfig.innerPageLogo |
|
||||
| `Layout.tsx` | Page wrapper with logo in header (top-left), 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. Logo reads from siteConfig.innerPageLogo. Displays social icons in header (left of search) when siteConfig.socialFooter.showInHeader is true. |
|
||||
| `ThemeToggle.tsx` | Theme switcher (dark/light/tan/cloud) |
|
||||
| `PostList.tsx` | Year-grouped blog post list or card grid (supports list/cards view modes, columns prop for 2/3 column grids, showExcerpts prop to control excerpt visibility) |
|
||||
| `BlogHeroCard.tsx` | Hero card component for the first blogFeatured post on blog page. Displays landscape image, tags, date, title, excerpt, author info, and read more link |
|
||||
@@ -75,7 +75,7 @@ A brief description of each file in the codebase.
|
||||
| `AIChatView.tsx` | AI chat interface component (Agent) using Anthropic Claude API. Supports per-page chat history, page content context, markdown rendering, and copy functionality. Used in Write page (replaces textarea when enabled) and optionally in RightSidebar. Requires ANTHROPIC_API_KEY environment variable in Convex. System prompt configurable via CLAUDE_PROMPT_STYLE, CLAUDE_PROMPT_COMMUNITY, CLAUDE_PROMPT_RULES, or CLAUDE_SYSTEM_PROMPT environment variables. Includes error handling for missing API keys. |
|
||||
| `NewsletterSignup.tsx` | Newsletter signup form component for email-only subscriptions. Displays configurable title/description, validates email, and submits to Convex. Shows on home, blog page, and posts based on siteConfig.newsletter settings. Supports frontmatter override via newsletter: true/false. Includes honeypot field for bot protection. |
|
||||
| `ContactForm.tsx` | Contact form component with name, email, and message fields. Displays when contactForm: true in frontmatter. Submits to Convex which sends email via AgentMail to configured recipient. Requires AGENTMAIL_API_KEY and AGENTMAIL_INBOX environment variables. Includes honeypot field for bot protection. |
|
||||
| `SocialFooter.tsx` | Social footer component with social icons on left (GitHub, Twitter/X, LinkedIn, Instagram, YouTube, TikTok, Discord, Website) and copyright on right. Configurable via siteConfig.socialFooter. Shows below main footer on homepage, blog posts, and pages. Supports frontmatter override via showSocialFooter: true/false. Auto-updates copyright year. |
|
||||
| `SocialFooter.tsx` | Social footer component with social icons on left (GitHub, Twitter/X, LinkedIn, Instagram, YouTube, TikTok, Discord, Website) and copyright on right. Configurable via siteConfig.socialFooter. Shows below main footer on homepage, blog posts, and pages. Supports frontmatter override via showSocialFooter: true/false. Auto-updates copyright year. Exports `platformIcons` for reuse in header. |
|
||||
|
||||
### Context (`src/context/`)
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
"showOnPosts": true,
|
||||
"showOnPages": true,
|
||||
"showOnBlogPage": true,
|
||||
"showInHeader": true,
|
||||
"socialLinks": [
|
||||
{
|
||||
"platform": "github",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
Type: page
|
||||
Date: 2026-01-01
|
||||
Date: 2026-01-02
|
||||
---
|
||||
|
||||
An open-source publishing framework built for AI agents and developers to ship websites, docs, or blogs.. Write markdown, sync from the terminal. Your content is instantly available to browsers, LLMs, and AI agents. Built on Convex and Netlify.
|
||||
|
||||
@@ -2,12 +2,34 @@
|
||||
|
||||
---
|
||||
Type: page
|
||||
Date: 2026-01-01
|
||||
Date: 2026-01-02
|
||||
---
|
||||
|
||||
All notable changes to this project.
|
||||

|
||||
|
||||
## v2.5.0
|
||||
|
||||
Released January 1, 2026
|
||||
|
||||
**Social footer icons in header navigation**
|
||||
|
||||
- New `showInHeader` option in `siteConfig.socialFooter` to display social icons in the header
|
||||
- Social icons appear left of the search icon on desktop viewports
|
||||
- Uses same icons and links as the social footer component
|
||||
- Configurable via siteConfig, FORK_CONFIG.md, and fork-config.json
|
||||
- Set `showInHeader: true` in socialFooter config to enable
|
||||
|
||||
**Technical details:**
|
||||
|
||||
- Exported `platformIcons` from `src/components/SocialFooter.tsx` for reuse
|
||||
- Added social icon rendering in `src/components/Layout.tsx` header controls
|
||||
- Added `.header-social-links` and `.header-social-link` CSS styles
|
||||
- Updated `SocialFooterConfig` interface with `showInHeader: boolean`
|
||||
- Added socialFooter support to `scripts/configure-fork.ts`
|
||||
|
||||
Updated files: `src/config/siteConfig.ts`, `src/components/SocialFooter.tsx`, `src/components/Layout.tsx`, `src/styles/global.css`, `scripts/configure-fork.ts`, `FORK_CONFIG.md`, `fork-config.json.example`, `public/raw/docs.md`, `public/raw/setup-guide.md`, `files.md`, `TASK.md`, `changelog.md`, `content/pages/changelog-page.md`
|
||||
|
||||
## v2.4.0
|
||||
|
||||
Released January 1, 2026
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
Type: page
|
||||
Date: 2026-01-01
|
||||
Date: 2026-01-02
|
||||
---
|
||||
|
||||
You found the contact page. Nice
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
Type: page
|
||||
Date: 2026-01-01
|
||||
Date: 2026-01-02
|
||||
---
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
Type: page
|
||||
Date: 2026-01-01
|
||||
Date: 2026-01-02
|
||||
---
|
||||
|
||||
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).
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
Type: page
|
||||
Date: 2026-01-01
|
||||
Date: 2026-01-02
|
||||
---
|
||||
|
||||
An open-source publishing framework built for AI agents and developers to ship **[docs](/docs)**, or **[blogs](/blog)** or **[websites](/)**.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
Type: page
|
||||
Date: 2026-01-01
|
||||
Date: 2026-01-02
|
||||
---
|
||||
|
||||
# Newsletter Demo Page
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
Type: page
|
||||
Date: 2026-01-01
|
||||
Date: 2026-01-02
|
||||
---
|
||||
|
||||
This markdown framework is open source and built to be extended. Here is what ships out of the box.
|
||||
|
||||
@@ -83,6 +83,22 @@ interface ForkConfig {
|
||||
slug?: string;
|
||||
originalHomeRoute?: string;
|
||||
};
|
||||
socialFooter?: {
|
||||
enabled?: boolean;
|
||||
showOnHomepage?: boolean;
|
||||
showOnPosts?: boolean;
|
||||
showOnPages?: boolean;
|
||||
showOnBlogPage?: boolean;
|
||||
showInHeader?: boolean;
|
||||
socialLinks?: Array<{
|
||||
platform: string;
|
||||
url: string;
|
||||
}>;
|
||||
copyright?: {
|
||||
siteName?: string;
|
||||
showYear?: boolean;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// Get project root directory
|
||||
@@ -318,6 +334,58 @@ function updateSiteConfig(config: ForkConfig): void {
|
||||
`contentPath: "${gitHubRepoContentPath}", // Path to raw markdown files`,
|
||||
);
|
||||
|
||||
// Update socialFooter if specified
|
||||
if (config.socialFooter) {
|
||||
if (config.socialFooter.enabled !== undefined) {
|
||||
content = content.replace(
|
||||
/socialFooter: \{[\s\S]*?enabled: (?:true|false),\s*\/\/ Global toggle for social footer/,
|
||||
`socialFooter: {\n enabled: ${config.socialFooter.enabled}, // Global toggle for social footer`,
|
||||
);
|
||||
}
|
||||
if (config.socialFooter.showOnHomepage !== undefined) {
|
||||
content = content.replace(
|
||||
/showOnHomepage: (?:true|false),\s*\/\/ Show social footer on homepage/,
|
||||
`showOnHomepage: ${config.socialFooter.showOnHomepage}, // Show social footer on homepage`,
|
||||
);
|
||||
}
|
||||
if (config.socialFooter.showOnPosts !== undefined) {
|
||||
content = content.replace(
|
||||
/showOnPosts: (?:true|false),\s*\/\/ Default: show social footer on blog posts/,
|
||||
`showOnPosts: ${config.socialFooter.showOnPosts}, // Default: show social footer on blog posts`,
|
||||
);
|
||||
}
|
||||
if (config.socialFooter.showOnPages !== undefined) {
|
||||
content = content.replace(
|
||||
/showOnPages: (?:true|false),\s*\/\/ Default: show social footer on static pages/,
|
||||
`showOnPages: ${config.socialFooter.showOnPages}, // Default: show social footer on static pages`,
|
||||
);
|
||||
}
|
||||
if (config.socialFooter.showOnBlogPage !== undefined) {
|
||||
content = content.replace(
|
||||
/showOnBlogPage: (?:true|false),\s*\/\/ Show social footer on \/blog page/,
|
||||
`showOnBlogPage: ${config.socialFooter.showOnBlogPage}, // Show social footer on /blog page`,
|
||||
);
|
||||
}
|
||||
if (config.socialFooter.showInHeader !== undefined) {
|
||||
content = content.replace(
|
||||
/showInHeader: (?:true|false),\s*\/\/ Show social icons in header/,
|
||||
`showInHeader: ${config.socialFooter.showInHeader}, // Show social icons in header`,
|
||||
);
|
||||
}
|
||||
if (config.socialFooter.copyright?.siteName) {
|
||||
content = content.replace(
|
||||
/siteName: ['"].*?['"],\s*\/\/ Update with your site\/company name/,
|
||||
`siteName: "${config.socialFooter.copyright.siteName}", // Update with your site/company name`,
|
||||
);
|
||||
}
|
||||
if (config.socialFooter.copyright?.showYear !== undefined) {
|
||||
content = content.replace(
|
||||
/showYear: (?:true|false),\s*\/\/ Auto-updates to current year/,
|
||||
`showYear: ${config.socialFooter.copyright.showYear}, // Auto-updates to current year`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(filePath, content, "utf-8");
|
||||
console.log(` Updated: src/config/siteConfig.ts`);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import MobileMenu, { HamburgerButton } from "./MobileMenu";
|
||||
import ScrollToTop, { ScrollToTopConfig } from "./ScrollToTop";
|
||||
import { useSidebarOptional } from "../context/SidebarContext";
|
||||
import siteConfig from "../config/siteConfig";
|
||||
import { platformIcons } from "./SocialFooter";
|
||||
|
||||
// Scroll-to-top configuration - enabled by default
|
||||
// Customize threshold (pixels) to control when button appears
|
||||
@@ -190,6 +191,26 @@ export default function Layout({ children }: LayoutProps) {
|
||||
|
||||
{/* Desktop search and theme (visible on desktop only) */}
|
||||
<div className="desktop-controls desktop-only">
|
||||
{/* Social icons in header (if enabled) */}
|
||||
{siteConfig.socialFooter?.enabled && siteConfig.socialFooter?.showInHeader && (
|
||||
<div className="header-social-links">
|
||||
{siteConfig.socialFooter.socialLinks.map((link) => {
|
||||
const IconComponent = platformIcons[link.platform];
|
||||
return (
|
||||
<a
|
||||
key={link.platform}
|
||||
href={link.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="header-social-link"
|
||||
aria-label={`Follow on ${link.platform}`}
|
||||
>
|
||||
<IconComponent size={18} weight="regular" />
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{/* Search button with icon */}
|
||||
<button
|
||||
onClick={openSearch}
|
||||
|
||||
@@ -9,10 +9,12 @@ import {
|
||||
TiktokLogo,
|
||||
DiscordLogo,
|
||||
Globe,
|
||||
type Icon,
|
||||
} from "@phosphor-icons/react";
|
||||
|
||||
// Map platform names to Phosphor icons
|
||||
const platformIcons: Record<SocialLink["platform"], React.ComponentType<{ size?: number; weight?: "regular" | "bold" | "fill" }>> = {
|
||||
// Exported for reuse in header social icons
|
||||
export const platformIcons: Record<SocialLink["platform"], Icon> = {
|
||||
github: GithubLogo,
|
||||
twitter: TwitterLogo,
|
||||
linkedin: LinkedinLogo,
|
||||
|
||||
@@ -226,6 +226,7 @@ export interface SocialFooterConfig {
|
||||
showOnPosts: boolean; // Default: show social footer on blog posts
|
||||
showOnPages: boolean; // Default: show social footer on static pages
|
||||
showOnBlogPage: boolean; // Show social footer on /blog page
|
||||
showInHeader: boolean; // Show social icons in header (left of search icon)
|
||||
socialLinks: SocialLink[]; // Array of social links to display
|
||||
copyright: {
|
||||
siteName: string; // Site name or company name displayed in copyright
|
||||
@@ -491,7 +492,7 @@ export const siteConfig: SiteConfig = {
|
||||
},
|
||||
|
||||
// Footer configuration
|
||||
// Footer content is loaded from content/pages/footer.md (synced via npm run sync)
|
||||
// Footer content is loaded from content/pages/footer.md (synced via npm run sync)
|
||||
// Use showFooter: false in frontmatter to hide footer on specific posts/pages
|
||||
footer: {
|
||||
enabled: true, // Global toggle for footer
|
||||
@@ -568,6 +569,7 @@ export const siteConfig: SiteConfig = {
|
||||
showOnPosts: true, // Default: show social footer on blog posts
|
||||
showOnPages: true, // Default: show social footer on static pages
|
||||
showOnBlogPage: true, // Show social footer on /blog page
|
||||
showInHeader: true, // Show social icons in header (left of search icon)
|
||||
socialLinks: [
|
||||
{
|
||||
platform: "github",
|
||||
|
||||
@@ -391,6 +391,31 @@ body {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* Header social links (shown left of search when enabled) */
|
||||
.header-social-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-right: 8px;
|
||||
padding-right: 8px;
|
||||
border-right: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.header-social-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--text-secondary);
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
transition: color 0.2s ease, background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.header-social-link:hover {
|
||||
color: var(--text-primary);
|
||||
background-color: var(--hover-bg);
|
||||
}
|
||||
|
||||
/* Page navigation links (About, Projects, Contact, etc.) */
|
||||
.page-nav {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user