A flexible, Python-based static site generator customized for personal websites. It supports multiple content types (posts, micro-blog, reviews, bookmarks), responsive design, and performance optimizations.
- Content Types: Specialized support for Posts, Micro-updates, Reviews (with ratings), Bookmarks, and Static Pages via a Registry Pattern.
- Performance:
- Incremental Builds: Caches Markdown processing for faster regeneration (
.cache/). - Asset Optimization: Automatic minification of CSS/JS and image resizing/WebP conversion.
- Incremental Builds: Caches Markdown processing for faster regeneration (
- Extensibility:
- Shortcodes: Plugin system for custom components (e.g., YouTube, Ratings, Spoilers).
- Theming: Light/Dark mode with persistence.
- Search: Built-in client-side search with a generated JSON index.
- SEO: Automatic sitemap and RSS feed generation.
- Deployment: Ready for Cloudflare Workers/Pages with
wrangler.tomlandpackage.jsonincluded.
-
Clone the repository:
git clone <repository_url> cd <repository_name>
-
Create a virtual environment:
python3 -m venv venv source venv/bin/activate -
Install dependencies:
pip install -r requirements.txt
The project uses a unified CLI tool manage.py for all operations.
The project uses manage.py as a unified CLI. First, ensure it is executable: chmod +x manage.py.
Generates the static site.
--drafts: Include posts marked asdraft: true.--no-cache: Force a fresh build by clearing the cache.
Starts a local development server with Live Reload.
--port: Specify a custom port (default:8000).
Creates a new post using archetypes.
--type,-t: Content type (posts,micro,reviews,bookmarks).
Removes the output directory.
Content lives in the content/ directory. It uses Markdown with YAML frontmatter.
Templates for new content are stored in archetypes/. You can customize these to change the default structure for each post type.
The generator includes an extensible shortcode system that allows you to embed complex HTML components using simple tags.
Shortcodes use the syntax {{< name argument="value" >}}. Both positional and keyword arguments are supported.
YouTube
Embed a responsive YouTube video.
{{< youtube id="VIDEO_ID" title="Accessibility Title" >}}
Rating
Renders a star rating (e.g., 9.5/10).
{{< rating score="9.5" max_score="10" >}}
SoundCloud Embed a SoundCloud track using either its ID or URL.
- ID:
{{< soundcloud 123456789 >}} - URL:
{{< soundcloud "https://soundcloud.com/artist/song" >}}
Spoiler Renders a collapsible block.
{{< spoiler "Title" >}}
Hidden content...
{{< /spoiler >}}Image (img)
Renders a responsive image with optional caption.
{{< img src="/path/to/img.jpg" caption="Description" >}}
Internal Link (link)
Links to another post using its shortname defined in frontmatter.
{{< link "my-shortname" "Click Here" >}} or {{< link "my-shortname" >}} (uses post title).
Add a .py file to generator/shortcodes/ with a render function.
Example: generator/shortcodes/alert.py -> {{< alert "message" >}}
def render(message, type="info"):
return f'<div class="alert alert-{type}">{message}</div>'Site settings are located in config.yaml.
- Site Metadata: Title, URL, Author, Language (
site.language). - Navigation: Menu links configuration. Supports multi-row layout (e.g.,
first_row,second_row). - Humans.txt: Dynamic generation via
humans:block (Team, Thanks, Site, Custom). - Data Files: Support for
data/directory (accessible viasite.data). - Root Files: Support for
files/directory (copied directly to root).
The site supports full localization via YAML files.
- Configuration: Set
site.languageinconfig.yaml(e.g.,sv). - Locale Files: Create/Edit
i18n/{language}.yaml(e.g.,i18n/sv.yaml). - UI Strings: Define key-value pairs in the
stringsblock. - Date Formatting: Define months, days, and formats in the
dateblock. - Localized URLs: Map content types to localized URL slugs in the
slugsblock.Output:slugs: posts: "inlagg" reviews: "recensioner"
content/posts/my-post.md->public/inlagg/my-post/index.html.
The project is configured for deployment as a Cloudflare Worker with static assets.
- Build command:
python3 manage.py build - Deploy command:
npx wrangler deploy - Non-production branch deploy command:
npx wrangler versions upload
See wrangler.toml for configuration details like compatibility_date and assets directory.
- Live Reload:
manage.py serveuseslivereloadto watch for changes and automatically rebuild. - Caching: Processed Markdown is cached in
.cache/markdown_cache.json. Use the--no-cacheflag to force a full rebuild. - Search Index: The search index
public/search.jsonis automatically regenerated on every build.
The generator supports a plugin system integrated into the CLI. Scripts placed in the plugins/ directory are automatically loaded and can register their own commands.
Imports bookmarks from a Linkding instance into content/bookmarks/.
Usage:
python3 manage.py import-linkding \
--url "https://linkding.yourdomain.com" \
--token "YOUR_API_TOKEN" \
--tag "shared" \
--limit 10
--limit 10Features:
- Fetches bookmarks by tag
- Uses
archetypes/bookmarks.mdfor consistent formatting - Safely escapes content for YAML frontmatter
- Skips already imported bookmarks (by slug)
To add web analytics (Google Analytics, Plausible, Umami, etc.) to your site:
- Open
templates/partials/analytics.html. - Paste your tracking code snippet (HTML/JS) directly into the file.
- Rebuild the site.
The snippet will be automatically injected into the <head> of every page.
