Files
kennethreitz 943bfe3e6c Fix theme name casing — store proper display names
AI Personalities not Ai Personalities, API Design not Api Design.
Theme names now stored with correct casing in cache, removed | title
filter from templates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:43:55 -04:00

255 lines
5.5 KiB
HTML

{% extends "base.html" %}
{% block title %}Themes{% endblock %}
{% block content %}
<article>
<h1>Themes Index</h1>
<p class="subtitle">{{ total_themes }} recurring patterns across {{ total_occurrences }} essays</p>
<p>These themes are detected programmatically — the site scans essay content for recurring patterns and groups them automatically. No manual tagging or curation. What shows up here is what the writing actually returns to, whether I intended it or not. For the hand-curated version, see <a href="/themes">the themes index</a>.</p>
<section>
{% if themes %}
{% for theme, data in themes.items() %}
<div class="theme-section" id="{{ theme|replace(' ', '-') }}">
<div class="theme-header">
<strong>{{ theme }}</strong>
<span class="theme-count">({{ data.articles | length }})</span>
</div>
{% if data.description %}
<p class="theme-description">{{ data.description }}</p>
{% endif %}
<details class="theme-details">
<summary>Show {{ data.articles | length }} article{{ 's' if data.articles | length != 1 else '' }}</summary>
<ul>
{% for article in data.articles|sort(attribute='date', reverse=true) %}
<li>
{% if article.unique_icon %}
<img src="{{ article.unique_icon }}" alt="" class="article-icon">
{% endif %}
<a href="{{ article.url }}">{{ article.title }}</a>
</li>
{% endfor %}
</ul>
</details>
</div>
{% endfor %}
{% else %}
<p>No themes found.</p>
{% endif %}
</section>
</article>
<style>
.subtitle {
font-style: italic;
color: #666;
margin-top: -1rem;
margin-bottom: 2.5rem;
font-size: 1.1rem;
}
.theme-section {
margin-bottom: 3rem;
padding-bottom: 2rem;
border-bottom: 1px solid #eee;
scroll-margin-top: 2rem;
max-width: 65%;
}
.theme-section:last-child {
border-bottom: none;
}
.theme-header {
margin-bottom: 0.75rem;
}
.theme-header strong {
font-size: 1.4rem;
font-weight: 600;
color: #333;
}
.theme-details {
margin-top: 0.75rem;
}
.theme-details summary {
cursor: pointer;
padding: 0.5rem 0 0.5rem 1rem;
user-select: none;
color: #666;
font-size: 0.9rem;
}
.theme-details summary:hover {
color: #000;
}
.theme-count {
color: #999;
font-size: 1rem;
margin-left: 0.75rem;
font-weight: 400;
}
.theme-details ul {
margin-top: 1rem;
padding-left: 3rem;
line-height: 1.8;
}
.theme-details li {
margin-bottom: 0.75rem;
display: flex;
align-items: center;
gap: 0.75rem;
}
.article-icon {
width: 16px;
height: 16px;
flex-shrink: 0;
}
.date {
color: #999;
font-size: 0.85rem;
margin-left: 0.5rem;
}
.theme-description {
color: #666;
font-size: 1rem;
font-style: italic;
margin: 0 0 1rem 0;
padding-left: 0;
line-height: 1.6;
}
@media (max-width: 768px) {
.theme-section {
max-width: 100%;
}
.theme-header strong {
font-size: 1.2rem;
}
.theme-description {
font-size: 0.95rem;
}
.theme-details summary {
padding-left: 0.5rem;
font-size: 0.9rem;
}
.theme-details ul {
padding-left: 2rem;
}
}
body.light-mode .subtitle {
color: #666 !important;
}
body.light-mode .theme-section {
border-bottom-color: #eee !important;
}
body.light-mode .theme-header strong {
color: #333 !important;
}
body.light-mode .theme-description {
color: #666 !important;
}
body.light-mode .theme-details summary {
color: #666 !important;
}
body.light-mode .theme-details summary:hover {
color: #000 !important;
}
body.light-mode .date {
color: #999 !important;
}
body.light-mode .theme-details ul li a {
color: #333 !important;
}
body.light-mode .theme-count {
color: #999 !important;
}
body.dark-mode .subtitle {
color: #999;
}
body.dark-mode .theme-section {
border-bottom-color: #2a2a2a;
}
body.dark-mode .theme-header strong {
color: #e5e5e5;
}
body.dark-mode .theme-description {
color: #999;
}
body.dark-mode .theme-details summary {
color: #999;
}
body.dark-mode .theme-details summary:hover {
color: #ccc;
}
body.dark-mode .date {
color: #666;
}
body.dark-mode .theme-details ul li a {
color: #ccc;
}
body.dark-mode .theme-details ul li a:hover {
color: #fff;
}
body.dark-mode .theme-count {
color: #666;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Check if there's a hash in the URL
if (window.location.hash) {
const hash = window.location.hash.substring(1);
const themeSection = document.getElementById(hash);
if (themeSection) {
// Find the details element within this section
const details = themeSection.querySelector('.theme-details');
if (details) {
// Open the details element
details.setAttribute('open', '');
}
// Scroll to the section with a slight delay to ensure it's expanded
setTimeout(() => {
themeSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
}, 100);
}
}
});
</script>
{% endblock %}