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
@@ -8,12 +8,7 @@ updated: 2026-08-11
---
author: Example Article Author
---
tags:
Lorem Ipsum
Information Card
Field Mapping
Example
tags: lorem-ipsum, information-card, field-mapping, example
---
kicker: Article
---
@@ -38,7 +33,7 @@ follows:
- **Updated** is read from the optional `updated` field.
- **Reading time** is calculated automatically from the words in the `body`
field, using approximately 200 words per minute.
- **Topics** are read from the multiline `tags` field.
- **Topics** are read from the controlled checkbox `tags` field.
- **Published online** loops over every item in the multiline `published_urls`
field.
@@ -6,12 +6,7 @@ date: 2026-08-11
---
author: Example Blog Author
---
tags:
Lektor
Deployment
Operations
Example
tags: lektor, deployment, operations, example
---
kicker: Blog
---
@@ -27,7 +22,7 @@ back to this record's `contents.lr` file:
- **Author** is read from the `author` field.
- **Published** is read from the `date` field.
- **Tags** are read from the multiline `tags` field.
- **Tags** are read from the controlled checkbox `tags` field.
The title, summary, and article body are supplied by `title`, `summary`, and
`body`, respectively, but those values appear outside the information card.
@@ -93,9 +88,10 @@ server is not part of production serving; nginx serves generated files only.
```text
Labyricorn.lektorproject Lektor project definition
content/ Editable site content (`contents.lr` files)
content/tags/ Controlled tag vocabulary and dedicated tag routes
models/ Lektor content models
templates/ Jinja templates
assets/static/ CSS, favicon, and other static source assets
assets/static/ CSS, filtering JavaScript, favicon, and static assets
.gitignore Excludes generated and local files
README.md This runbook
```
@@ -133,6 +129,56 @@ Do not edit generated files under `/srv/labyricorn/current` or
`/srv/labyricorn/releases`. They will be replaced by deployment and are not
source-controlled.
## Tags and filtering workflow
`content/tags/` is the single source of truth for the controlled tag
vocabulary. Each child directory is a normal Lektor record whose directory name
is the canonical lowercase, hyphenated slug used in entry data and URLs:
```text
content/tags/deployment/contents.lr -> /tags/deployment/
```
The tag record supplies the editor label and public description:
_model: tag
---
title: Deployment
---
summary: Build, release, rollout, verification, and rollback workflows.
The entry model reads its checkbox choices directly from these records. Blog
entries and articles store the selected slugs as a comma-separated `tags`
value:
```text
tags: lektor, deployment, operations
```
To add a tag, create its `content/tags/<slug>/contents.lr` record, run a build,
and then select it on the relevant entries. Do not add a slug directly to an
entry before its tag record exists. To rename or retire a tag, update every
referencing entry deliberately and verify that no old slug remains before
renaming or removing its record.
`/tags/` lists every approved tag and counts its usage across blog entries and
articles. Dedicated tag URLs list matching entries from both sections. Tag
links are normal links and work without JavaScript. On the Blog and Articles
listing pages, `assets/static/tags.js` progressively adds instant filtering and
keeps the selected filter in the `tag` query parameter.
After taxonomy or filtering changes:
1. Run `lektor build --output-path build`.
2. Verify `/tags/`, at least one dedicated tag URL, and both section listings.
3. Confirm tag counts cover blog entries and articles and that every entry slug
has a matching tag record.
4. Test filtering with JavaScript enabled and confirm tag links remain usable
without JavaScript.
5. Check keyboard operation plus desktop and narrow layouts.
6. If filtering JavaScript or tag styles changed, increment the corresponding
cache-busting version in `templates/base.html`.
## Local development
Install Lektor in an isolated Python environment. For example:
+1 -5
View File
@@ -6,11 +6,7 @@ date: 2026-08-11
---
author: Labyricorn
---
tags:
Lektor
Git
Publishing
tags: lektor, git, publishing
---
kicker: Blog
---
+7
View File
@@ -0,0 +1,7 @@
_model: tag-index
---
title: Tags
---
eyebrow: Taxonomy
---
summary: Browse the controlled vocabulary used across blog entries and articles.
+5
View File
@@ -0,0 +1,5 @@
_model: tag
---
title: Deployment
---
summary: Build, release, rollout, verification, and rollback workflows.
+5
View File
@@ -0,0 +1,5 @@
_model: tag
---
title: Example
---
summary: Demonstration content that explains how the publishing system works.
+5
View File
@@ -0,0 +1,5 @@
_model: tag
---
title: Field Mapping
---
summary: Connections between Lektor content fields and their rendered output.
+5
View File
@@ -0,0 +1,5 @@
_model: tag
---
title: Git
---
summary: Version control, review, and repository-centered publishing.
@@ -0,0 +1,5 @@
_model: tag
---
title: Information Card
---
summary: Metadata presentation for posts and long-form articles.
+5
View File
@@ -0,0 +1,5 @@
_model: tag
---
title: Lektor
---
summary: Content modeling, authoring, and static-site generation with Lektor.
+5
View File
@@ -0,0 +1,5 @@
_model: tag
---
title: Lorem Ipsum
---
summary: Placeholder prose used to exercise article layouts and metadata.
+5
View File
@@ -0,0 +1,5 @@
_model: tag
---
title: Operations
---
summary: Hosting, service management, observability, and production procedures.
+5
View File
@@ -0,0 +1,5 @@
_model: tag
---
title: Publishing
---
summary: Editorial workflows, content delivery, and production releases.