Eleventy theme for Indiekit-powered IndieWeb blogs
  • Nunjucks 76.3%
  • JavaScript 19.7%
  • CSS 4%
Find a file
Ricardo de043020ac feat: add RSS per-category feed template, discovery links, and WebSub notifications
- Create category-feed.njk (RSS 2.0 pagination template)
- Add conditional <link rel="alternate"> tags for category pages in base.njk
- Extend WebSub hub notifications to include per-category feed URLs
2026-02-24 22:45:14 +01:00
_data feat: add Markdown for Agents — serve clean Markdown to AI agents 2026-02-24 20:24:06 +01:00
_includes feat: add RSS per-category feed template, discovery links, and WebSub notifications 2026-02-24 22:45:14 +01:00
css fix: use side-specific border color on post-list items 2026-02-24 17:21:02 +01:00
docs/plans docs: add per-category feeds implementation plan 2026-02-24 22:37:00 +01:00
images fix: multiple frontend issues 2026-01-28 15:08:01 +01:00
js fix: align client-side webmention selectors with build-time HTML 2026-02-23 11:02:32 +01:00
lib feat: add unfurl cards to blog page and homepage recent posts 2026-02-20 16:10:25 +01:00
.gitignore fix: pagefind output directory to match template references 2026-02-18 17:31:00 +01:00
404.njk fix: load pagefind once in base layout, eliminate duplicate scripts 2026-02-13 10:50:32 +01:00
about.njk fix: disable about.njk completely with permalink: false 2026-02-02 13:08:42 +01:00
articles.njk feat: harmonize blog views with homepage UI/UX 2026-02-24 16:58:46 +01:00
blog.njk feat: harmonize blog views with homepage UI/UX 2026-02-24 16:58:46 +01:00
blogroll.njk feat: blogroll category tabs and upcoming badge 2026-02-10 21:22:31 +01:00
bookmarks.njk feat: harmonize blog views with homepage UI/UX 2026-02-24 16:58:46 +01:00
categories-index.njk fix: declare collection dependencies for incremental builds 2026-02-18 14:42:02 +01:00
categories.njk feat: harmonize blog views with homepage UI/UX 2026-02-24 16:58:46 +01:00
category-feed-json.njk feat: add JSON Feed 1.1 per-category feed template 2026-02-24 22:41:01 +01:00
category-feed.njk feat: add RSS per-category feed template, discovery links, and WebSub notifications 2026-02-24 22:45:14 +01:00
changelog.njk feat: add changelog page and refactor footer to 4-zone grid 2026-02-12 09:16:51 +01:00
chardonsbleus.njk feat: add ChardonsBleus page with embedded Bluesky timeline 2026-02-03 09:48:47 +01:00
CLAUDE.md docs: update CLAUDE.md and README.md with comprehensive documentation 2026-02-13 18:24:14 +01:00
cv.njk feat: add configurable CV page layout with builder support 2026-02-20 15:17:32 +01:00
eleventy.config.js feat: add RSS per-category feed template, discovery links, and WebSub notifications 2026-02-24 22:45:14 +01:00
favicon.ico fix: multiple frontend issues 2026-01-28 15:08:01 +01:00
feed-json.njk fix: declare collection dependencies for incremental builds 2026-02-18 14:42:02 +01:00
feed.njk fix: declare collection dependencies for incremental builds 2026-02-18 14:42:02 +01:00
funkwhale.njk perf: skip eleventy-img processing for external cover art 2026-02-04 15:12:17 +01:00
github.njk fix: prevent overflow on mobile in featured repos commits list 2026-01-24 20:36:55 +01:00
index.njk fix: declare collection dependencies for incremental builds 2026-02-18 14:42:02 +01:00
interactions.njk feat: graceful no-JS fallback and noscript handling 2026-02-19 17:35:21 +01:00
likes.njk feat: harmonize blog views with homepage UI/UX 2026-02-24 16:58:46 +01:00
listening.njk perf: skip eleventy-img processing for external cover art 2026-02-04 15:12:17 +01:00
news.njk feat: make /news page fully client-side with real-time updates 2026-01-25 12:10:24 +01:00
notes.njk feat: harmonize blog views with homepage UI/UX 2026-02-24 16:58:46 +01:00
package-lock.json fix: vendor Alpine.js and lite-youtube-embed locally instead of CDN 2026-02-22 16:24:43 +01:00
package.json fix: vendor Alpine.js and lite-youtube-embed locally instead of CDN 2026-02-22 16:24:43 +01:00
photos.njk feat: harmonize blog views with homepage UI/UX 2026-02-24 16:58:46 +01:00
podroll.njk fix: populate podcast dropdown from sources, filter via API 2026-02-03 18:05:02 +01:00
postcss.config.js Initial commit: Indiekit Eleventy theme 2026-01-24 12:13:34 +01:00
README.md docs: update CLAUDE.md and README.md with comprehensive documentation 2026-02-13 18:24:14 +01:00
replies.njk feat: harmonize blog views with homepage UI/UX 2026-02-24 16:58:46 +01:00
reposts.njk feat: harmonize blog views with homepage UI/UX 2026-02-24 16:58:46 +01:00
search.njk feat: graceful no-JS fallback and noscript handling 2026-02-19 17:35:21 +01:00
slashes.njk fix: declare collection dependencies for incremental builds 2026-02-18 14:42:02 +01:00
tailwind.config.js feat: add unfurl shortcode for rich link preview cards 2026-02-20 11:29:11 +01:00
webmention-debug.njk feat: eliminate URL dualism — computed permalinks, conversations support 2026-02-23 09:38:30 +01:00
youtube.njk fix: comprehensive mobile responsive design audit 2026-01-24 15:48:23 +01:00

Indiekit Eleventy Theme

A modern, IndieWeb-native Eleventy theme designed for Indiekit-powered personal websites. Own your content, syndicate everywhere.

Features

IndieWeb First

This theme is built from the ground up for the IndieWeb:

  • Microformats2 markup (h-card, h-entry, h-feed, h-cite)
  • Webmentions via webmention.io (likes, reposts, replies)
  • IndieAuth with rel="me" verification
  • Micropub integration with Indiekit
  • POSSE syndication to Bluesky, Mastodon, LinkedIn, IndieNews

Full Post Type Support

All IndieWeb post types via Indiekit:

  • Articles — Long-form blog posts with titles
  • Notes — Short status updates (like tweets)
  • Photos — Image posts with multi-photo galleries
  • Bookmarks — Save and share links with descriptions
  • Likes — Appreciate others' content
  • Replies — Respond to posts across the web
  • Reposts — Share others' content
  • Pages — Root-level slash pages (/about, /now, /uses)

Homepage Builder

Dynamic, plugin-configured homepage with:

  • Hero section with avatar, bio, social links
  • Recent posts with configurable filtering
  • CV sections (experience, skills, education, projects, interests)
  • Custom HTML sections from admin UI
  • Two-column layout with configurable sidebar
  • Single-column or full-width hero layouts

Plugin Integration

Integrates with custom Indiekit endpoint plugins:

Plugin Features
@rmdes/indiekit-endpoint-homepage Dynamic homepage builder with admin UI
@rmdes/indiekit-endpoint-cv CV/resume builder with admin UI
@rmdes/indiekit-endpoint-github GitHub activity, commits, stars, featured repos
@rmdes/indiekit-endpoint-funkwhale Listening activity from Funkwhale
@rmdes/indiekit-endpoint-lastfm Scrobbles and loved tracks from Last.fm
@rmdes/indiekit-endpoint-youtube Channel info, latest videos, live status
@rmdes/indiekit-endpoint-blogroll OPML/Microsub blog aggregator with admin UI
@rmdes/indiekit-endpoint-podroll Podcast episode aggregator
@rmdes/indiekit-endpoint-rss RSS feed reader with MongoDB caching
@rmdes/indiekit-endpoint-microsub Social reader with channels and timeline

Modern Tech Stack

  • Eleventy 3.0 — Fast, flexible static site generator
  • Tailwind CSS — Utility-first styling with dark mode
  • Alpine.js — Lightweight JavaScript framework
  • Pagefind — Fast client-side search
  • Markdown-it — Rich markdown with auto-linking
  • Image optimization — Automatic WebP conversion, lazy loading

Installation

This theme is designed to be used as a Git submodule in your Indiekit deployment repository:

# In your Indiekit deployment repo
git submodule add https://github.com/rmdes/indiekit-eleventy-theme.git eleventy-site
git submodule update --init --recursive
cd eleventy-site
npm install

Why submodule? Keeps the theme neutral (no personal data), allows upstream updates, and separates theme development from deployment.

Standalone Installation

For local development or testing:

git clone https://github.com/rmdes/indiekit-eleventy-theme.git
cd indiekit-eleventy-theme
npm install

Configuration

All configuration is done via environment variables — the theme contains no hardcoded personal data.

Required Variables

# Site basics
SITE_URL="https://your-site.com"
SITE_NAME="Your Site Name"
SITE_DESCRIPTION="A short description of your site"
SITE_LOCALE="en"

# Author info (displayed in h-card)
AUTHOR_NAME="Your Name"
AUTHOR_BIO="A short bio about yourself"
AUTHOR_AVATAR="/images/avatar.jpg"

Format: Name|URL|icon,Name|URL|icon

SITE_SOCIAL="GitHub|https://github.com/you|github,Mastodon|https://mastodon.social/@you|mastodon,Bluesky|https://bsky.app/profile/you|bluesky"

Auto-generation: If SITE_SOCIAL is not set, social links are automatically generated from feed credentials (GitHub, Bluesky, Mastodon, LinkedIn).

Optional Author Fields

AUTHOR_TITLE="Software Developer"
AUTHOR_LOCATION="City, Country"
AUTHOR_LOCALITY="City"
AUTHOR_REGION="State/Province"
AUTHOR_COUNTRY="Country"
AUTHOR_ORG="Company Name"
AUTHOR_PRONOUN="they/them"
AUTHOR_CATEGORIES="IndieWeb,Open Source,Photography"  # Comma-separated
AUTHOR_KEY_URL="https://keybase.io/you/pgp_keys.asc"
AUTHOR_EMAIL="you@example.com"

Social Activity Feeds

For sidebar social activity widgets:

# Bluesky
BLUESKY_HANDLE="you.bsky.social"

# Mastodon
MASTODON_INSTANCE="https://mastodon.social"
MASTODON_USER="your-username"

Plugin API Credentials

GitHub Activity

GITHUB_USERNAME="your-username"
GITHUB_TOKEN="ghp_xxxx"  # Personal access token (optional, increases rate limit)
GITHUB_FEATURED_REPOS="user/repo1,user/repo2"  # Comma-separated

Funkwhale

FUNKWHALE_INSTANCE="https://your-instance.com"
FUNKWHALE_USERNAME="your-username"
FUNKWHALE_TOKEN="your-api-token"

YouTube

YOUTUBE_API_KEY="your-api-key"
YOUTUBE_CHANNELS="@channel1,@channel2"  # Comma-separated handles

LinkedIn

LINKEDIN_USERNAME="your-username"

Post Type Configuration

Control which post types appear in navigation:

# Option 1: Environment variable (comma-separated)
POST_TYPES="article,note,photo,bookmark"

# Option 2: JSON file (written by Indiekit or deployer)
# Create content/.indiekit/post-types.json:
# ["article", "note", "photo"]

Default: All standard post types enabled (article, note, photo, bookmark, like, reply, repost).

Directory Structure

indiekit-eleventy-theme/
├── _data/                    # Data files
│   ├── site.js              # Site config from env vars
│   ├── cv.js                # CV data from plugin
│   ├── homepageConfig.js    # Homepage layout from plugin
│   ├── enabledPostTypes.js  # Post types for navigation
│   ├── githubActivity.js    # GitHub data (Indiekit API → GitHub API fallback)
│   ├── funkwhaleActivity.js # Funkwhale listening activity
│   ├── lastfmActivity.js    # Last.fm scrobbles
│   ├── youtubeChannel.js    # YouTube channel info
│   ├── blueskyFeed.js       # Bluesky posts for sidebar
│   ├── mastodonFeed.js      # Mastodon posts for sidebar
│   ├── blogrollStatus.js    # Blogroll API availability check
│   └── urlAliases.js        # Legacy URL mappings for webmentions
├── _includes/
│   ├── layouts/
│   │   ├── base.njk         # Base HTML shell (header, footer, nav)
│   │   ├── home.njk         # Homepage layout (plugin vs default)
│   │   ├── post.njk         # Individual post (h-entry, webmentions)
│   │   └── page.njk         # Simple page layout
│   ├── components/
│   │   ├── homepage-builder.njk  # Renders plugin homepage config
│   │   ├── homepage-section.njk  # Section router
│   │   ├── sidebar.njk           # Default sidebar
│   │   ├── h-card.njk            # Author identity card
│   │   ├── reply-context.njk     # Reply/like/repost context
│   │   └── webmentions.njk       # Webmention display + form
│   │   ├── sections/
│   │   │   ├── hero.njk          # Homepage hero
│   │   │   ├── recent-posts.njk  # Recent posts grid
│   │   │   ├── cv-experience.njk # Work experience timeline
│   │   │   ├── cv-skills.njk     # Skills with proficiency
│   │   │   ├── cv-education.njk  # Education history
│   │   │   ├── cv-projects.njk   # Featured projects
│   │   │   ├── cv-interests.njk  # Personal interests
│   │   │   └── custom-html.njk   # Custom HTML content
│   │   └── widgets/
│   │       ├── author-card.njk   # Sidebar h-card
│   │       ├── social-activity.njk  # Bluesky/Mastodon feed
│   │       ├── github-repos.njk  # GitHub featured repos
│   │       ├── funkwhale.njk     # Now playing widget
│   │       ├── blogroll.njk      # Recently updated blogs
│   │       └── categories.njk    # Category list
├── css/
│   ├── tailwind.css         # Tailwind source
│   ├── style.css            # Compiled output (generated)
│   └── prism-theme.css      # Syntax highlighting theme
├── js/
│   ├── webmentions.js       # Client-side webmention fetcher
│   └── admin.js             # Admin auth detection (shows FAB + dashboard link)
├── images/                  # Static images
├── *.njk                    # Page templates (blog, about, cv, etc.)
├── eleventy.config.js       # Eleventy configuration
├── tailwind.config.js       # Tailwind configuration
├── postcss.config.js        # PostCSS pipeline
└── package.json             # Dependencies and scripts

Usage

Development

# Install dependencies
npm install

# Development server with hot reload
npm run dev
# → http://localhost:8080

# Build for production
npm run build
# → Output to _site/

# Build CSS only (after Tailwind config changes)
npm run build:css

Content Directory

The theme expects content in a content/ directory (typically a symlink to Indiekit's content store):

content/
├── .indiekit/               # Plugin data files
│   ├── homepage.json        # Homepage builder config
│   ├── cv.json              # CV data
│   └── post-types.json      # Enabled post types
├── articles/
│   └── 2025-01-15-post.md
├── notes/
│   └── 2025-01-15-note.md
├── photos/
│   └── 2025-01-15-photo.md
└── pages/
    └── about.md             # Slash page

Customization

Colors and Typography

Edit tailwind.config.js:

theme: {
  extend: {
    colors: {
      primary: {
        500: "#3b82f6",  // Your primary color
        600: "#2563eb",
        // ...
      },
    },
    fontFamily: {
      sans: ["Your Font", "system-ui", "sans-serif"],
    },
  },
}

Then rebuild CSS: npm run build:css

Dark Mode

The theme includes full dark mode support with dark: variants. Toggle is available in header/mobile nav, syncs with system preference.

Override Files

When using as a submodule, place override files in your parent repo:

your-deployment-repo/
├── overrides/
│   └── eleventy-site/
│       ├── _data/           # Override data files
│       ├── images/          # Your images
│       └── about.njk        # Override templates
└── eleventy-site/           # This theme (submodule)

Override files are copied over the submodule during build.

Warning: Be careful with _data/ overrides — they can shadow dynamic plugin data. Use only for truly static customizations.

Plugin Integration

How Plugins Provide Data

Indiekit plugins write JSON files to content/.indiekit/*.json. The theme's _data/*.js files read these JSON files at build time.

Example flow:

  1. User edits CV in Indiekit admin UI (/cv)
  2. @rmdes/indiekit-endpoint-cv saves to content/.indiekit/cv.json
  3. Eleventy rebuild triggers (_data/cv.js reads the JSON file)
  4. CV sections render with new data

Homepage Builder

The homepage builder is controlled by @rmdes/indiekit-endpoint-homepage:

  1. Plugin provides admin UI at /homepage
  2. User configures layout, sections, sidebar widgets
  3. Plugin writes content/.indiekit/homepage.json
  4. Theme renders configured layout (or falls back to default)

Fallback: If no homepage plugin is installed, the theme shows a default layout (hero + recent posts + sidebar).

Adding Custom Sections

To add a custom homepage section:

  1. Create template in _includes/components/sections/your-section.njk
  2. Register in _includes/components/homepage-section.njk:
{% if section.type == "your-section" %}
  {% include "components/sections/your-section.njk" %}
{% endif %}
  1. Plugin should register the section via homepageSections in Indiekit

Deployment

Cloudron

See indiekit-cloudron repository for Cloudron deployment with this theme as submodule.

Docker Compose

See indiekit-deploy repository for Docker Compose deployment with this theme as submodule.

Static Host (Netlify, Vercel, etc.)

  1. Not recommended — Indiekit needs a server for Micropub/Webmentions
  2. For static-only use (no Indiekit), set all env vars and run npm run build
  3. Deploy _site/ directory

Pages Included

Page URL Description
Home / Dynamic homepage (plugin or default)
About /about/ Full h-card with bio
CV /cv/ Resume with all sections
Blog /blog/ All posts chronologically
Articles /articles/ Long-form articles
Notes /notes/ Short status updates
Photos /photos/ Photo posts
Bookmarks /bookmarks/ Saved links
Likes /likes/ Liked posts
Replies /replies/ Responses to others
Reposts /reposts/ Shared content
Interactions /interactions/ Combined social interactions
Slashes /slashes/ Index of all slash pages
Categories /categories/ Posts by category
GitHub /github/ GitHub activity (if plugin enabled)
Funkwhale /funkwhale/ Listening history (if plugin enabled)
Last.fm /listening/ Last.fm scrobbles (if plugin enabled)
YouTube /youtube/ YouTube channel (if plugin enabled)
Blogroll /blogroll/ Blog aggregator (if plugin enabled)
Podroll /podroll/ Podcast episodes (if plugin enabled)
IndieNews /news/ IndieNews submissions (if plugin enabled)
Search /search/ Pagefind search UI
RSS Feed /feed.xml RSS 2.0 feed
JSON Feed /feed.json JSON Feed 1.1
Changelog /changelog/ Site changelog

IndieWeb Resources

Troubleshooting

Webmentions not appearing

Solution:

  1. Check SITE_URL matches your live domain exactly
  2. Verify webmention.io API is responding: https://webmention.io/api/mentions?target=https://your-site.com/
  3. Check build-time cache at /webmention-debug/
  4. Ensure post URLs match exactly (with/without trailing slash)

Plugin data not showing

Solution:

  1. Verify the plugin is installed and running in Indiekit
  2. Check environment variables are set correctly
  3. Check content/.indiekit/*.json files exist and are valid JSON
  4. Rebuild Eleventy to refresh data: npm run build

Dark mode not working

Solution:

  1. Check browser console for JavaScript errors
  2. Verify Alpine.js loaded: <script src="...alpinejs..."></script>
  3. Clear localStorage: localStorage.removeItem('theme')

Search not working

Solution:

  1. Check Pagefind indexed: _site/_pagefind/ directory exists
  2. Rebuild with search indexing: npm run build
  3. Check search page is not blocked by CSP headers

Contributing

This theme is tailored for a specific Indiekit deployment but designed to be adaptable. Contributions welcome:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Test with npm run dev
  5. Submit a pull request

Guidelines:

  • Keep theme neutral (no hardcoded personal data)
  • Use environment variables for all configuration
  • Maintain microformats2 markup
  • Test dark mode
  • Follow existing code style (ESM, Nunjucks, Tailwind)

License

MIT

Credits