Adds hierarchical tag support using "/" separator (e.g. "tech/programming/js"). - New filters: nestedSlugify, categoryMatches, categoryBreadcrumb, categoryGroupByRoot, categoryDirectChildren - categories collection auto-generates ancestor pages for nested tags - categories.njk: breadcrumb nav, sub-tags section, ancestor-aware post matching - categories-index.njk: grouped tree view (root + indented children) - categories widget: shows root tags only with child count badge - All category links updated from slugify → nestedSlugify (backward-compatible) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
146 lines
8.0 KiB
Plaintext
146 lines
8.0 KiB
Plaintext
---
|
|
layout: layouts/base.njk
|
|
withSidebar: true
|
|
---
|
|
{# Layout for slash pages (/about, /now, /uses, etc.) #}
|
|
{# These are root-level pages created via Indiekit's page post type #}
|
|
|
|
{# AI metadata compatibility: support nested ai object plus legacy top-level keys #}
|
|
{% set aiMeta = ai or {} %}
|
|
{% set aiTextLevel = aiTextLevel or ai_text_level or aiMeta.textLevel or aiMeta.aiTextLevel or "0" %}
|
|
{% set aiCodeLevel = aiCodeLevel or ai_code_level or aiMeta.codeLevel or aiMeta.aiCodeLevel or "0" %}
|
|
{% set aiTools = aiTools or ai_tools or aiMeta.aiTools or aiMeta.tools %}
|
|
{% set aiDescription = aiDescription or ai_description or aiMeta.aiDescription or aiMeta.description %}
|
|
{% set aiUsed = (aiTextLevel and aiTextLevel !== "0") or (aiCodeLevel and aiCodeLevel !== "0") %}
|
|
|
|
<article class="h-entry{% if aiUsed %} h-ai-usage{% endif %}" data-ai-text-level="{{ aiTextLevel }}" data-ai-code-level="{{ aiCodeLevel or '0' }}" data-ai-used="{% if aiUsed %}true{% else %}false{% endif %}"{% if aiTools %} data-ai-tools="{{ aiTools }}"{% endif %}>
|
|
<header class="mb-6 sm:mb-8">
|
|
<h1 class="p-name text-2xl sm:text-3xl font-bold text-surface-900 dark:text-surface-100 mb-2">
|
|
{{ title }}
|
|
</h1>
|
|
{% if summary %}
|
|
<p class="p-summary text-lg text-surface-600 dark:text-surface-400">
|
|
{{ summary }}
|
|
</p>
|
|
{% endif %}
|
|
{% set lastUpdated = updated or page.date %}
|
|
{% if lastUpdated %}
|
|
<p class="text-sm text-surface-600 dark:text-surface-400 mt-2">
|
|
Last updated: <time class="dt-updated font-mono text-sm" datetime="{{ lastUpdated | isoDate }}">{{ lastUpdated | dateDisplay }}</time>
|
|
</p>
|
|
{% endif %}
|
|
</header>
|
|
|
|
<div class="e-content prose dark:prose-invert prose-lg max-w-none">
|
|
{{ content | safe }}
|
|
</div>
|
|
|
|
{# AI post-graph — shown only on the /ai/ page #}
|
|
{% if page.url == "/ai/" and collections.posts %}
|
|
{% set stats = collections.posts | aiStats %}
|
|
{% set aiPostsList = collections.posts | aiPosts %}
|
|
<section class="mt-8 sm:mt-12 p-6 rounded-lg bg-surface-50 dark:bg-surface-800/50 border border-surface-200 dark:border-surface-700 shadow-sm">
|
|
<h2 class="text-xl font-bold text-surface-900 dark:text-surface-100 mb-4">AI Usage Across Posts</h2>
|
|
<div class="grid gap-4 sm:grid-cols-4 mb-6">
|
|
<div class="text-center p-3 rounded-lg bg-surface-50 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 shadow-sm">
|
|
<div class="text-2xl font-bold text-surface-900 dark:text-surface-100">{{ stats.total }}</div>
|
|
<div class="text-xs text-surface-600 dark:text-surface-400">Total posts</div>
|
|
</div>
|
|
<div class="text-center p-3 rounded-lg bg-surface-50 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 shadow-sm">
|
|
<div class="text-2xl font-bold text-amber-600 dark:text-amber-400">{{ stats.aiCount }}</div>
|
|
<div class="text-xs text-surface-600 dark:text-surface-400">AI-involved</div>
|
|
</div>
|
|
<div class="text-center p-3 rounded-lg bg-surface-50 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 shadow-sm">
|
|
<div class="text-2xl font-bold text-emerald-600 dark:text-emerald-400">{{ stats.total - stats.aiCount }}</div>
|
|
<div class="text-xs text-surface-600 dark:text-surface-400">Human-only</div>
|
|
</div>
|
|
<div class="text-center p-3 rounded-lg bg-surface-50 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 shadow-sm">
|
|
<div class="text-2xl font-bold text-surface-900 dark:text-surface-100">{{ stats.percentage }}%</div>
|
|
<div class="text-xs text-surface-600 dark:text-surface-400">AI ratio</div>
|
|
</div>
|
|
</div>
|
|
|
|
{# Breakdown by level #}
|
|
<div class="flex flex-wrap gap-3 text-sm mb-6">
|
|
<span class="px-3 py-1 rounded-full bg-surface-100 dark:bg-surface-700 text-surface-600 dark:text-surface-300">
|
|
Level 0 (None): {{ stats.byLevel[0] }}
|
|
</span>
|
|
<span class="px-3 py-1 rounded-full bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300">
|
|
Level 1 (Editorial): {{ stats.byLevel[1] }}
|
|
</span>
|
|
<span class="px-3 py-1 rounded-full bg-amber-100 dark:bg-amber-900/40 text-amber-800 dark:text-amber-200">
|
|
Level 2 (Co-drafted): {{ stats.byLevel[2] }}
|
|
</span>
|
|
<span class="px-3 py-1 rounded-full bg-amber-200 dark:bg-amber-900/60 text-amber-900 dark:text-amber-100">
|
|
Level 3 (AI-generated): {{ stats.byLevel[3] }}
|
|
</span>
|
|
</div>
|
|
|
|
{# Post graph showing AI posts (highlighted) on the full year grid #}
|
|
<h3 class="text-lg font-semibold text-surface-900 dark:text-surface-100 mb-3">AI-Involved Posts Over Time</h3>
|
|
<p class="text-sm text-surface-600 dark:text-surface-400 mb-4">Highlighted days had posts with AI involvement (level 1+). Empty boxes represent days with no AI-involved posts.</p>
|
|
{% postGraph aiPostsList, { prefix: "ai", highlightColorLight: "#d97706", highlightColorDark: "#fbbf24" } %}
|
|
</section>
|
|
{% endif %}
|
|
|
|
{# Categories/tags if present #}
|
|
{% if category %}
|
|
<footer class="mt-8 pt-6 border-t border-surface-200 dark:border-surface-700">
|
|
<div class="flex flex-wrap gap-2">
|
|
{% if category is string %}
|
|
<a href="/categories/{{ category | nestedSlugify }}/" class="p-category text-sm px-3 py-1 bg-surface-100 dark:bg-surface-800 rounded-full hover:bg-surface-200 dark:hover:bg-surface-700 transition-colors">
|
|
{{ category }}
|
|
</a>
|
|
{% else %}
|
|
{% for cat in category %}
|
|
<a href="/categories/{{ cat | nestedSlugify }}/" class="p-category text-sm px-3 py-1 bg-surface-100 dark:bg-surface-800 rounded-full hover:bg-surface-200 dark:hover:bg-surface-700 transition-colors">
|
|
{{ cat }}
|
|
</a>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</div>
|
|
</footer>
|
|
{% endif %}
|
|
|
|
{# Hidden metadata for microformats #}
|
|
<a class="u-url hidden" href="{{ page.url }}"></a>
|
|
<data class="p-author h-card hidden" value="{{ site.author.name }}"></data>
|
|
|
|
{# Pagefind filter metadata #}
|
|
<div hidden>
|
|
<span data-pagefind-filter="type">Page</span>
|
|
<span data-pagefind-filter="ai-text-level">{{ aiTextLevel }}</span>
|
|
<span data-pagefind-filter="ai-code-level">{{ aiCodeLevel or "0" }}</span>
|
|
<span data-pagefind-filter="ai-used">{% if aiUsed %}yes{% else %}no{% endif %}</span>
|
|
{% if category %}
|
|
{% if category is string %}
|
|
<span data-pagefind-filter="category">{{ category }}</span>
|
|
{% else %}
|
|
{% for cat in category %}
|
|
<span data-pagefind-filter="category">{{ cat }}</span>
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% endif %}
|
|
</div>
|
|
|
|
{# JSON-LD Structured Data for pages with AI transparency metadata #}
|
|
<script type="application/ld+json">
|
|
{
|
|
"@context": "https://schema.org",
|
|
"@type": "WebPage",
|
|
"name": {{ title | dump | safe }},
|
|
"url": "{{ site.url }}{{ page.url }}",
|
|
"datePublished": "{{ page.date | isoDate }}",
|
|
"dateModified": "{{ (updated or page.date) | isoDate }}",
|
|
"usageInfo": "{{ site.url }}/ai"{% set _aiParts = [] %}{% if aiTextLevel %}{% set _textLabel %}{% if aiTextLevel === "0" %}None{% elif aiTextLevel === "1" %}Editorial assistance{% elif aiTextLevel === "2" %}Co-drafting{% elif aiTextLevel === "3" %}AI-generated{% endif %}{% endset %}{% set _aiParts = (_aiParts.push("Text: " + _textLabel), _aiParts) %}{% endif %}{% if aiCodeLevel %}{% set _codeLabel %}{% if aiCodeLevel === "0" %}Human-written{% elif aiCodeLevel === "1" %}AI-assisted{% elif aiCodeLevel === "2" %}AI-generated{% endif %}{% endset %}{% set _aiParts = (_aiParts.push("Code: " + _codeLabel), _aiParts) %}{% endif %}{% if aiTools %}{% set _aiParts = (_aiParts.push("Tools: " + aiTools), _aiParts) %}{% endif %},
|
|
"creativeWorkStatus": "{{ _aiParts | join(', ') }}",
|
|
"additionalProperty": [
|
|
{ "@type": "PropertyValue", "name": "aiTextLevel", "value": "{{ aiTextLevel }}" },
|
|
{ "@type": "PropertyValue", "name": "aiCodeLevel", "value": "{{ aiCodeLevel or '0' }}" }{% if aiTools %},
|
|
{ "@type": "PropertyValue", "name": "aiTools", "value": {{ aiTools | dump | safe }} }{% endif %}
|
|
]{% if aiDescription %},
|
|
"abstract": {{ aiDescription | dump | safe }}{% endif %}
|
|
}
|
|
</script>
|
|
</article>
|