This commit is contained in:
@@ -52,12 +52,17 @@ making changes; it is the authoritative operations and deployment runbook.
|
|||||||
- Preserve normal links to dedicated tag pages as the no-JavaScript baseline.
|
- Preserve normal links to dedicated tag pages as the no-JavaScript baseline.
|
||||||
Client-side filtering must remain a progressive enhancement with semantic
|
Client-side filtering must remain a progressive enhancement with semantic
|
||||||
buttons, keyboard support, and an announced result count.
|
buttons, keyboard support, and an announced result count.
|
||||||
- Tag-directory counts and dedicated tag pages must include projects, blog
|
- Tag-directory counts and dedicated tag pages must include projects, their
|
||||||
entries, and articles in the same discovery feed.
|
devlog entries, blog entries, and articles in the same discovery feed.
|
||||||
- For remote projects, keep repository language labels and project-declared
|
- For remote projects, keep repository language labels and project-declared
|
||||||
technology labels separate from their derived controlled tag slugs. Approved
|
technology labels separate from their derived controlled tag slugs. Approved
|
||||||
labels link to tag pages; unapproved labels remain visible, non-clickable, and
|
labels link to tag pages; unapproved labels remain visible, non-clickable, and
|
||||||
mustard-colored but do not affect tag feeds or counts.
|
mustard-colored but do not affect tag feeds or counts.
|
||||||
|
- Apply that same controlled mapping to remote devlog topics. Approved topics
|
||||||
|
link to tag pages and populate `topic_tag_slugs`; unapproved topics remain
|
||||||
|
mustard labels and are excluded from discovery.
|
||||||
|
- Keep project devlog entries in the homepage Recent Activity feed alongside
|
||||||
|
projects, blog entries, and articles, ordered by publication date.
|
||||||
- When `README.md` changes, keep the README-derived example blog entry aligned
|
- When `README.md` changes, keep the README-derived example blog entry aligned
|
||||||
with the runbook content it demonstrates.
|
with the runbook content it demonstrates.
|
||||||
|
|
||||||
@@ -78,9 +83,9 @@ making changes; it is the authoritative operations and deployment runbook.
|
|||||||
the relevant cache-busting version in the template and verify that generated
|
the relevant cache-busting version in the template and verify that generated
|
||||||
pages reference the new asset URL.
|
pages reference the new asset URL.
|
||||||
- For taxonomy changes, verify every entry tag has a matching `content/tags/`
|
- For taxonomy changes, verify every entry tag has a matching `content/tags/`
|
||||||
record, tag counts match rendered project/blog/article usage, dedicated tag
|
record, tag counts match rendered project/devlog/blog/article usage,
|
||||||
URLs build, and listing filters work with valid, absent, and unknown query
|
dedicated tag URLs build, and listing filters work with valid, absent, and
|
||||||
values.
|
unknown query values.
|
||||||
- Run `git diff --check` and review the exact diff before committing.
|
- Run `git diff --check` and review the exact diff before committing.
|
||||||
- If a push was requested, verify the Gitea Action result, deployed revision,
|
- If a push was requested, verify the Gitea Action result, deployed revision,
|
||||||
and site health instead of treating a successful `git push` as completion.
|
and site health instead of treating a successful `git push` as completion.
|
||||||
|
|||||||
@@ -144,27 +144,30 @@ 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
|
referencing entry deliberately and verify that no old slug remains before
|
||||||
renaming or removing its record.
|
renaming or removing its record.
|
||||||
|
|
||||||
`/tags/` lists every approved tag and counts its usage across projects, blog
|
`/tags/` lists every approved tag and counts its usage across projects, project
|
||||||
entries, and articles. Dedicated tag URLs combine matching records from all
|
devlog entries, blog entries, and articles. Dedicated tag URLs combine matching
|
||||||
three sections in one chronological discovery feed. Tag links are normal links
|
records from all four content types in one chronological discovery feed. Tag
|
||||||
and work without JavaScript. On the Projects, Blog, and Articles listing pages,
|
links are normal links and work without JavaScript. On the Projects, Blog, and
|
||||||
`assets/static/tags.js` progressively adds instant filtering and keeps the
|
Articles listing pages, `assets/static/tags.js` progressively adds instant
|
||||||
selected filter in the `tag` query parameter.
|
filtering and keeps the selected filter in the `tag` query parameter.
|
||||||
|
|
||||||
Remote-project languages and declared technologies are normalized to slugs and
|
Remote-project languages and declared technologies are normalized to slugs and
|
||||||
matched only against this controlled vocabulary. Their approved matches become
|
matched only against this controlled vocabulary. Their approved matches become
|
||||||
clickable tags and a deduplicated `taxonomy_tags` field used by filters, counts,
|
clickable tags and a deduplicated `taxonomy_tags` field used by filters, counts,
|
||||||
and tag pages. A label that has no approved record remains visible and
|
and tag pages. Devlog topics follow the same rule and populate derived
|
||||||
non-clickable in mustard, produces a build warning, and is excluded from tag
|
`topic_tag_slugs` used by tag feeds and counts. A label that has no approved
|
||||||
discovery. Remote data never creates a tag record automatically.
|
record remains visible and non-clickable in mustard, produces a build warning,
|
||||||
|
and is excluded from tag discovery. Remote data never creates a tag record
|
||||||
|
automatically.
|
||||||
|
|
||||||
After taxonomy or filtering changes:
|
After taxonomy or filtering changes:
|
||||||
|
|
||||||
1. Run `python scripts/build_with_projects.py --output-path build`.
|
1. Run `python scripts/build_with_projects.py --output-path build`.
|
||||||
2. Verify `/tags/`, at least one dedicated tag URL, and all three section listings.
|
2. Verify `/tags/`, at least one dedicated tag URL, the three top-level section
|
||||||
3. Confirm tag counts cover projects, blog entries, and articles; every stored
|
listings, and a project devlog index.
|
||||||
entry slug has a matching tag record; and unapproved project labels are not
|
3. Confirm tag counts cover projects, devlog entries, blog entries, and
|
||||||
counted.
|
articles; every stored entry slug has a matching tag record; and unapproved
|
||||||
|
remote labels are not counted.
|
||||||
4. Test filtering with JavaScript enabled and confirm tag links remain usable
|
4. Test filtering with JavaScript enabled and confirm tag links remain usable
|
||||||
without JavaScript.
|
without JavaScript.
|
||||||
5. Check keyboard operation plus desktop and narrow layouts.
|
5. Check keyboard operation plus desktop and narrow layouts.
|
||||||
@@ -194,7 +197,9 @@ The public routes are `/projects/thinkloom/`,
|
|||||||
`/projects/thinkloom/devlog/`, and
|
`/projects/thinkloom/devlog/`, and
|
||||||
`/projects/thinkloom/devlog/<entry-slug>/`. The project repository owns the
|
`/projects/thinkloom/devlog/<entry-slug>/`. The project repository owns the
|
||||||
native Lektor records and approved images. This site owns their models,
|
native Lektor records and approved images. This site owns their models,
|
||||||
templates, layout, repository-information card, and import policy.
|
templates, layout, repository-information card, and import policy. Imported
|
||||||
|
devlog entries also join the homepage Recent Activity feed, ordered with
|
||||||
|
projects, articles, and blog entries by publication date.
|
||||||
|
|
||||||
`configs/project-sources.ini` is the allowlist. Each source declares a stable
|
`configs/project-sources.ini` is the allowlist. Each source declares a stable
|
||||||
project ID, credential-free HTTPS Git URL, public web/API URL, and branch. Add
|
project ID, credential-free HTTPS Git URL, public web/API URL, and branch. Add
|
||||||
@@ -235,8 +240,9 @@ The project card combines repository-owned content with public provider and Git
|
|||||||
metadata: source and README links, default branch, latest commit, license,
|
metadata: source and README links, default branch, latest commit, license,
|
||||||
languages, open issues, stars, forks, latest release, imported revision, and
|
languages, open issues, stars, forks, latest release, imported revision, and
|
||||||
sync time. Approved language and technology labels link into the shared tag
|
sync time. Approved language and technology labels link into the shared tag
|
||||||
taxonomy, allowing a project to lead visitors to related writing. API metadata
|
taxonomy, as do approved devlog topics, allowing either a project or a
|
||||||
failure uses cached metadata and is identified in the
|
development milestone to lead visitors to related writing. API metadata failure
|
||||||
|
uses cached metadata and is identified in the
|
||||||
sync status; it never causes an unvalidated new snapshot to replace a working
|
sync status; it never causes an unvalidated new snapshot to replace a working
|
||||||
one.
|
one.
|
||||||
|
|
||||||
|
|||||||
@@ -161,19 +161,20 @@ 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
|
referencing entry deliberately and verify that no old slug remains before
|
||||||
renaming or removing its record.
|
renaming or removing its record.
|
||||||
|
|
||||||
`/tags/` lists every approved tag and counts its usage across projects, blog
|
`/tags/` lists every approved tag and counts its usage across projects, project
|
||||||
entries, and articles. Dedicated tag URLs combine matching records from all
|
devlog entries, blog entries, and articles. Dedicated tag URLs combine matching
|
||||||
three sections. Tag links are normal links and work without JavaScript. On the
|
records from all four content types. Tag links are normal links and work without
|
||||||
Projects, Blog, and Articles listing pages, `assets/static/tags.js`
|
JavaScript. On the Projects, Blog, and Articles listing pages,
|
||||||
progressively adds instant filtering and keeps the selected filter in the `tag`
|
`assets/static/tags.js` progressively adds instant filtering and keeps the
|
||||||
query parameter.
|
selected filter in the `tag` query parameter.
|
||||||
|
|
||||||
After taxonomy or filtering changes:
|
After taxonomy or filtering changes:
|
||||||
|
|
||||||
1. Run `python scripts/build_with_projects.py --output-path build`.
|
1. Run `python scripts/build_with_projects.py --output-path build`.
|
||||||
2. Verify `/tags/`, at least one dedicated tag URL, and all three section listings.
|
2. Verify `/tags/`, at least one dedicated tag URL, the three top-level section
|
||||||
3. Confirm tag counts cover projects, blog entries, and articles and that every
|
listings, and a project devlog index.
|
||||||
stored entry slug has a matching tag record.
|
3. Confirm tag counts cover projects, devlog entries, blog entries, and articles
|
||||||
|
and that every stored entry slug has a matching tag record.
|
||||||
4. Test filtering with JavaScript enabled and confirm tag links remain usable
|
4. Test filtering with JavaScript enabled and confirm tag links remain usable
|
||||||
without JavaScript.
|
without JavaScript.
|
||||||
5. Check keyboard operation plus desktop and narrow layouts.
|
5. Check keyboard operation plus desktop and narrow layouts.
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: Architecture
|
||||||
|
---
|
||||||
|
summary: Product boundaries, system structure, and consequential technical design.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: Configuration
|
||||||
|
---
|
||||||
|
summary: User-editable and system configuration design and implementation.
|
||||||
@@ -4,4 +4,4 @@ title: Tags
|
|||||||
---
|
---
|
||||||
eyebrow: Taxonomy
|
eyebrow: Taxonomy
|
||||||
---
|
---
|
||||||
summary: Browse the controlled vocabulary used across projects, blog entries, and articles.
|
summary: Browse the controlled vocabulary used across projects, devlogs, blog entries, and articles.
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: Documentation
|
||||||
|
---
|
||||||
|
summary: Technical, operational, product, and user-facing documentation.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: Interface
|
||||||
|
---
|
||||||
|
summary: Interaction models, workspace layout, and user-interface design.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: JSON Schema
|
||||||
|
---
|
||||||
|
summary: Machine-readable JSON contracts, validation, fixtures, and compatibility.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: Models
|
||||||
|
---
|
||||||
|
summary: AI model integration, selection, configuration, and behavior.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: MVP
|
||||||
|
---
|
||||||
|
summary: Minimum viable product milestones and end-to-end prototypes.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: OpenAI Build Week
|
||||||
|
---
|
||||||
|
summary: Projects, milestones, and releases developed during OpenAI Build Week.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: Privacy
|
||||||
|
---
|
||||||
|
summary: Data minimization, local ownership, credential handling, and private operation.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: Prompts
|
||||||
|
---
|
||||||
|
summary: Model prompt design, configuration, evaluation, and user control.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: Prototype
|
||||||
|
---
|
||||||
|
summary: Early implementations used to test workflows, boundaries, and ideas.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: Release
|
||||||
|
---
|
||||||
|
summary: Preparing, packaging, publishing, and documenting software releases.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: User Control
|
||||||
|
---
|
||||||
|
summary: Explicit user authority, review, consent, and reversible operations.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: v0.4.0
|
||||||
|
---
|
||||||
|
summary: Work associated with the version 0.4.0 contract and milestone.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: Verification
|
||||||
|
---
|
||||||
|
summary: Tests, assertions, conformance checks, and reproducible evidence.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
_model: tag
|
||||||
|
---
|
||||||
|
title: Writing Workspace
|
||||||
|
---
|
||||||
|
summary: Structured environments for drafting, revision, and creative work.
|
||||||
@@ -32,6 +32,18 @@ type = strings
|
|||||||
label = Imported topics
|
label = Imported topics
|
||||||
type = strings
|
type = strings
|
||||||
|
|
||||||
|
[fields.topic_labels]
|
||||||
|
label = Topic display labels
|
||||||
|
type = strings
|
||||||
|
|
||||||
|
[fields.topic_tag_slugs]
|
||||||
|
label = Approved topic tags
|
||||||
|
type = strings
|
||||||
|
|
||||||
|
[fields.kicker]
|
||||||
|
label = Type
|
||||||
|
type = string
|
||||||
|
|
||||||
[fields.source_commit]
|
[fields.source_commit]
|
||||||
label = Source commit
|
label = Source commit
|
||||||
type = string
|
type = string
|
||||||
|
|||||||
@@ -647,12 +647,24 @@ def materialize(
|
|||||||
if record.get("_model") == "devlog-entry":
|
if record.get("_model") == "devlog-entry":
|
||||||
entry_commit = record["source_commit"]
|
entry_commit = record["source_commit"]
|
||||||
entry_meta = commit_metadata(Path(metadata["mirror_path"]), entry_commit)
|
entry_meta = commit_metadata(Path(metadata["mirror_path"]), entry_commit)
|
||||||
|
topic_values = split_list(record["tags"])
|
||||||
|
topic_tag_slugs = approved_tag_slugs(
|
||||||
|
source["project_id"],
|
||||||
|
"devlog topic",
|
||||||
|
topic_values,
|
||||||
|
tag_vocabulary,
|
||||||
|
)
|
||||||
output = append_fields(
|
output = append_fields(
|
||||||
data,
|
data,
|
||||||
{
|
{
|
||||||
|
"kicker": "Devlog",
|
||||||
"source_commit_url": f"{source['web_url']}/commit/{entry_commit}",
|
"source_commit_url": f"{source['web_url']}/commit/{entry_commit}",
|
||||||
"source_commit_time": entry_meta["commit_date"],
|
"source_commit_time": entry_meta["commit_date"],
|
||||||
"topic_tags": split_list(record["tags"]),
|
"topic_tags": topic_values,
|
||||||
|
"topic_labels": taxonomy_label_items(
|
||||||
|
topic_values, topic_tag_slugs
|
||||||
|
),
|
||||||
|
"topic_tag_slugs": topic_tag_slugs,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
target.write_bytes(output)
|
target.write_bytes(output)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% from "macros/tag-links.html" import taxonomy_labels with context %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{% set project = this.parent.parent %}
|
{% set project = this.parent.parent %}
|
||||||
{% set siblings = this.get_siblings() %}
|
{% set siblings = this.get_siblings() %}
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
<dt>Source commit</dt>
|
<dt>Source commit</dt>
|
||||||
<dd><a href="{{ this.source_commit_url }}"><code>{{ this.source_commit[:10] }}</code></a></dd>
|
<dd><a href="{{ this.source_commit_url }}"><code>{{ this.source_commit[:10] }}</code></a></dd>
|
||||||
</div>
|
</div>
|
||||||
{% if this.topic_tags %}<div class="post-info-row"><dt>Topics</dt><dd class="technology-list">{% for tag in this.topic_tags %}<span>{{ tag }}</span>{% endfor %}</dd></div>{% endif %}
|
{% if this.topic_labels %}<div class="post-info-row"><dt>Topics</dt><dd class="technology-list">{{ taxonomy_labels(this.topic_labels) }}</dd></div>{% endif %}
|
||||||
</dl>
|
</dl>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% from "macros/tag-links.html" import taxonomy_labels with context %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{% set project = this.parent %}
|
{% set project = this.parent %}
|
||||||
<section class="hero compact devlog-hero">
|
<section class="hero compact devlog-hero">
|
||||||
@@ -17,7 +18,7 @@
|
|||||||
<div class="entry-meta"><span class="label">Devlog</span><time datetime="{{ entry.date }}">{{ entry.date|dateformat('YYYY.MM.dd') }}</time></div>
|
<div class="entry-meta"><span class="label">Devlog</span><time datetime="{{ entry.date }}">{{ entry.date|dateformat('YYYY.MM.dd') }}</time></div>
|
||||||
<h2><a href="{{ entry|url }}">{{ entry.title }}</a></h2>
|
<h2><a href="{{ entry|url }}">{{ entry.title }}</a></h2>
|
||||||
<p>{{ entry.summary }}</p>
|
<p>{{ entry.summary }}</p>
|
||||||
{% if entry.topic_tags %}<div class="technology-list">{% for tag in entry.topic_tags %}<span>{{ tag }}</span>{% endfor %}</div>{% endif %}
|
{% if entry.topic_labels %}<div class="technology-list">{{ taxonomy_labels(entry.topic_labels) }}</div>{% endif %}
|
||||||
<a class="read-more" href="{{ entry|url }}">Read entry →</a>
|
<a class="read-more" href="{{ entry|url }}">Read entry →</a>
|
||||||
</article>
|
</article>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
+10
-1
@@ -19,6 +19,16 @@
|
|||||||
{% if entries.append(item) %}{% endif %}
|
{% if entries.append(item) %}{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% for project in site.query('/projects') %}
|
||||||
|
{% if project._model == 'project' %}
|
||||||
|
{% set devlog = site.get(project.path ~ '/devlog') %}
|
||||||
|
{% if devlog %}
|
||||||
|
{% for entry in devlog.children %}
|
||||||
|
{% if entries.append(entry) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
{% for item in entries|sort(attribute='date', reverse=true) %}
|
{% for item in entries|sort(attribute='date', reverse=true) %}
|
||||||
<article class="timeline-entry accent-{{ item.kicker|lower }}">
|
<article class="timeline-entry accent-{{ item.kicker|lower }}">
|
||||||
<div class="entry-meta">
|
<div class="entry-meta">
|
||||||
@@ -33,4 +43,3 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,16 @@
|
|||||||
{% if tag._id in item_tags %}{% set usage.count = usage.count + 1 %}{% endif %}
|
{% if tag._id in item_tags %}{% set usage.count = usage.count + 1 %}{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% for project in site.query('/projects') %}
|
||||||
|
{% if project._model == 'project' %}
|
||||||
|
{% set devlog = site.get(project.path ~ '/devlog') %}
|
||||||
|
{% if devlog %}
|
||||||
|
{% for entry in devlog.children %}
|
||||||
|
{% if tag._id in entry.topic_tag_slugs %}{% set usage.count = usage.count + 1 %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
<a class="tag-directory-card" href="{{ tag|url }}">
|
<a class="tag-directory-card" href="{{ tag|url }}">
|
||||||
<span class="tag-directory-name">{{ tag.title }}</span>
|
<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-count">{{ usage.count }} {% if usage.count == 1 %}entry{% else %}entries{% endif %}</span>
|
||||||
|
|||||||
+12
-2
@@ -8,6 +8,16 @@
|
|||||||
{% if this._id in item_tags %}{% set matches.items = matches.items + [item] %}{% endif %}
|
{% if this._id in item_tags %}{% set matches.items = matches.items + [item] %}{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% for project in site.query('/projects') %}
|
||||||
|
{% if project._model == 'project' %}
|
||||||
|
{% set devlog = site.get(project.path ~ '/devlog') %}
|
||||||
|
{% if devlog %}
|
||||||
|
{% for entry in devlog.children %}
|
||||||
|
{% if this._id in entry.topic_tag_slugs %}{% set matches.items = matches.items + [entry] %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
<section class="hero compact">
|
<section class="hero compact">
|
||||||
<div class="shell narrow">
|
<div class="shell narrow">
|
||||||
<p class="eyebrow">Tag</p>
|
<p class="eyebrow">Tag</p>
|
||||||
@@ -24,7 +34,7 @@
|
|||||||
{% if matches.items %}
|
{% if matches.items %}
|
||||||
<div class="card-grid">
|
<div class="card-grid">
|
||||||
{% for item in matches.items|sort(attribute='date', reverse=true) %}
|
{% for item in matches.items|sort(attribute='date', reverse=true) %}
|
||||||
{% set item_tags = item.taxonomy_tags if item._model == 'project' else item.tags %}
|
{% set item_tags = item.taxonomy_tags if item._model == 'project' else (item.topic_tag_slugs if item._model == 'devlog-entry' else item.tags) %}
|
||||||
<article class="entry-card accent-{{ item.kicker|lower }}">
|
<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>
|
<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>
|
<h2><a href="{{ item|url }}">{{ item.title }}</a></h2>
|
||||||
@@ -35,7 +45,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="empty-state">No projects, blog entries, or articles use this tag yet.</p>
|
<p class="empty-state">No projects, devlog entries, blog entries, or articles use this tag yet.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from project_sources import ( # noqa: E402
|
|||||||
append_fields,
|
append_fields,
|
||||||
fetch_json,
|
fetch_json,
|
||||||
metadata_digest,
|
metadata_digest,
|
||||||
|
normalize_tag_value,
|
||||||
parse_record,
|
parse_record,
|
||||||
split_list,
|
split_list,
|
||||||
taxonomy_label_items,
|
taxonomy_label_items,
|
||||||
@@ -68,6 +69,10 @@ class ProjectSourceTests(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(items, ["typescript\tTypeScript", "-\tUnlisted Tool"])
|
self.assertEqual(items, ["typescript\tTypeScript", "-\tUnlisted Tool"])
|
||||||
|
|
||||||
|
def test_devlog_topic_versions_get_stable_tag_slugs(self) -> None:
|
||||||
|
self.assertEqual(normalize_tag_value("v0.4.0"), "v0-4-0")
|
||||||
|
self.assertEqual(normalize_tag_value("OpenAI Build Week"), "openai-build-week")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user