From e9a11640735c1ef73648978c737ad8a2a2aecb9f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 10 Jan 2026 13:26:55 +0000 Subject: [PATCH 1/3] Initial plan From a49ddb065a3eb7428d1703ea0cd490b7ad7b4686 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 10 Jan 2026 13:32:56 +0000 Subject: [PATCH 2/3] Initial plan for consistent header implementation Co-authored-by: CarwilB <54286746+CarwilB@users.noreply.github.com> --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index ced27229a80..b3e09c8a0c1 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "entities": "^4.5.0", "lodash": "^4.17.21", "numeral": "^2.0.6", - "pagefind": "^0.10.6", "parse-domain": "^5.0.0", "sentiment": "^5.0.2", "sqlite3": "^5.1.6", From 98e096a282e9d27c4afce5218360480c3605ee72 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 10 Jan 2026 13:37:45 +0000 Subject: [PATCH 3/3] Implement consistent header across all pages with navigation and accessibility Co-authored-by: CarwilB <54286746+CarwilB@users.noreply.github.com> --- _includes/header.11ty.js | 29 ++++++++ _includes/layout.11ty.js | 50 ++++++++------ assets/style.css | 146 ++++++++++++++++++++++++++++++++++++++- docs/header-component.md | 71 +++++++++++++++++++ 4 files changed, 272 insertions(+), 24 deletions(-) create mode 100644 _includes/header.11ty.js create mode 100644 docs/header-component.md diff --git a/_includes/header.11ty.js b/_includes/header.11ty.js new file mode 100644 index 00000000000..41c2ca14207 --- /dev/null +++ b/_includes/header.11ty.js @@ -0,0 +1,29 @@ +const metadata = require("../_data/metadata.js"); + +module.exports = function(data) { + // Determine if this is the current page for navigation highlighting + const isHome = data.page.url === "/" || data.page.fileSlug === "index"; + const isRecent = data.page.url.startsWith("/recent"); + const isPopular = data.page.url.startsWith("/popular"); + + return ` + + `; +}; diff --git a/_includes/layout.11ty.js b/_includes/layout.11ty.js index 0698b9cfa5a..6a7c956f212 100644 --- a/_includes/layout.11ty.js +++ b/_includes/layout.11ty.js @@ -1,5 +1,6 @@ const dataSource = require("../src/DataSource"); const metadata = require("../_data/metadata.js"); +const header = require("./header.11ty.js"); module.exports = async function(data) { let titleTweetNumberStr = ""; @@ -38,6 +39,9 @@ module.exports = async function(data) { // Check if this is the index page and should use sidebar layout const isIndexPage = data.page.url === "/" || data.page.fileSlug === "index.11ty" || data.page.fileSlug === "index"; + + // Generate the consistent header + const headerHtml = header.call(this, data); if (isIndexPage) { // Sidebar layout for index page @@ -55,16 +59,19 @@ module.exports = async function(data) { - -
-
- ${data.content} -
- + ${headerHtml} +
+ +
+
+ ${data.content} +
+ +
`; @@ -90,19 +97,16 @@ module.exports = async function(data) { ` : ""} -
-

${data.metadata.username}'s avatar${data.metadata.username}'s Twitter Archive${titleTweetNumberStr}

- ${!data.hideHeaderTweetsLink ? ``: ""} -
-
- ${data.content} -
- ${navHtml} - + ${headerHtml} +
+
+ ${data.content} +
+ ${navHtml} + +
`; }; diff --git a/assets/style.css b/assets/style.css index 3dbe92e762a..0961571258b 100644 --- a/assets/style.css +++ b/assets/style.css @@ -10,7 +10,7 @@ body { margin: 0; padding: 0; display: flex; - flex-direction: row; + flex-direction: column; } @media (max-width: 48em) { /* 768px */ body { @@ -459,4 +459,148 @@ img.tweet-media-og { margin: 0 auto; max-width: 40rem; /* 640px /16 */ font-size: 1.25em; /* 20px /16 */ +} + +/* Site Header */ +.site-header { + background-color: #fff; + border-bottom: 2px solid #ddd; + padding: 1rem 2rem; + position: sticky; + top: 0; + z-index: 100; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} +@media (max-width: 48em) { /* 768px */ + .site-header { + padding: 0.75rem 1rem; + position: static; + } +} + +.site-header-content { + max-width: 70em; + margin: 0 auto; + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 1rem; +} + +.site-title { + margin: 0; + font-size: 1.25rem; + font-weight: 600; + line-height: 1.2; +} + +.site-title a { + display: flex; + align-items: center; + gap: 0.5rem; + text-decoration: none; + color: #1C4A1D; +} + +.site-title a:hover { + text-decoration: underline; +} + +.site-avatar { + border-radius: 50%; + flex-shrink: 0; +} + +.site-title-text { + display: inline-block; +} + +@media (max-width: 32em) { /* 512px */ + .site-title { + font-size: 1rem; + } + .site-avatar { + width: 32px; + height: 32px; + } +} + +.site-nav { + flex-shrink: 0; +} + +.site-nav-list { + display: flex; + list-style: none; + margin: 0; + padding: 0; + gap: 1.5rem; + align-items: center; +} + +@media (max-width: 48em) { /* 768px */ + .site-nav-list { + gap: 1rem; + flex-wrap: wrap; + } +} + +@media (max-width: 32em) { /* 512px */ + .site-nav-list { + gap: 0.75rem; + font-size: 0.9rem; + } +} + +.site-nav-list a { + text-decoration: none; + color: #1C4A1D; + font-weight: 500; + padding: 0.25rem 0.5rem; + border-radius: 4px; + transition: background-color 0.2s; +} + +.site-nav-list a:hover { + background-color: #f5f5f5; + text-decoration: underline; +} + +.site-nav-list a[aria-current="page"] { + background-color: #17bf63; + color: #fff; +} + +.site-nav-list a[aria-current="page"]:hover { + background-color: #15a957; + text-decoration: none; +} + +/* Page Container */ +.page-container { + display: flex; + flex: 1; + flex-direction: row; +} + +@media (max-width: 48em) { /* 768px */ + .page-container { + flex-direction: column; + } +} + +/* Single column layout (no sidebar) */ +.page-container-single { + flex-direction: column; + max-width: 70em; + margin: 0 auto; + padding: 2rem; + width: 100%; +} + +@media (max-width: 48em) { /* 768px */ + .page-container-single { + padding: 1rem; + } } \ No newline at end of file diff --git a/docs/header-component.md b/docs/header-component.md new file mode 100644 index 00000000000..98129ff08e2 --- /dev/null +++ b/docs/header-component.md @@ -0,0 +1,71 @@ +# Site Header Component + +## Overview + +The site header provides consistent navigation and branding across all pages of the tweetback Twitter Archive. + +## Features + +- **Consistent Branding**: Logo with avatar and site title appears on every page +- **Primary Navigation**: Quick access to Home, Recent, Popular pages, and external website link +- **Accessibility**: Proper ARIA labels, semantic HTML, and keyboard navigation support +- **Responsive Design**: Adapts to mobile and desktop viewports +- **Active Page Indication**: Current page is highlighted in the navigation + +## Implementation + +The header is implemented as a reusable component in `_includes/header.11ty.js` and is automatically included in the main layout (`_includes/layout.11ty.js`). + +### File Structure + +``` +_includes/ +├── header.11ty.js # Header component +└── layout.11ty.js # Main layout that includes the header +``` + +### Navigation Items + +The header includes the following navigation links: + +1. **Home** - Links to the homepage (/) +2. **Recent** - Links to recent tweets page (/recent/) +3. **Popular** - Links to popular tweets page (/popular/) +4. **External Link** - Configurable link to user's main website (from metadata.js) + +### Styling + +Header styles are defined in `assets/style.css` with the following CSS classes: + +- `.site-header` - Main header container +- `.site-header-content` - Content wrapper with max-width +- `.site-title` - Logo and title +- `.site-avatar` - User avatar image +- `.site-nav` - Navigation container +- `.site-nav-list` - Navigation list +- `[aria-current="page"]` - Active page indicator + +### Customization + +To customize the header: + +1. **Change Logo/Avatar**: Update the `avatar` property in `_data/metadata.js` +2. **Modify Navigation Links**: Edit the navigation structure in `_includes/header.11ty.js` +3. **Adjust Styling**: Modify the `.site-header` styles in `assets/style.css` +4. **Add New Navigation Items**: Add new list items to the `.site-nav-list` in `header.11ty.js` + +### Accessibility Features + +- Semantic HTML5 `
` and `