Add controlled tag taxonomy and filters
Deploy production / deploy (push) Successful in 1s

This commit is contained in:
2026-08-11 22:01:22 -07:00
parent bdcad1321f
commit 2b4eb9f0f6
26 changed files with 438 additions and 36 deletions
+3 -1
View File
@@ -9,7 +9,8 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=Inter:wght@400;500&family=Playfair+Display:ital,wght@0,600;0,700;1,500;1,600&display=swap" rel="stylesheet">
<link rel="icon" href="{{ '/static/favicon.svg'|url }}" type="image/svg+xml">
<link rel="stylesheet" href="{{ '/static/style.css'|url }}?v=3">
<link rel="stylesheet" href="{{ '/static/style.css'|url }}?v=4">
<script src="{{ '/static/tags.js'|url }}?v=1" defer></script>
</head>
<body>
<header class="site-header">
@@ -42,6 +43,7 @@
<span>© 2026 Labyricorn — GENERATED FROM GIT, NEVER HAND-EDITED</span>
<nav aria-label="Footer navigation">
<a href="mailto:[email protected]">Contact</a>
<a href="{{ '/tags'|url }}">Tags</a>
<a href="https://github.com/">GitHub</a>
<a href="https://git.labyricorn.com/">Gitea</a>
<a href="https://ko-fi.com/">Ko-fi</a>
+3 -2
View File
@@ -1,4 +1,5 @@
{% extends "base.html" %}
{% from "macros/tag-links.html" import tag_links with context %}
{% block body %}
{% if this.parent._id == 'blog' %}
<article class="blog-post-layout shell">
@@ -22,7 +23,7 @@
<div class="post-info-row">
<dt>Tags</dt>
<dd class="post-tags">
{% for tag in this.tags %}<span>{{ tag }}</span>{% endfor %}
{{ tag_links(this.tags) }}
</dd>
</div>
</dl>
@@ -70,7 +71,7 @@
<div class="post-info-row">
<dt>Topics</dt>
<dd class="post-tags">
{% for tag in this.tags %}<span>{{ tag }}</span>{% endfor %}
{{ tag_links(this.tags) }}
</dd>
</div>
{% endif %}
+6
View File
@@ -0,0 +1,6 @@
{% macro tag_links(tags) -%}
{% for tag in tags %}
{% set tag_record = site.get('/tags/' ~ tag) %}
{% if tag_record %}<a href="{{ tag_record|url }}" rel="tag">{{ tag_record.title }}</a>{% else %}<span>{{ tag }}</span>{% endif %}
{% endfor %}
{%- endmacro %}
+23 -3
View File
@@ -1,5 +1,14 @@
{% extends "base.html" %}
{% from "macros/tag-links.html" import tag_links with context %}
{% block body %}
{% set filter_tags = namespace(values=[]) %}
{% if this._id in ['blog', 'articles'] %}
{% for item in this.children %}
{% for tag in item.tags %}
{% if tag not in filter_tags.values %}{% set filter_tags.values = filter_tags.values + [tag] %}{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
<section class="hero compact">
<div class="shell narrow">
<p class="eyebrow">{{ this.eyebrow }}</p>
@@ -8,18 +17,29 @@
</section>
<section class="activity-section">
<div class="shell">
<div class="section-heading"><span>{{ this.title }}</span><span>{{ this.children.count() }} entries</span></div>
<div class="section-heading"><span>{{ this.title }}</span><span data-entry-count>{{ this.children.count() }} entries</span></div>
{% if filter_tags.values %}
<div class="tag-filter" data-tag-filter aria-label="Filter {{ this.title }} by tag">
<button class="tag-filter-button is-active" type="button" data-tag-value="" aria-pressed="true">All</button>
{% for tag in filter_tags.values|sort %}
{% set tag_record = site.get('/tags/' ~ tag) %}
{% if tag_record %}<button class="tag-filter-button" type="button" data-tag-value="{{ tag }}" aria-pressed="false">{{ tag_record.title }}</button>{% endif %}
{% endfor %}
</div>
<p class="filter-status" data-filter-status aria-live="polite"></p>
{% endif %}
<div class="card-grid">
{% for item in this.children %}
<article class="entry-card accent-{{ item.kicker|lower }}">
<article class="entry-card accent-{{ item.kicker|lower }}"{% if filter_tags.values %} data-filter-item data-tags="{{ item.tags|join(' ') }}"{% endif %}>
<div class="entry-meta"><span class="label">{{ item.kicker }}</span><time>{{ item.date|dateformat('YYYY.MM.dd') }}</time></div>
<h2><a href="{{ item|url }}">{{ item.title }}</a></h2>
<p>{{ item.summary }}</p>
{% if item.tags %}<div class="entry-tags">{{ tag_links(item.tags) }}</div>{% endif %}
<a class="read-more" href="{{ item|url }}">Read entry →</a>
</article>
{% endfor %}
</div>
{% if filter_tags.values %}<p class="filter-empty" data-filter-empty hidden>No entries use this tag.</p>{% endif %}
</div>
</section>
{% endblock %}
+29
View File
@@ -0,0 +1,29 @@
{% extends "base.html" %}
{% block body %}
<section class="hero compact">
<div class="shell narrow">
<p class="eyebrow">{{ this.eyebrow }}</p>
<h1>{{ this.summary }}</h1>
</div>
</section>
<section class="activity-section">
<div class="shell">
<div class="section-heading"><span>{{ this.title }}</span><span>{{ this.children.count() }} approved tags</span></div>
<div class="tag-directory">
{% for tag in this.children %}
{% set usage = namespace(count=0) %}
{% for section_id in ['blog', 'articles'] %}
{% for item in site.query('/' ~ section_id) %}
{% if tag._id in item.tags %}{% set usage.count = usage.count + 1 %}{% endif %}
{% endfor %}
{% endfor %}
<a class="tag-directory-card" href="{{ tag|url }}">
<span class="tag-directory-name">{{ tag.title }}</span>
<span class="tag-directory-count">{{ usage.count }} {% if usage.count == 1 %}entry{% else %}entries{% endif %}</span>
<span class="tag-directory-summary">{{ tag.summary }}</span>
</a>
{% endfor %}
</div>
</div>
</section>
{% endblock %}
+40
View File
@@ -0,0 +1,40 @@
{% extends "base.html" %}
{% from "macros/tag-links.html" import tag_links with context %}
{% block body %}
{% set matches = namespace(items=[]) %}
{% for section_id in ['blog', 'articles'] %}
{% for item in site.query('/' ~ section_id) %}
{% if this._id in item.tags %}{% set matches.items = matches.items + [item] %}{% endif %}
{% endfor %}
{% endfor %}
<section class="hero compact">
<div class="shell narrow">
<p class="eyebrow">Tag</p>
<h1>{{ this.title }}</h1>
<p class="dek">{{ this.summary }}</p>
</div>
</section>
<section class="activity-section">
<div class="shell">
<div class="section-heading">
<span>Tagged {{ this.title }}</span>
<span>{{ matches.items|length }} {% if matches.items|length == 1 %}entry{% else %}entries{% endif %}</span>
</div>
{% if matches.items %}
<div class="card-grid">
{% for item in matches.items|sort(attribute='date', reverse=true) %}
<article class="entry-card accent-{{ item.kicker|lower }}">
<div class="entry-meta"><span class="label">{{ item.kicker }}</span><time>{{ item.date|dateformat('YYYY.MM.dd') }}</time></div>
<h2><a href="{{ item|url }}">{{ item.title }}</a></h2>
<p>{{ item.summary }}</p>
{% if item.tags %}<div class="entry-tags">{{ tag_links(item.tags) }}</div>{% endif %}
<a class="read-more" href="{{ item|url }}">Read entry →</a>
</article>
{% endfor %}
</div>
{% else %}
<p class="empty-state">No blog entries or articles use this tag yet.</p>
{% endif %}
</div>
</section>
{% endblock %}