feat: warm palette overhaul — cold zinc/teal to warm stone/amber

Replace the entire color system with a design-driven warm palette:

- Surface tokens: cold zinc grays → warm stone (#faf8f5 to #0f0e0d)
- Accent tokens: cold teal → warm amber (#fffbeb to #451a03)
- All bg-white → bg-surface-50 across templates (warm cream instead of pure white)
- Critical CSS: all hardcoded hex values updated to warm palette
- Prism code blocks: cold gray backgrounds → warm stone
- Pagefind search UI: blue buttons/links → amber interactive colors
- Dark mode: warm dark surfaces with amber accents throughout

Design system documented in .interface-design/system.md

Confab-Link: http://localhost:8080/sessions/bd3f7012-c703-47e9-bfe2-2ad04ce1842d
This commit is contained in:
Ricardo
2026-03-04 14:02:59 +01:00
parent 155816a0bc
commit 8e393e215d
32 changed files with 272 additions and 176 deletions

View File

@@ -0,0 +1,93 @@
# Design System — rmendes.net
## Direction: Workshop Terminal
**Feel:** A well-configured terminal in a warm room. Structure is precise and technical. Warmth comes from surfaces and content, not decorative color. Color is signal, not decoration.
**Signature:** Chromatically quiet at rest, vivid in context. The base is warm monochrome. Color enters when content demands it — music pages glow purple, code pages pulse emerald, social feeds carry brand colors. You feel the shift as you navigate between worlds.
## Intent
**Who:** Visitors to a DevOps engineer's personal site — peers, recruiters, fellow IndieWeb enthusiasts, RSS subscribers. They're reading, browsing, discovering.
**What:** Read posts, explore interests, follow feeds, understand who this person is.
**How it should feel:** Like opening a well-used notebook in a workshop. Technical precision meets personal warmth. Not corporate, not cold, not decorative.
## Surfaces — Warm Stone
Warm neutral tones. Not yellow — just not cold. The difference is felt, not seen.
| Token | Light | Dark | Role |
|-------|-------|------|------|
| 50 | `#faf8f5` | — | Canvas background |
| 100 | `#f4f2ee` | — | Card surfaces |
| 200 | `#e8e5df` | — | Borders, dividers |
| 300 | `#d5d0c8` | — | Strong borders |
| 400 | `#a09a90` | — | Muted/placeholder text |
| 500 | `#7a746a` | — | Secondary text |
| 600 | `#5c5750` | — | — |
| 700 | `#3f3b35` | — | Dark text secondary |
| 800 | `#2a2722` | — | Card surfaces (dark) |
| 900 | `#1c1b19` | — | Canvas (dark) |
| 950 | `#0f0e0d` | — | Deepest dark |
## Text Hierarchy
| Level | Light | Dark | Usage |
|-------|-------|------|-------|
| Primary | surface-900 `#1c1b19` | surface-50 `#faf8f5` | Headlines, body |
| Secondary | surface-600 `#5c5750` | surface-400 `#a09a90` | Supporting text |
| Muted | surface-400 `#a09a90` | surface-600 `#5c5750` | Metadata, timestamps |
| Faint | surface-300 `#d5d0c8` | surface-700 `#3f3b35` | Disabled, decorative |
## Interactive — Accent (Warm Amber)
Default interactive color for generic links, CTAs, focus rings. Terminal amber warmth.
| Weight | Value | Usage |
|--------|-------|-------|
| 400 | `#fbbf24` | Dark mode links, hover states |
| 500 | `#f59e0b` | — |
| 600 | `#d97706` | Light mode links, buttons |
| 700 | `#b45309` | Light mode hover |
## Domain Colors
Each section of the site owns its chromatic identity. These override accent on their respective pages.
| Domain | Tailwind Color | Pages |
|--------|---------------|-------|
| Writing/Blog | amber (= accent) | blog, articles, notes, homepage |
| Code/GitHub | emerald | github, repo widgets |
| Music | violet | funkwhale, listening, last.fm |
| Bluesky | `#0085ff` | social-activity bluesky tab |
| Mastodon | `#a730b8` | social-activity mastodon tab |
| Bookmarks | amber | bookmarks page |
| Likes | rose | likes page |
| Replies | sky | replies page |
| Reposts | emerald | reposts page |
| Photos | violet | photos page |
| RSS/Podcasts | orange | podroll, subscribe, RSS links |
| CV | neutral (no accent) | cv page |
## Typography
- **Body:** Inter — clean, technical sans-serif
- **Metadata:** `font-mono` for dates, timestamps, stats, version numbers
- **Headlines:** Inter bold, tight tracking
## Depth Strategy
**Borders only.** No drop shadows. Low-opacity warm borders define surfaces. Hierarchy comes from surface color shifts, not elevation effects.
## Spacing
Base: 4px (Tailwind default). No custom scale needed.
## Dark Mode
- Surfaces invert (dark warm canvas, lighter warm cards)
- Domain colors use their 400-weight for dark mode (lighter/brighter)
- Borders use warm low-opacity rgba
- No shadows in either mode

View File

@@ -72,7 +72,7 @@
class="widget-collapsible mb-4" class="widget-collapsible mb-4"
x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : {{ defaultOpen }} }" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : {{ defaultOpen }} }"
> >
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden {{ widgetBorder }}"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden {{ widgetBorder }}">
<button <button
class="widget-header w-full p-4" class="widget-header w-full p-4"
@click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)"
@@ -167,7 +167,7 @@
{# Author Card Compact #} {# Author Card Compact #}
{% set widgetKey = "post-fb-author-card-compact" %} {% set widgetKey = "post-fb-author-card-compact" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : true }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : true }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("user", "w-5 h-5 text-surface-500") }} Author</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("user", "w-5 h-5 text-surface-500") }} Author</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -181,7 +181,7 @@
{# Table of Contents #} {# Table of Contents #}
{% set widgetKey = "post-fb-toc" %} {% set widgetKey = "post-fb-toc" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : true }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : true }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("list", "w-5 h-5 text-surface-500") }} Table of Contents</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("list", "w-5 h-5 text-surface-500") }} Table of Contents</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -195,7 +195,7 @@
{# Post Categories #} {# Post Categories #}
{% set widgetKey = "post-fb-post-categories" %} {% set widgetKey = "post-fb-post-categories" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : true }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : true }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("tag", "w-5 h-5 text-surface-500") }} Categories</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("tag", "w-5 h-5 text-surface-500") }} Categories</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -209,7 +209,7 @@
{# Recent Posts #} {# Recent Posts #}
{% set widgetKey = "post-fb-recent-posts" %} {% set widgetKey = "post-fb-recent-posts" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("list", "w-5 h-5 text-surface-500") }} Recent Posts</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("list", "w-5 h-5 text-surface-500") }} Recent Posts</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -223,7 +223,7 @@
{# Webmentions #} {# Webmentions #}
{% set widgetKey = "post-fb-webmentions" %} {% set widgetKey = "post-fb-webmentions" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("share", "w-5 h-5 text-surface-500") }} Webmentions</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("share", "w-5 h-5 text-surface-500") }} Webmentions</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -237,7 +237,7 @@
{# Share #} {# Share #}
{% set widgetKey = "post-fb-share" %} {% set widgetKey = "post-fb-share" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("share", "w-5 h-5 text-surface-500") }} Share</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("share", "w-5 h-5 text-surface-500") }} Share</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -251,7 +251,7 @@
{# Subscribe #} {# Subscribe #}
{% set widgetKey = "post-fb-subscribe" %} {% set widgetKey = "post-fb-subscribe" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden border-l-[3px] border-l-orange-400 dark:border-l-orange-500"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden border-l-[3px] border-l-orange-400 dark:border-l-orange-500">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("rss", "w-5 h-5 text-orange-500") }} Subscribe</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("rss", "w-5 h-5 text-orange-500") }} Subscribe</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -265,7 +265,7 @@
{# Recent Comments #} {# Recent Comments #}
{% set widgetKey = "post-fb-recent-comments" %} {% set widgetKey = "post-fb-recent-comments" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("chat", "w-5 h-5 text-surface-500") }} Recent Comments</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("chat", "w-5 h-5 text-surface-500") }} Recent Comments</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>

View File

@@ -13,7 +13,7 @@
x-transition:leave-end="opacity-0" x-transition:leave-end="opacity-0"
@click="showModal = false"></div> @click="showModal = false"></div>
{# Panel #} {# Panel #}
<div class="relative bg-white dark:bg-surface-800 rounded-xl shadow-xl w-full max-w-sm p-6" <div class="relative bg-surface-50 dark:bg-surface-800 rounded-xl shadow-xl w-full max-w-sm p-6"
x-transition:enter="transition ease-out duration-200" x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 scale-95" x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100" x-transition:enter-end="opacity-100 scale-100"
@@ -60,7 +60,7 @@
@keydown.enter.prevent="confirm()" @keydown.enter.prevent="confirm()"
type="text" type="text"
placeholder="mastodon.social" placeholder="mastodon.social"
class="w-full px-3 py-2 border border-surface-300 dark:border-surface-600 rounded-lg bg-white dark:bg-surface-700 text-surface-900 dark:text-surface-100 placeholder-surface-400 focus:outline-none focus:ring-2 focus:ring-[#a730b8] focus:border-transparent text-sm"> class="w-full px-3 py-2 border border-surface-300 dark:border-surface-600 rounded-lg bg-surface-50 dark:bg-surface-700 text-surface-900 dark:text-surface-100 placeholder-surface-400 focus:outline-none focus:ring-2 focus:ring-[#a730b8] focus:border-transparent text-sm">
<template x-if="error"> <template x-if="error">
<p class="text-xs text-red-500 mt-1" x-text="error"></p> <p class="text-xs text-red-500 mt-1" x-text="error"></p>
</template> </template>

View File

@@ -1,19 +1,19 @@
{# Stats Summary Cards #} {# Stats Summary Cards #}
{% if summary %} {% if summary %}
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3 sm:gap-4 mb-6 sm:mb-8"> <div class="grid grid-cols-2 sm:grid-cols-4 gap-3 sm:gap-4 mb-6 sm:mb-8">
<div class="p-4 bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 text-center"> <div class="p-4 bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 text-center">
<span class="text-2xl font-bold text-purple-600 dark:text-purple-400 block">{{ summary.totalPlays or 0 }}</span> <span class="text-2xl font-bold text-purple-600 dark:text-purple-400 block">{{ summary.totalPlays or 0 }}</span>
<span class="text-xs text-surface-500 uppercase tracking-wide">Plays</span> <span class="text-xs text-surface-500 uppercase tracking-wide">Plays</span>
</div> </div>
<div class="p-4 bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 text-center"> <div class="p-4 bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 text-center">
<span class="text-2xl font-bold text-purple-600 dark:text-purple-400 block">{{ summary.uniqueTracks or 0 }}</span> <span class="text-2xl font-bold text-purple-600 dark:text-purple-400 block">{{ summary.uniqueTracks or 0 }}</span>
<span class="text-xs text-surface-500 uppercase tracking-wide">Tracks</span> <span class="text-xs text-surface-500 uppercase tracking-wide">Tracks</span>
</div> </div>
<div class="p-4 bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 text-center"> <div class="p-4 bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 text-center">
<span class="text-2xl font-bold text-purple-600 dark:text-purple-400 block">{{ summary.uniqueArtists or 0 }}</span> <span class="text-2xl font-bold text-purple-600 dark:text-purple-400 block">{{ summary.uniqueArtists or 0 }}</span>
<span class="text-xs text-surface-500 uppercase tracking-wide">Artists</span> <span class="text-xs text-surface-500 uppercase tracking-wide">Artists</span>
</div> </div>
<div class="p-4 bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 text-center"> <div class="p-4 bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 text-center">
<span class="text-2xl font-bold text-purple-600 dark:text-purple-400 block">{{ summary.totalDurationFormatted or '0m' }}</span> <span class="text-2xl font-bold text-purple-600 dark:text-purple-400 block">{{ summary.totalDurationFormatted or '0m' }}</span>
<span class="text-xs text-surface-500 uppercase tracking-wide">Listened</span> <span class="text-xs text-surface-500 uppercase tracking-wide">Listened</span>
</div> </div>
@@ -26,7 +26,7 @@
<h3 class="text-lg font-semibold text-surface-900 dark:text-surface-100 mb-4">Top Artists</h3> <h3 class="text-lg font-semibold text-surface-900 dark:text-surface-100 mb-4">Top Artists</h3>
<div class="space-y-2"> <div class="space-y-2">
{% for artist in topArtists | head(5) %} {% for artist in topArtists | head(5) %}
<div class="flex items-center gap-3 p-3 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700"> <div class="flex items-center gap-3 p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700">
<span class="w-6 h-6 flex items-center justify-center text-sm font-bold text-surface-400 bg-surface-100 dark:bg-surface-700 rounded-full">{{ loop.index }}</span> <span class="w-6 h-6 flex items-center justify-center text-sm font-bold text-surface-400 bg-surface-100 dark:bg-surface-700 rounded-full">{{ loop.index }}</span>
<span class="flex-1 font-medium text-surface-900 dark:text-surface-100">{{ artist.name }}</span> <span class="flex-1 font-medium text-surface-900 dark:text-surface-100">{{ artist.name }}</span>
<span class="text-sm text-surface-500">{{ artist.playCount }} plays</span> <span class="text-sm text-surface-500">{{ artist.playCount }} plays</span>

View File

@@ -61,7 +61,7 @@
class="widget-collapsible mb-4" class="widget-collapsible mb-4"
x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : {{ defaultOpen }} }" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : {{ defaultOpen }} }"
> >
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden {{ widgetBorder }}"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden {{ widgetBorder }}">
<button <button
class="widget-header w-full p-4" class="widget-header w-full p-4"
@click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)"

View File

@@ -14,7 +14,7 @@
<div class="space-y-3"> <div class="space-y-3">
{% for item in cv.education %} {% for item in cv.education %}
{% if not filterType or item.educationType == filterType or not item.educationType %} {% if not filterType or item.educationType == filterType or not item.educationType %}
<div class="p-4 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700"> <div class="p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700">
<h3 class="font-semibold text-surface-900 dark:text-surface-100">{{ item.degree }}</h3> <h3 class="font-semibold text-surface-900 dark:text-surface-100">{{ item.degree }}</h3>
<p class="text-sm text-surface-600 dark:text-surface-400"> <p class="text-sm text-surface-600 dark:text-surface-400">
{{ item.institution }}{% if item.location %} &middot; {{ item.location }}{% endif %} {{ item.institution }}{% if item.location %} &middot; {{ item.location }}{% endif %}

View File

@@ -34,7 +34,7 @@
{% if showHighlights and item.highlights and item.highlights.length %} {% if showHighlights and item.highlights and item.highlights.length %}
<div class="flex flex-wrap gap-1.5 mt-2"> <div class="flex flex-wrap gap-1.5 mt-2">
{% for h in item.highlights %} {% for h in item.highlights %}
<span class="px-2.5 py-1 bg-white dark:bg-surface-800 border border-surface-200 dark:border-surface-700 rounded-full text-xs text-surface-700 dark:text-surface-300"> <span class="px-2.5 py-1 bg-surface-50 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 rounded-full text-xs text-surface-700 dark:text-surface-300">
{{ h }} {{ h }}
</span> </span>
{% endfor %} {% endfor %}

View File

@@ -12,7 +12,7 @@
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
{% for category, items in cv.interests %} {% for category, items in cv.interests %}
{% if not filterType or (cv.interestTypes and cv.interestTypes[category] == filterType) or not cv.interestTypes or not cv.interestTypes[category] %} {% if not filterType or (cv.interestTypes and cv.interestTypes[category] == filterType) or not cv.interestTypes or not cv.interestTypes[category] %}
<div class="p-4 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700"> <div class="p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700">
<h3 class="font-semibold text-sm uppercase tracking-wide text-surface-600 dark:text-surface-400 mb-2"> <h3 class="font-semibold text-sm uppercase tracking-wide text-surface-600 dark:text-surface-400 mb-2">
{{ category }} {{ category }}
</h3> </h3>

View File

@@ -11,7 +11,7 @@
<div class="flex flex-wrap gap-3"> <div class="flex flex-wrap gap-3">
{% for lang in cv.languages %} {% for lang in cv.languages %}
<div class="flex items-center gap-2 px-3 py-1.5 bg-white dark:bg-surface-800 rounded-full border border-surface-200 dark:border-surface-700"> <div class="flex items-center gap-2 px-3 py-1.5 bg-surface-50 dark:bg-surface-800 rounded-full border border-surface-200 dark:border-surface-700">
<span class="font-medium text-sm text-surface-900 dark:text-surface-100">{{ lang.name }}</span> <span class="font-medium text-sm text-surface-900 dark:text-surface-100">{{ lang.name }}</span>
<span class="text-xs text-surface-500 capitalize">{{ lang.level }}</span> <span class="text-xs text-surface-500 capitalize">{{ lang.level }}</span>
</div> </div>

View File

@@ -25,7 +25,7 @@
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
{% for item in personalProjects | head(maxItems) %} {% for item in personalProjects | head(maxItems) %}
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors overflow-hidden">
{# Summary row — always visible, clickable #} {# Summary row — always visible, clickable #}
<button <button
class="w-full p-4 flex items-center justify-between gap-2 cursor-pointer text-left hover:bg-surface-50 dark:hover:bg-surface-700/50 transition-colors" class="w-full p-4 flex items-center justify-between gap-2 cursor-pointer text-left hover:bg-surface-50 dark:hover:bg-surface-700/50 transition-colors"

View File

@@ -25,7 +25,7 @@
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
{% for item in workProjects | head(maxItems) %} {% for item in workProjects | head(maxItems) %}
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors overflow-hidden">
{# Summary row — always visible, clickable #} {# Summary row — always visible, clickable #}
<button <button
class="w-full p-4 flex items-center justify-between gap-2 cursor-pointer text-left hover:bg-surface-50 dark:hover:bg-surface-700/50 transition-colors" class="w-full p-4 flex items-center justify-between gap-2 cursor-pointer text-left hover:bg-surface-50 dark:hover:bg-surface-700/50 transition-colors"

View File

@@ -15,7 +15,7 @@
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
{% for item in cv.projects | head(maxItems) %} {% for item in cv.projects | head(maxItems) %}
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors overflow-hidden">
{# Summary row — always visible, clickable #} {# Summary row — always visible, clickable #}
<button <button
class="w-full p-4 flex items-center justify-between gap-2 cursor-pointer text-left hover:bg-surface-50 dark:hover:bg-surface-700/50 transition-colors" class="w-full p-4 flex items-center justify-between gap-2 cursor-pointer text-left hover:bg-surface-50 dark:hover:bg-surface-700/50 transition-colors"

View File

@@ -12,7 +12,7 @@
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
{% for category, items in cv.skills %} {% for category, items in cv.skills %}
{% if not filterType or (cv.skillTypes and cv.skillTypes[category] == filterType) or not cv.skillTypes or not cv.skillTypes[category] %} {% if not filterType or (cv.skillTypes and cv.skillTypes[category] == filterType) or not cv.skillTypes or not cv.skillTypes[category] %}
<div class="p-4 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700"> <div class="p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700">
<h3 class="font-semibold text-sm uppercase tracking-wide text-surface-600 dark:text-surface-400 mb-2"> <h3 class="font-semibold text-sm uppercase tracking-wide text-surface-600 dark:text-surface-400 mb-2">
{{ category }} {{ category }}
</h3> </h3>

View File

@@ -39,7 +39,7 @@
{% set borderClass = "border-l-[3px] border-l-surface-300 dark:border-l-surface-600" %} {% set borderClass = "border-l-[3px] border-l-surface-300 dark:border-l-surface-600" %}
{% endif %} {% endif %}
<article class="h-entry p-4 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors {{ borderClass }}"> <article class="h-entry p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors {{ borderClass }}">
{% if likedUrl %} {% if likedUrl %}
{# ── Like card ── #} {# ── Like card ── #}

View File

@@ -65,7 +65,7 @@
class="widget-collapsible mb-4" class="widget-collapsible mb-4"
x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : {{ defaultOpen }} }" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : {{ defaultOpen }} }"
> >
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden {{ widgetBorder }}"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden {{ widgetBorder }}">
<button <button
class="widget-header w-full p-4" class="widget-header w-full p-4"
@click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)"
@@ -156,7 +156,7 @@
{# Author Card (h-card) — always shown #} {# Author Card (h-card) — always shown #}
{% set widgetKey = "listing-fb-author-card" %} {% set widgetKey = "listing-fb-author-card" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : true }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : true }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("user", "w-5 h-5 text-surface-500") }} Author</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("user", "w-5 h-5 text-surface-500") }} Author</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -170,7 +170,7 @@
{# Social Activity — Bluesky/Mastodon feeds #} {# Social Activity — Bluesky/Mastodon feeds #}
{% set widgetKey = "listing-fb-social-activity" %} {% set widgetKey = "listing-fb-social-activity" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : true }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : true }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden border-l-[3px] border-l-[#0085ff]"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden border-l-[3px] border-l-[#0085ff]">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("globe", "w-5 h-5 text-[#0085ff]") }} Social Activity</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("globe", "w-5 h-5 text-[#0085ff]") }} Social Activity</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -184,7 +184,7 @@
{# GitHub Repos #} {# GitHub Repos #}
{% set widgetKey = "listing-fb-github-repos" %} {% set widgetKey = "listing-fb-github-repos" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : true }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : true }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden border-l-[3px] border-l-surface-400 dark:border-l-surface-500"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden border-l-[3px] border-l-surface-400 dark:border-l-surface-500">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("github", "w-5 h-5 text-surface-800 dark:text-surface-200") }} GitHub</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("github", "w-5 h-5 text-surface-800 dark:text-surface-200") }} GitHub</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -198,7 +198,7 @@
{# Funkwhale — Now Playing / Listening Stats #} {# Funkwhale — Now Playing / Listening Stats #}
{% set widgetKey = "listing-fb-funkwhale" %} {% set widgetKey = "listing-fb-funkwhale" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden border-l-[3px] border-l-purple-400 dark:border-l-purple-500"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden border-l-[3px] border-l-purple-400 dark:border-l-purple-500">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("headphones", "w-5 h-5 text-purple-500") }} Listening</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("headphones", "w-5 h-5 text-purple-500") }} Listening</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -212,7 +212,7 @@
{# Recent Posts #} {# Recent Posts #}
{% set widgetKey = "listing-fb-recent-posts" %} {% set widgetKey = "listing-fb-recent-posts" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("list", "w-5 h-5 text-surface-500") }} Recent Posts</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("list", "w-5 h-5 text-surface-500") }} Recent Posts</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -227,7 +227,7 @@
{% if blogrollStatus and blogrollStatus.source == "indiekit" %} {% if blogrollStatus and blogrollStatus.source == "indiekit" %}
{% set widgetKey = "listing-fb-blogroll" %} {% set widgetKey = "listing-fb-blogroll" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden border-l-[3px] border-l-amber-400 dark:border-l-amber-500"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden border-l-[3px] border-l-amber-400 dark:border-l-amber-500">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("book-open", "w-5 h-5 text-amber-500") }} Blogroll</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("book-open", "w-5 h-5 text-amber-500") }} Blogroll</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -243,7 +243,7 @@
{% if blogrollStatus and blogrollStatus.source == "indiekit" %} {% if blogrollStatus and blogrollStatus.source == "indiekit" %}
{% set widgetKey = "listing-fb-feedland" %} {% set widgetKey = "listing-fb-feedland" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden border-l-[3px] border-l-amber-400 dark:border-l-amber-500"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden border-l-[3px] border-l-amber-400 dark:border-l-amber-500">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("rss", "w-5 h-5 text-amber-500") }} FeedLand</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("rss", "w-5 h-5 text-amber-500") }} FeedLand</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -258,7 +258,7 @@
{# Recent Comments #} {# Recent Comments #}
{% set widgetKey = "listing-fb-recent-comments" %} {% set widgetKey = "listing-fb-recent-comments" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("chat", "w-5 h-5 text-surface-500") }} Recent Comments</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("chat", "w-5 h-5 text-surface-500") }} Recent Comments</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
@@ -272,7 +272,7 @@
{# Categories/Tags #} {# Categories/Tags #}
{% set widgetKey = "listing-fb-categories" %} {% set widgetKey = "listing-fb-categories" %}
<div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }"> <div class="widget-collapsible mb-4" x-data="{ open: localStorage.getItem('{{ widgetKey }}') !== null ? localStorage.getItem('{{ widgetKey }}') === 'true' : false }">
<div class="bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden"> <div class="bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden">
<button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'"> <button class="widget-header w-full p-4" @click="open = !open; localStorage.setItem('{{ widgetKey }}', open)" :aria-expanded="open ? 'true' : 'false'">
<h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("tag", "w-5 h-5 text-surface-500") }} Categories</h3> <h3 class="widget-title font-bold text-lg flex items-center gap-2">{{ icon("tag", "w-5 h-5 text-surface-500") }} Categories</h3>
<svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="widget-chevron" :class="open && 'rotate-180'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>

View File

@@ -190,7 +190,7 @@
name="source" name="source"
placeholder="https://your-site.com/response" placeholder="https://your-site.com/response"
required required
class="flex-1 px-3 py-2 text-sm bg-white dark:bg-surface-700 border border-surface-300 dark:border-surface-600 rounded focus:outline-none focus:ring-2 focus:ring-accent-500" class="flex-1 px-3 py-2 text-sm bg-surface-50 dark:bg-surface-700 border border-surface-300 dark:border-surface-600 rounded focus:outline-none focus:ring-2 focus:ring-accent-500"
> >
<button <button
type="submit" type="submit"

View File

@@ -79,7 +79,7 @@ withSidebar: true
<h2 class="text-xl sm:text-2xl font-bold text-surface-900 dark:text-surface-100 mb-4 sm:mb-6">Recent Posts</h2> <h2 class="text-xl sm:text-2xl font-bold text-surface-900 dark:text-surface-100 mb-4 sm:mb-6">Recent Posts</h2>
<div class="space-y-4"> <div class="space-y-4">
{% for post in collections.posts | head(10) %} {% for post in collections.posts | head(10) %}
<article class="p-4 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors"> <article class="p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors">
<h3 class="font-semibold text-surface-900 dark:text-surface-100 mb-1"> <h3 class="font-semibold text-surface-900 dark:text-surface-100 mb-1">
<a href="{{ post.url }}" class="hover:text-accent-600 dark:hover:text-accent-400"> <a href="{{ post.url }}" class="hover:text-accent-600 dark:hover:text-accent-400">
{{ post.data.title or post.data.name or "Untitled" }} {{ post.data.title or post.data.name or "Untitled" }}
@@ -110,7 +110,7 @@ withSidebar: true
<section class="mb-8 sm:mb-12"> <section class="mb-8 sm:mb-12">
<h2 class="text-xl sm:text-2xl font-bold text-surface-900 dark:text-surface-100 mb-4 sm:mb-6">Explore</h2> <h2 class="text-xl sm:text-2xl font-bold text-surface-900 dark:text-surface-100 mb-4 sm:mb-6">Explore</h2>
<div class="grid gap-3 sm:grid-cols-3"> <div class="grid gap-3 sm:grid-cols-3">
<a href="/blog/" class="p-4 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors text-center"> <a href="/blog/" class="p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors text-center">
<div class="text-2xl mb-2"> <div class="text-2xl mb-2">
<svg class="w-8 h-8 mx-auto text-accent-600 dark:text-accent-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"> <svg class="w-8 h-8 mx-auto text-accent-600 dark:text-accent-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/> <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/>
@@ -119,7 +119,7 @@ withSidebar: true
<span class="font-semibold text-surface-900 dark:text-surface-100">Blog</span> <span class="font-semibold text-surface-900 dark:text-surface-100">Blog</span>
<p class="text-sm text-surface-600 dark:text-surface-400 mt-1">Articles, notes, and photos</p> <p class="text-sm text-surface-600 dark:text-surface-400 mt-1">Articles, notes, and photos</p>
</a> </a>
<a href="/cv/" class="p-4 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors text-center"> <a href="/cv/" class="p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors text-center">
<div class="text-2xl mb-2"> <div class="text-2xl mb-2">
<svg class="w-8 h-8 mx-auto text-accent-600 dark:text-accent-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"> <svg class="w-8 h-8 mx-auto text-accent-600 dark:text-accent-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<rect x="2" y="7" width="20" height="14" rx="2" ry="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/> <rect x="2" y="7" width="20" height="14" rx="2" ry="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/>
@@ -128,7 +128,7 @@ withSidebar: true
<span class="font-semibold text-surface-900 dark:text-surface-100">CV</span> <span class="font-semibold text-surface-900 dark:text-surface-100">CV</span>
<p class="text-sm text-surface-600 dark:text-surface-400 mt-1">Experience and projects</p> <p class="text-sm text-surface-600 dark:text-surface-400 mt-1">Experience and projects</p>
</a> </a>
<a href="/about/" class="p-4 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors text-center"> <a href="/about/" class="p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors text-center">
<div class="text-2xl mb-2"> <div class="text-2xl mb-2">
<svg class="w-8 h-8 mx-auto text-accent-600 dark:text-accent-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"> <svg class="w-8 h-8 mx-auto text-accent-600 dark:text-accent-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/> <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>

View File

@@ -24,7 +24,7 @@ permalink: "blog/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumber
{% if paginatedPosts.length > 0 %} {% if paginatedPosts.length > 0 %}
<filter-container oninit leave-url-alone> <filter-container oninit leave-url-alone>
<div class="flex flex-wrap gap-3 mb-6"> <div class="flex flex-wrap gap-3 mb-6">
<select data-filter-key="type" class="px-3 py-1.5 text-sm bg-white dark:bg-surface-800 border border-surface-200 dark:border-surface-700 rounded-lg"> <select data-filter-key="type" class="px-3 py-1.5 text-sm bg-surface-50 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 rounded-lg">
<option value="">All Types</option> <option value="">All Types</option>
<option value="article">Articles</option> <option value="article">Articles</option>
<option value="note">Notes</option> <option value="note">Notes</option>

View File

@@ -65,7 +65,7 @@ permalink: /blogroll/
<template x-for="blog in blogs" :key="blog.id"> <template x-for="blog in blogs" :key="blog.id">
<a <a
:href="blog.siteUrl || blog.feedUrl" :href="blog.siteUrl || blog.feedUrl"
class="block bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-4 hover:border-accent-400 dark:hover:border-accent-600 transition-colors group" class="block bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-4 hover:border-accent-400 dark:hover:border-accent-600 transition-colors group"
target="_blank" target="_blank"
rel="noopener" rel="noopener"
> >
@@ -109,7 +109,7 @@ permalink: /blogroll/
{# Category Items Tab (one for each category) #} {# Category Items Tab (one for each category) #}
<div x-show="activeTab.startsWith('category:') && !loading" class="space-y-4"> <div x-show="activeTab.startsWith('category:') && !loading" class="space-y-4">
<template x-for="item in categoryItems" :key="item.id"> <template x-for="item in categoryItems" :key="item.id">
<article class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-4 sm:p-6 hover:border-accent-400 dark:hover:border-accent-600 transition-colors"> <article class="bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-4 sm:p-6 hover:border-accent-400 dark:hover:border-accent-600 transition-colors">
<div class="flex items-start gap-4"> <div class="flex items-start gap-4">
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
<div class="flex items-center gap-2 mb-1"> <div class="flex items-center gap-2 mb-1">

View File

@@ -4,28 +4,28 @@
*,*::before,*::after{box-sizing:border-box} *,*::before,*::after{box-sizing:border-box}
body{margin:0;font-family:"Inter",system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;line-height:1.5;-webkit-font-smoothing:antialiased} body{margin:0;font-family:"Inter",system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;line-height:1.5;-webkit-font-smoothing:antialiased}
/* Dark mode base */ /* Dark mode base — warm stone palette */
body{background-color:#fff;color:#18181b} body{background-color:#faf8f5;color:#1c1b19}
.dark body{background-color:#09090b;color:#f4f4f5} .dark body{background-color:#0f0e0d;color:#faf8f5}
/* Container */ /* Container */
.container{max-width:64rem;margin-left:auto;margin-right:auto;padding-left:1rem;padding-right:1rem} .container{max-width:64rem;margin-left:auto;margin-right:auto;padding-left:1rem;padding-right:1rem}
/* Header — sticky, visible immediately */ /* Header — sticky, visible immediately */
.site-header{background-color:#fff;border-bottom:1px solid #e4e4e7;padding-top:1rem;padding-bottom:1rem;position:sticky;top:0;z-index:50} .site-header{background-color:#faf8f5;border-bottom:1px solid #e8e5df;padding-top:1rem;padding-bottom:1rem;position:sticky;top:0;z-index:50}
.dark .site-header{background-color:#18181b;border-bottom-color:#3f3f46} .dark .site-header{background-color:#1c1b19;border-bottom-color:#3f3b35}
.header-container{display:flex;align-items:center;justify-content:space-between} .header-container{display:flex;align-items:center;justify-content:space-between}
.site-title{font-size:1.25rem;font-weight:700;color:#18181b;text-decoration:none} .site-title{font-size:1.25rem;font-weight:700;color:#1c1b19;text-decoration:none}
.dark .site-title{color:#fff} .dark .site-title{color:#faf8f5}
/* Header actions — hidden on mobile */ /* Header actions — hidden on mobile */
.header-actions{display:none} .header-actions{display:none}
@media(min-width:768px){.header-actions{display:flex;align-items:center;gap:1rem}} @media(min-width:768px){.header-actions{display:flex;align-items:center;gap:1rem}}
/* Mobile menu toggle */ /* Mobile menu toggle */
.menu-toggle{display:block;padding:0.5rem;border-radius:0.5rem;background:none;border:none;color:#52525b;cursor:pointer} .menu-toggle{display:block;padding:0.5rem;border-radius:0.5rem;background:none;border:none;color:#5c5750;cursor:pointer}
@media(min-width:768px){.menu-toggle{display:none}} @media(min-width:768px){.menu-toggle{display:none}}
.dark .menu-toggle{color:#a1a1aa} .dark .menu-toggle{color:#a09a90}
/* Hidden utility */ /* Hidden utility */
.hidden{display:none!important} .hidden{display:none!important}
@@ -48,10 +48,10 @@ main.container{padding-top:1.5rem;padding-bottom:1.5rem}
/* Basic typography — prevent FOUT */ /* Basic typography — prevent FOUT */
h1,h2,h3,h4{margin:0;line-height:1.25} h1,h2,h3,h4{margin:0;line-height:1.25}
a{color:#2563eb} a{color:#b45309}
.dark a{color:#60a5fa} .dark a{color:#fbbf24}
/* Prevent flash of unstyled content for nav */ /* Prevent flash of unstyled content for nav */
.site-nav{display:flex;align-items:center;gap:1rem} .site-nav{display:flex;align-items:center;gap:1rem}
.site-nav>a,.site-nav .nav-dropdown-trigger{color:#52525b;text-decoration:none;padding-top:0.5rem;padding-bottom:0.5rem} .site-nav>a,.site-nav .nav-dropdown-trigger{color:#5c5750;text-decoration:none;padding-top:0.5rem;padding-bottom:0.5rem}
.dark .site-nav>a,.dark .site-nav .nav-dropdown-trigger{color:#a1a1aa} .dark .site-nav>a,.dark .site-nav .nav-dropdown-trigger{color:#a09a90}

View File

@@ -37,12 +37,12 @@ pre[class*="language-"] {
} }
pre[class*="language-"] { pre[class*="language-"] {
background: #f6f8fa; background: #f4f2ee;
border: 1px solid #e1e4e8; border: 1px solid #e1e4e8;
} }
:not(pre) > code[class*="language-"] { :not(pre) > code[class*="language-"] {
background: #f6f8fa; background: #f4f2ee;
} }
.token.comment, .token.comment,

View File

@@ -103,10 +103,10 @@
} }
} }
/* Dark mode body background */ /* Body background — warm stone canvas */
@layer base { @layer base {
body { body {
@apply bg-white dark:bg-surface-950 text-surface-900 dark:text-surface-100; @apply bg-surface-50 dark:bg-surface-950 text-surface-900 dark:text-surface-100;
} }
} }
@@ -114,7 +114,7 @@
@layer components { @layer components {
/* Site header */ /* Site header */
.site-header { .site-header {
@apply bg-white dark:bg-surface-900 border-b border-surface-200 dark:border-surface-700 py-4 sticky top-0 z-50; @apply bg-surface-50 dark:bg-surface-900 border-b border-surface-200 dark:border-surface-700 py-4 sticky top-0 z-50;
} }
.header-container { .header-container {
@@ -149,7 +149,7 @@
} }
.nav-dropdown-menu { .nav-dropdown-menu {
@apply absolute top-full left-0 mt-1 py-2 bg-white dark:bg-surface-800 border border-surface-200 dark:border-surface-700 rounded-lg shadow-lg min-w-[160px] z-50 overflow-y-auto; @apply absolute top-full left-0 mt-1 py-2 bg-surface-50 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 rounded-lg shadow-lg min-w-[160px] z-50 overflow-y-auto;
max-height: calc(100vh - 5rem); max-height: calc(100vh - 5rem);
max-height: calc(100dvh - 5rem); max-height: calc(100dvh - 5rem);
} }
@@ -169,7 +169,7 @@
/* Mobile navigation dropdown */ /* Mobile navigation dropdown */
.mobile-nav { .mobile-nav {
@apply md:hidden border-t border-surface-200 dark:border-surface-700 bg-white dark:bg-surface-900 overflow-y-auto; @apply md:hidden border-t border-surface-200 dark:border-surface-700 bg-surface-50 dark:bg-surface-900 overflow-y-auto;
max-height: calc(100vh - 4rem); max-height: calc(100vh - 4rem);
max-height: calc(100dvh - 4rem); max-height: calc(100dvh - 4rem);
} }
@@ -351,7 +351,7 @@
/* Widget cards */ /* Widget cards */
.widget { .widget {
@apply p-4 mb-4 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden; @apply p-4 mb-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden;
} }
.widget-title { .widget-title {
@@ -388,7 +388,7 @@
/* Post cards */ /* Post cards */
.post-card { .post-card {
@apply p-5 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden; @apply p-5 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden;
} }
.post-header { .post-header {
@@ -500,7 +500,7 @@
} }
.fab-menu-item { .fab-menu-item {
@apply flex items-center gap-3 px-4 py-3 rounded-xl bg-white dark:bg-surface-800 shadow-md hover:shadow-lg border border-surface-200 dark:border-surface-700 text-surface-700 dark:text-surface-200 hover:text-accent-600 dark:hover:text-accent-400 no-underline transition-all duration-150 text-sm font-medium; @apply flex items-center gap-3 px-4 py-3 rounded-xl bg-surface-50 dark:bg-surface-800 shadow-md hover:shadow-lg border border-surface-200 dark:border-surface-700 text-surface-700 dark:text-surface-200 hover:text-accent-600 dark:hover:text-accent-400 no-underline transition-all duration-150 text-sm font-medium;
} }
.fab-menu-divider { .fab-menu-divider {
@@ -625,11 +625,11 @@
/* Pagefind UI theme overrides — outside @layer for higher specificity over Pagefind's :root defaults */ /* Pagefind UI theme overrides — outside @layer for higher specificity over Pagefind's :root defaults */
#search .pagefind-ui { #search .pagefind-ui {
--pagefind-ui-scale: 1; --pagefind-ui-scale: 1;
--pagefind-ui-primary: #0d9488; --pagefind-ui-primary: #b45309;
--pagefind-ui-text: #18181b; --pagefind-ui-text: #1c1b19;
--pagefind-ui-background: #ffffff; --pagefind-ui-background: #faf8f5;
--pagefind-ui-border: #e4e4e7; --pagefind-ui-border: #e8e5df;
--pagefind-ui-tag: #f4f4f5; --pagefind-ui-tag: #f4f2ee;
--pagefind-ui-border-width: 1px; --pagefind-ui-border-width: 1px;
--pagefind-ui-border-radius: 8px; --pagefind-ui-border-radius: 8px;
--pagefind-ui-image-border-radius: 8px; --pagefind-ui-image-border-radius: 8px;
@@ -637,60 +637,60 @@
} }
.dark #search .pagefind-ui { .dark #search .pagefind-ui {
--pagefind-ui-primary: #2dd4bf; --pagefind-ui-primary: #fbbf24;
--pagefind-ui-text: #f4f4f5; --pagefind-ui-text: #faf8f5;
--pagefind-ui-background: #09090b; --pagefind-ui-background: #0f0e0d;
--pagefind-ui-border: #3f3f46; --pagefind-ui-border: #3f3b35;
--pagefind-ui-tag: #27272a; --pagefind-ui-tag: #2a2722;
} }
/* Search input */ /* Search input */
#search .pagefind-ui__search-input { #search .pagefind-ui__search-input {
background-color: #ffffff; background-color: #faf8f5;
color: #18181b; color: #1c1b19;
border-color: #e4e4e7; border-color: #e8e5df;
font-weight: 400; font-weight: 400;
} }
.dark #search .pagefind-ui__search-input { .dark #search .pagefind-ui__search-input {
background-color: #18181b; background-color: #1c1b19;
color: #f4f4f5; color: #faf8f5;
border-color: #3f3f46; border-color: #3f3b35;
} }
#search .pagefind-ui__search-input:focus { #search .pagefind-ui__search-input:focus {
outline: 2px solid #3b82f6; outline: 2px solid #d97706;
outline-offset: 2px; outline-offset: 2px;
border-color: #3b82f6; border-color: #d97706;
} }
.dark #search .pagefind-ui__search-input:focus { .dark #search .pagefind-ui__search-input:focus {
outline-color: #60a5fa; outline-color: #fbbf24;
border-color: #60a5fa; border-color: #fbbf24;
} }
/* Search clear button */ /* Search clear button */
#search .pagefind-ui__search-clear { #search .pagefind-ui__search-clear {
color: #52525b; color: #5c5750;
background-color: #ffffff; background-color: #faf8f5;
} }
.dark #search .pagefind-ui__search-clear { .dark #search .pagefind-ui__search-clear {
color: #a1a1aa; color: #a09a90;
background-color: #18181b; background-color: #1c1b19;
} }
#search .pagefind-ui__search-clear:hover { #search .pagefind-ui__search-clear:hover {
color: #18181b; color: #1c1b19;
} }
.dark #search .pagefind-ui__search-clear:hover { .dark #search .pagefind-ui__search-clear:hover {
color: #f4f4f5; color: #faf8f5;
} }
/* Result links */ /* Result links */
#search .pagefind-ui__result-link { #search .pagefind-ui__result-link {
color: #2563eb; color: #b45309;
} }
#search .pagefind-ui__result-link:hover { #search .pagefind-ui__result-link:hover {
@@ -698,64 +698,64 @@
} }
.dark #search .pagefind-ui__result-link { .dark #search .pagefind-ui__result-link {
color: #60a5fa; color: #fbbf24;
} }
/* Result excerpts */ /* Result excerpts */
#search .pagefind-ui__result-excerpt { #search .pagefind-ui__result-excerpt {
color: #52525b; color: #5c5750;
} }
.dark #search .pagefind-ui__result-excerpt { .dark #search .pagefind-ui__result-excerpt {
color: #a1a1aa; color: #a09a90;
} }
/* Highlighted search terms in results */ /* Highlighted search terms in results */
#search .pagefind-ui__result-excerpt mark, #search .pagefind-ui__result-excerpt mark,
#search mark { #search mark {
background-color: #dbeafe; background-color: #fef3c7;
color: #1e40af; color: #92400e;
padding: 0.1em 0.2em; padding: 0.1em 0.2em;
border-radius: 2px; border-radius: 2px;
} }
.dark #search .pagefind-ui__result-excerpt mark, .dark #search .pagefind-ui__result-excerpt mark,
.dark #search mark { .dark #search mark {
background-color: #1e3a8a; background-color: #78350f;
color: #bfdbfe; color: #fde68a;
} }
/* Message (result count) */ /* Message (result count) */
#search .pagefind-ui__message { #search .pagefind-ui__message {
color: #52525b; color: #5c5750;
} }
.dark #search .pagefind-ui__message { .dark #search .pagefind-ui__message {
color: #a1a1aa; color: #a09a90;
} }
/* "Load more" button */ /* "Load more" button */
#search .pagefind-ui__button { #search .pagefind-ui__button {
color: #2563eb; color: #b45309;
background-color: #ffffff; background-color: #faf8f5;
border-color: #e4e4e7; border-color: #e8e5df;
cursor: pointer; cursor: pointer;
} }
#search .pagefind-ui__button:hover { #search .pagefind-ui__button:hover {
background-color: #eff6ff; background-color: #fffbeb;
border-color: #2563eb; border-color: #b45309;
} }
.dark #search .pagefind-ui__button { .dark #search .pagefind-ui__button {
color: #60a5fa; color: #fbbf24;
background-color: #09090b; background-color: #0f0e0d;
border-color: #3f3f46; border-color: #3f3b35;
} }
.dark #search .pagefind-ui__button:hover { .dark #search .pagefind-ui__button:hover {
background-color: #18181b; background-color: #1c1b19;
border-color: #60a5fa; border-color: #fbbf24;
} }
/* Filter panel labels */ /* Filter panel labels */

View File

@@ -21,7 +21,7 @@ permalink: "digest/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumb
{% if paginatedDigests.length > 0 %} {% if paginatedDigests.length > 0 %}
<ul class="space-y-4"> <ul class="space-y-4">
{% for d in paginatedDigests %} {% for d in paginatedDigests %}
<li class="p-4 bg-white dark:bg-surface-800 border border-surface-200 dark:border-surface-700 rounded-lg hover:border-accent-300 dark:hover:border-accent-600 transition-colors"> <li class="p-4 bg-surface-50 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 rounded-lg hover:border-accent-300 dark:hover:border-accent-600 transition-colors">
<a href="/digest/{{ d.slug }}/" class="block"> <a href="/digest/{{ d.slug }}/" class="block">
<h2 class="font-semibold text-surface-900 dark:text-surface-100 hover:text-accent-600 dark:hover:text-accent-400"> <h2 class="font-semibold text-surface-900 dark:text-surface-100 hover:text-accent-600 dark:hover:text-accent-400">
{{ d.label }} {{ d.label }}

View File

@@ -144,7 +144,7 @@ withSidebar: true
{# Trends Tab #} {# Trends Tab #}
<div x-show="activeTab === 'trends'" x-cloak> <div x-show="activeTab === 'trends'" x-cloak>
{% if funkwhaleActivity.stats.trends and funkwhaleActivity.stats.trends.length %} {% if funkwhaleActivity.stats.trends and funkwhaleActivity.stats.trends.length %}
<div class="bg-white dark:bg-surface-800 rounded-xl p-6 border border-surface-200 dark:border-surface-700"> <div class="bg-surface-50 dark:bg-surface-800 rounded-xl p-6 border border-surface-200 dark:border-surface-700">
<h3 class="text-lg font-semibold text-surface-900 dark:text-surface-100 mb-4">Daily Listening (Last 30 Days)</h3> <h3 class="text-lg font-semibold text-surface-900 dark:text-surface-100 mb-4">Daily Listening (Last 30 Days)</h3>
<div class="flex items-end gap-1 h-32"> <div class="flex items-end gap-1 h-32">
{% set maxCount = 1 %} {% set maxCount = 1 %}
@@ -185,7 +185,7 @@ withSidebar: true
{% if funkwhaleActivity.listenings.length %} {% if funkwhaleActivity.listenings.length %}
<div class="space-y-3"> <div class="space-y-3">
{% for listening in funkwhaleActivity.listenings | head(15) %} {% for listening in funkwhaleActivity.listenings | head(15) %}
<div class="flex items-center gap-4 p-3 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-purple-400 dark:hover:border-purple-600 transition-colors"> <div class="flex items-center gap-4 p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-purple-400 dark:hover:border-purple-600 transition-colors">
{% if listening.coverUrl %} {% if listening.coverUrl %}
<img src="{{ listening.coverUrl }}" alt="" class="w-12 h-12 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore> <img src="{{ listening.coverUrl }}" alt="" class="w-12 h-12 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
{% else %} {% else %}
@@ -235,7 +235,7 @@ withSidebar: true
<div class="grid gap-3 sm:gap-4 md:grid-cols-2"> <div class="grid gap-3 sm:gap-4 md:grid-cols-2">
{% for favorite in funkwhaleActivity.favorites | head(10) %} {% for favorite in funkwhaleActivity.favorites | head(10) %}
<div class="flex items-center gap-3 p-3 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700"> <div class="flex items-center gap-3 p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700">
{% if favorite.coverUrl %} {% if favorite.coverUrl %}
<img src="{{ favorite.coverUrl }}" alt="" class="w-14 h-14 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore> <img src="{{ favorite.coverUrl }}" alt="" class="w-14 h-14 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
{% else %} {% else %}

View File

@@ -30,7 +30,7 @@ withSidebar: true
<article class="p-5 bg-gradient-to-br from-surface-50 to-white dark:from-surface-800 dark:to-surface-800 rounded-xl border-2 border-surface-200 dark:border-surface-700 shadow-sm"> <article class="p-5 bg-gradient-to-br from-surface-50 to-white dark:from-surface-800 dark:to-surface-800 rounded-xl border-2 border-surface-200 dark:border-surface-700 shadow-sm">
<div class="flex items-start justify-between mb-3"> <div class="flex items-start justify-between mb-3">
<h3 class="font-bold text-lg text-surface-900 dark:text-surface-100"> <h3 class="font-bold text-lg text-surface-900 dark:text-surface-100">
<a href="{{ repo.url }}" class="hover:text-surface-600 dark:hover:text-surface-400" target="_blank" rel="noopener"> <a href="{{ repo.url }}" class="hover:text-emerald-600 dark:hover:text-emerald-400" target="_blank" rel="noopener">
{{ repo.fullName }} {{ repo.fullName }}
</a> </a>
</h3> </h3>
@@ -75,7 +75,7 @@ withSidebar: true
{% for commit in repo.commits %} {% for commit in repo.commits %}
<li class="flex items-start gap-2 text-sm min-w-0"> <li class="flex items-start gap-2 text-sm min-w-0">
<code class="flex-shrink-0 text-xs font-mono bg-surface-100 dark:bg-surface-700 px-1.5 py-0.5 rounded"> <code class="flex-shrink-0 text-xs font-mono bg-surface-100 dark:bg-surface-700 px-1.5 py-0.5 rounded">
<a href="{{ commit.url }}" class="text-surface-600 dark:text-surface-400 hover:underline" target="_blank" rel="noopener">{{ commit.sha }}</a> <a href="{{ commit.url }}" class="text-emerald-600 dark:text-emerald-400 hover:underline font-mono text-xs" target="_blank" rel="noopener">{{ commit.sha }}</a>
</code> </code>
<span class="text-surface-700 dark:text-surface-300 truncate min-w-0 flex-1">{{ commit.message }}</span> <span class="text-surface-700 dark:text-surface-300 truncate min-w-0 flex-1">{{ commit.message }}</span>
</li> </li>
@@ -101,12 +101,12 @@ withSidebar: true
{% if githubActivity.commits.length %} {% if githubActivity.commits.length %}
<div class="space-y-3"> <div class="space-y-3">
{% for commit in githubActivity.commits %} {% for commit in githubActivity.commits %}
<div class="flex items-start gap-3 p-3 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700"> <div class="flex items-start gap-3 p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700">
<code class="text-xs font-mono bg-surface-100 dark:bg-surface-700 px-2 py-1 rounded"> <code class="text-xs font-mono bg-surface-100 dark:bg-surface-700 px-2 py-1 rounded">
{{ commit.sha }} {{ commit.sha }}
</code> </code>
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
<a href="{{ commit.url }}" class="text-surface-900 dark:text-surface-100 hover:text-surface-600 dark:hover:text-surface-400" target="_blank" rel="noopener"> <a href="{{ commit.url }}" class="text-surface-900 dark:text-surface-100 hover:text-emerald-600 dark:hover:text-emerald-400" target="_blank" rel="noopener">
{{ commit.message }} {{ commit.message }}
</a> </a>
<p class="text-xs text-surface-500 mt-1"> <p class="text-xs text-surface-500 mt-1">
@@ -134,14 +134,14 @@ withSidebar: true
<div class="space-y-3"> <div class="space-y-3">
{% for item in githubActivity.contributions %} {% for item in githubActivity.contributions %}
<div class="flex items-start gap-3 p-3 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700"> <div class="flex items-start gap-3 p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700">
{% if item.type == "pr" %} {% if item.type == "pr" %}
<span class="flex-shrink-0 px-2 py-1 text-xs font-medium bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200 rounded">PR</span> <span class="flex-shrink-0 px-2 py-1 text-xs font-medium bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200 rounded">PR</span>
{% else %} {% else %}
<span class="flex-shrink-0 px-2 py-1 text-xs font-medium bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200 rounded">Issue</span> <span class="flex-shrink-0 px-2 py-1 text-xs font-medium bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200 rounded">Issue</span>
{% endif %} {% endif %}
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
<a href="{{ item.url }}" class="text-surface-900 dark:text-surface-100 hover:text-surface-600 dark:hover:text-surface-400" target="_blank" rel="noopener"> <a href="{{ item.url }}" class="text-surface-900 dark:text-surface-100 hover:text-emerald-600 dark:hover:text-emerald-400" target="_blank" rel="noopener">
{{ item.title }} {{ item.title }}
</a> </a>
<p class="text-xs text-surface-500 mt-1"> <p class="text-xs text-surface-500 mt-1">
@@ -168,9 +168,9 @@ withSidebar: true
{% if githubRepos.length %} {% if githubRepos.length %}
<div class="grid gap-3 sm:gap-4 md:grid-cols-2"> <div class="grid gap-3 sm:gap-4 md:grid-cols-2">
{% for repo in githubRepos | head(6) %} {% for repo in githubRepos | head(6) %}
<article class="p-4 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700"> <article class="p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700">
<h3 class="font-semibold text-surface-900 dark:text-surface-100 mb-1"> <h3 class="font-semibold text-surface-900 dark:text-surface-100 mb-1">
<a href="{{ repo.html_url }}" class="hover:text-surface-600 dark:hover:text-surface-400" target="_blank" rel="noopener"> <a href="{{ repo.html_url }}" class="hover:text-emerald-600 dark:hover:text-emerald-400" target="_blank" rel="noopener">
{{ repo.name }} {{ repo.name }}
</a> </a>
</h3> </h3>
@@ -223,9 +223,9 @@ withSidebar: true
{% if githubActivity.stars.length %} {% if githubActivity.stars.length %}
<div class="grid gap-3 sm:gap-4 md:grid-cols-2"> <div class="grid gap-3 sm:gap-4 md:grid-cols-2">
{% for repo in githubActivity.stars | head(10) %} {% for repo in githubActivity.stars | head(10) %}
<article class="p-4 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-surface-400 dark:hover:border-surface-600 transition-colors"> <article class="p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-surface-400 dark:hover:border-surface-600 transition-colors">
<h3 class="font-semibold text-surface-900 dark:text-surface-100 mb-1"> <h3 class="font-semibold text-surface-900 dark:text-surface-100 mb-1">
<a href="{{ repo.url }}" class="hover:text-surface-600 dark:hover:text-surface-400" target="_blank" rel="noopener"> <a href="{{ repo.url }}" class="hover:text-emerald-600 dark:hover:text-emerald-400" target="_blank" rel="noopener">
{{ repo.name }} {{ repo.name }}
</a> </a>
</h3> </h3>

View File

@@ -179,7 +179,7 @@ withSidebar: true
<div class="grid gap-4 sm:gap-6 md:grid-cols-2"> <div class="grid gap-4 sm:gap-6 md:grid-cols-2">
{# Funkwhale Stats #} {# Funkwhale Stats #}
{% if funkwhaleActivity.stats %} {% if funkwhaleActivity.stats %}
<div x-show="activeSource === 'all' || activeSource === 'funkwhale'" class="bg-white dark:bg-surface-800 rounded-xl p-6 border border-purple-200 dark:border-purple-800"> <div x-show="activeSource === 'all' || activeSource === 'funkwhale'" class="bg-surface-50 dark:bg-surface-800 rounded-xl p-6 border border-purple-200 dark:border-purple-800">
<h3 class="text-lg font-semibold text-purple-700 dark:text-purple-400 mb-4 flex items-center gap-2"> <h3 class="text-lg font-semibold text-purple-700 dark:text-purple-400 mb-4 flex items-center gap-2">
<span class="w-3 h-3 rounded-full bg-purple-500"></span> <span class="w-3 h-3 rounded-full bg-purple-500"></span>
Funkwhale Funkwhale
@@ -217,7 +217,7 @@ withSidebar: true
{# Last.fm Stats #} {# Last.fm Stats #}
{% if lastfmActivity.stats %} {% if lastfmActivity.stats %}
<div x-show="activeSource === 'all' || activeSource === 'lastfm'" class="bg-white dark:bg-surface-800 rounded-xl p-6 border border-red-200 dark:border-red-800"> <div x-show="activeSource === 'all' || activeSource === 'lastfm'" class="bg-surface-50 dark:bg-surface-800 rounded-xl p-6 border border-red-200 dark:border-red-800">
<h3 class="text-lg font-semibold text-red-700 dark:text-red-400 mb-4 flex items-center gap-2"> <h3 class="text-lg font-semibold text-red-700 dark:text-red-400 mb-4 flex items-center gap-2">
<span class="w-3 h-3 rounded-full bg-red-500"></span> <span class="w-3 h-3 rounded-full bg-red-500"></span>
Last.fm Last.fm
@@ -270,7 +270,7 @@ withSidebar: true
{% if funkwhaleActivity.listenings.length %} {% if funkwhaleActivity.listenings.length %}
<div x-show="activeSource === 'all' || activeSource === 'funkwhale'"> <div x-show="activeSource === 'all' || activeSource === 'funkwhale'">
{% for listening in funkwhaleActivity.listenings | head(10) %} {% for listening in funkwhaleActivity.listenings | head(10) %}
<div class="flex items-center gap-4 p-3 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-purple-400 dark:hover:border-purple-600 transition-colors mb-2"> <div class="flex items-center gap-4 p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-purple-400 dark:hover:border-purple-600 transition-colors mb-2">
{% if listening.coverUrl %} {% if listening.coverUrl %}
<img src="{{ listening.coverUrl }}" alt="" class="w-12 h-12 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore> <img src="{{ listening.coverUrl }}" alt="" class="w-12 h-12 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
{% else %} {% else %}
@@ -324,7 +324,7 @@ withSidebar: true
{% if lastfmActivity.scrobbles.length %} {% if lastfmActivity.scrobbles.length %}
<div x-show="activeSource === 'all' || activeSource === 'lastfm'"> <div x-show="activeSource === 'all' || activeSource === 'lastfm'">
{% for scrobble in lastfmActivity.scrobbles | head(10) %} {% for scrobble in lastfmActivity.scrobbles | head(10) %}
<div class="flex items-center gap-4 p-3 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-red-400 dark:hover:border-red-600 transition-colors mb-2"> <div class="flex items-center gap-4 p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-red-400 dark:hover:border-red-600 transition-colors mb-2">
{% if scrobble.coverUrl %} {% if scrobble.coverUrl %}
<img src="{{ scrobble.coverUrl }}" alt="" class="w-12 h-12 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore> <img src="{{ scrobble.coverUrl }}" alt="" class="w-12 h-12 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
{% else %} {% else %}
@@ -396,7 +396,7 @@ withSidebar: true
<div class="grid gap-3 sm:gap-4 md:grid-cols-2"> <div class="grid gap-3 sm:gap-4 md:grid-cols-2">
{% for track in lastfmActivity.loved | head(10) %} {% for track in lastfmActivity.loved | head(10) %}
<div class="flex items-center gap-3 p-3 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700"> <div class="flex items-center gap-3 p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700">
{% if track.coverUrl %} {% if track.coverUrl %}
<img src="{{ track.coverUrl }}" alt="" class="w-14 h-14 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore> <img src="{{ track.coverUrl }}" alt="" class="w-14 h-14 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
{% else %} {% else %}
@@ -457,7 +457,7 @@ withSidebar: true
<div class="grid gap-3 sm:gap-4 md:grid-cols-2"> <div class="grid gap-3 sm:gap-4 md:grid-cols-2">
{% for favorite in funkwhaleActivity.favorites | head(10) %} {% for favorite in funkwhaleActivity.favorites | head(10) %}
<div class="flex items-center gap-3 p-3 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700"> <div class="flex items-center gap-3 p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700">
{% if favorite.coverUrl %} {% if favorite.coverUrl %}
<img src="{{ favorite.coverUrl }}" alt="" class="w-14 h-14 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore> <img src="{{ favorite.coverUrl }}" alt="" class="w-14 h-14 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
{% else %} {% else %}

View File

@@ -125,7 +125,7 @@ withSidebar: true
{# List View #} {# List View #}
<div x-show="viewMode === 'list'" class="space-y-3"> <div x-show="viewMode === 'list'" class="space-y-3">
<template x-for="item in filteredItems" :key="item.id"> <template x-for="item in filteredItems" :key="item.id">
<article class="flex items-start gap-4 p-4 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors"> <article class="flex items-start gap-4 p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-accent-400 dark:hover:border-accent-600 transition-colors">
<img <img
x-show="item.imageUrl" x-show="item.imageUrl"
:src="item.imageUrl" :src="item.imageUrl"
@@ -190,7 +190,7 @@ withSidebar: true
{# Card View #} {# Card View #}
<div x-show="viewMode === 'card'" class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3"> <div x-show="viewMode === 'card'" class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
<template x-for="item in filteredItems" :key="item.id"> <template x-for="item in filteredItems" :key="item.id">
<article class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 overflow-hidden hover:shadow-lg transition-shadow"> <article class="bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 overflow-hidden hover:shadow-lg transition-shadow">
<div x-show="item.imageUrl" class="aspect-video bg-surface-100 dark:bg-surface-700"> <div x-show="item.imageUrl" class="aspect-video bg-surface-100 dark:bg-surface-700">
<img <img
:src="item.imageUrl" :src="item.imageUrl"
@@ -243,7 +243,7 @@ withSidebar: true
{# Full/Expanded View #} {# Full/Expanded View #}
<div x-show="viewMode === 'full'" class="space-y-6"> <div x-show="viewMode === 'full'" class="space-y-6">
<template x-for="item in filteredItems" :key="item.id"> <template x-for="item in filteredItems" :key="item.id">
<article class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 overflow-hidden"> <article class="bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 overflow-hidden">
<div x-show="item.imageUrl" class="aspect-[3/1] bg-surface-100 dark:bg-surface-700"> <div x-show="item.imageUrl" class="aspect-[3/1] bg-surface-100 dark:bg-surface-700">
<img <img
:src="item.imageUrl" :src="item.imageUrl"

View File

@@ -66,7 +66,7 @@ permalink: /podroll/
{# Episodes List #} {# Episodes List #}
<div x-show="episodes.length > 0" class="space-y-4"> <div x-show="episodes.length > 0" class="space-y-4">
<template x-for="episode in filteredEpisodes" :key="episode.id"> <template x-for="episode in filteredEpisodes" :key="episode.id">
<article class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-4 sm:p-6 hover:border-accent-400 dark:hover:border-accent-600 transition-colors"> <article class="bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-4 sm:p-6 hover:border-accent-400 dark:hover:border-accent-600 transition-colors">
{# Episode Header #} {# Episode Header #}
<div class="flex items-start gap-4 mb-4"> <div class="flex items-start gap-4 mb-4">
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">

View File

@@ -41,7 +41,7 @@ permalink: /readlater/
<select <select
x-model="selectedSource" x-model="selectedSource"
@change="fetchData()" @change="fetchData()"
class="appearance-none bg-white dark:bg-surface-800 border border-surface-300 dark:border-surface-600 rounded-lg pl-3 pr-8 py-2 text-sm focus:ring-2 focus:ring-accent-500 focus:border-accent-500" class="appearance-none bg-surface-50 dark:bg-surface-800 border border-surface-300 dark:border-surface-600 rounded-lg pl-3 pr-8 py-2 text-sm focus:ring-2 focus:ring-accent-500 focus:border-accent-500"
> >
<option value="">All sources</option> <option value="">All sources</option>
<template x-for="src in sources" :key="src"> <template x-for="src in sources" :key="src">
@@ -58,7 +58,7 @@ permalink: /readlater/
x-model.debounce.300ms="searchQuery" x-model.debounce.300ms="searchQuery"
@input="fetchData()" @input="fetchData()"
placeholder="Search..." placeholder="Search..."
class="w-full bg-white dark:bg-surface-800 border border-surface-300 dark:border-surface-600 rounded-lg pl-9 pr-3 py-2 text-sm focus:ring-2 focus:ring-accent-500 focus:border-accent-500" class="w-full bg-surface-50 dark:bg-surface-800 border border-surface-300 dark:border-surface-600 rounded-lg pl-9 pr-3 py-2 text-sm focus:ring-2 focus:ring-accent-500 focus:border-accent-500"
/> />
<svg class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-surface-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-surface-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
@@ -66,7 +66,7 @@ permalink: /readlater/
</div> </div>
<button <button
@click="toggleSort()" @click="toggleSort()"
class="inline-flex items-center gap-1 px-3 py-2 bg-white dark:bg-surface-800 border border-surface-300 dark:border-surface-600 rounded-lg text-sm hover:bg-surface-50 dark:hover:bg-surface-700 transition-colors" class="inline-flex items-center gap-1 px-3 py-2 bg-surface-50 dark:bg-surface-800 border border-surface-300 dark:border-surface-600 rounded-lg text-sm hover:bg-surface-50 dark:hover:bg-surface-700 transition-colors"
:title="sortDir === 'desc' ? 'Newest first' : 'Oldest first'" :title="sortDir === 'desc' ? 'Newest first' : 'Oldest first'"
> >
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -80,7 +80,7 @@ permalink: /readlater/
{# Items List #} {# Items List #}
<div x-show="!loading" class="space-y-4"> <div x-show="!loading" class="space-y-4">
<template x-for="item in items" :key="item.id"> <template x-for="item in items" :key="item.id">
<article class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-4 sm:p-5 hover:border-accent-400 dark:hover:border-accent-600 transition-colors"> <article class="bg-surface-50 dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-4 sm:p-5 hover:border-accent-400 dark:hover:border-accent-600 transition-colors">
<div class="flex items-start gap-4"> <div class="flex items-start gap-4">
<div class="flex-shrink-0 w-10 h-10 rounded-lg bg-gradient-to-br from-accent-400 to-accent-600 flex items-center justify-center"> <div class="flex-shrink-0 w-10 h-10 rounded-lg bg-gradient-to-br from-accent-400 to-accent-600 flex items-center justify-center">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">

View File

@@ -108,7 +108,7 @@ eleventyExcludeFromCollections: true
x-model="searchQuery" x-model="searchQuery"
@input="resetView()" @input="resetView()"
placeholder="Search by name, description, topic, or language..." placeholder="Search by name, description, topic, or language..."
class="w-full pl-10 pr-10 py-2 rounded-lg border border-surface-300 dark:border-surface-600 bg-white dark:bg-surface-800 text-surface-900 dark:text-surface-100 placeholder-surface-400 text-sm focus:outline-none focus:ring-2 focus:ring-accent-500 focus:border-transparent" class="w-full pl-10 pr-10 py-2 rounded-lg border border-surface-300 dark:border-surface-600 bg-surface-50 dark:bg-surface-800 text-surface-900 dark:text-surface-100 placeholder-surface-400 text-sm focus:outline-none focus:ring-2 focus:ring-accent-500 focus:border-transparent"
> >
<template x-if="searchQuery"> <template x-if="searchQuery">
<button @click="searchQuery = ''; resetView()" class="absolute right-3 top-1/2 -translate-y-1/2 text-surface-400 hover:text-surface-600"> <button @click="searchQuery = ''; resetView()" class="absolute right-3 top-1/2 -translate-y-1/2 text-surface-400 hover:text-surface-600">
@@ -123,7 +123,7 @@ eleventyExcludeFromCollections: true
<select <select
x-model="sortBy" x-model="sortBy"
@change="resetView()" @change="resetView()"
class="px-3 py-2 rounded-lg border border-surface-300 dark:border-surface-600 bg-white dark:bg-surface-800 text-surface-900 dark:text-surface-100 text-sm focus:outline-none focus:ring-2 focus:ring-accent-500" class="px-3 py-2 rounded-lg border border-surface-300 dark:border-surface-600 bg-surface-50 dark:bg-surface-800 text-surface-900 dark:text-surface-100 text-sm focus:outline-none focus:ring-2 focus:ring-accent-500"
> >
<option value="stars">Sort: Stars</option> <option value="stars">Sort: Stars</option>
<option value="starredAt">Sort: Recently Starred</option> <option value="starredAt">Sort: Recently Starred</option>
@@ -138,7 +138,7 @@ eleventyExcludeFromCollections: true
<select <select
x-model="languageFilter" x-model="languageFilter"
@change="resetView()" @change="resetView()"
class="px-2 py-1.5 rounded border border-surface-300 dark:border-surface-600 bg-white dark:bg-surface-800 text-surface-900 dark:text-surface-100 text-xs focus:outline-none focus:ring-2 focus:ring-accent-500" class="px-2 py-1.5 rounded border border-surface-300 dark:border-surface-600 bg-surface-50 dark:bg-surface-800 text-surface-900 dark:text-surface-100 text-xs focus:outline-none focus:ring-2 focus:ring-accent-500"
> >
<option value="">All Languages</option> <option value="">All Languages</option>
<template x-for="lang in availableLanguages" :key="lang"> <template x-for="lang in availableLanguages" :key="lang">
@@ -153,7 +153,7 @@ eleventyExcludeFromCollections: true
@click="starCountMin = opt.value; resetView()" @click="starCountMin = opt.value; resetView()"
:class="starCountMin === opt.value :class="starCountMin === opt.value
? 'bg-accent-600 text-white' ? 'bg-accent-600 text-white'
: 'bg-white dark:bg-surface-800 text-surface-600 dark:text-surface-400 hover:bg-surface-100 dark:hover:bg-surface-700'" : 'bg-surface-50 dark:bg-surface-800 text-surface-600 dark:text-surface-400 hover:bg-surface-100 dark:hover:bg-surface-700'"
class="px-2.5 py-1 text-xs font-medium transition-colors" class="px-2.5 py-1 text-xs font-medium transition-colors"
x-text="opt.label" x-text="opt.label"
></button> ></button>
@@ -184,7 +184,7 @@ eleventyExcludeFromCollections: true
{# ===== REPO GRID ===== #} {# ===== REPO GRID ===== #}
<div class="grid gap-3 sm:gap-4 md:grid-cols-2" id="starred-grid"> <div class="grid gap-3 sm:gap-4 md:grid-cols-2" id="starred-grid">
<template x-for="repo in visibleStars" :key="repo.fullName"> <template x-for="repo in visibleStars" :key="repo.fullName">
<article class="starred-card p-4 bg-white dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-surface-400 dark:hover:border-surface-500 transition-colors"> <article class="starred-card p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-surface-400 dark:hover:border-surface-500 transition-colors">
<div class="flex items-center gap-2 mb-1"> <div class="flex items-center gap-2 mb-1">
<template x-if="repo.ownerAvatar"> <template x-if="repo.ownerAvatar">
<img :src="repo.ownerAvatar" :alt="repo.ownerLogin" class="w-5 h-5 rounded-full" loading="lazy"> <img :src="repo.ownerAvatar" :alt="repo.ownerLogin" class="w-5 h-5 rounded-full" loading="lazy">

View File

@@ -13,6 +13,35 @@ export default {
theme: { theme: {
extend: { extend: {
colors: { colors: {
// Warm stone — surfaces, text, structure
surface: {
50: "#faf8f5",
100: "#f4f2ee",
200: "#e8e5df",
300: "#d5d0c8",
400: "#a09a90",
500: "#7a746a",
600: "#5c5750",
700: "#3f3b35",
800: "#2a2722",
900: "#1c1b19",
950: "#0f0e0d",
},
// Warm amber — default interactive, CTAs, focus rings
accent: {
50: "#fffbeb",
100: "#fef3c7",
200: "#fde68a",
300: "#fcd34d",
400: "#fbbf24",
500: "#f59e0b",
600: "#d97706",
700: "#b45309",
800: "#92400e",
900: "#78350f",
950: "#451a03",
},
// Legacy — kept for compatibility, not used in templates
primary: { primary: {
50: "#eff6ff", 50: "#eff6ff",
100: "#dbeafe", 100: "#dbeafe",
@@ -26,32 +55,6 @@ export default {
900: "#1e3a8a", 900: "#1e3a8a",
950: "#172554", 950: "#172554",
}, },
accent: {
50: "#f0fdfa",
100: "#ccfbf1",
200: "#99f6e4",
300: "#5eead4",
400: "#2dd4bf",
500: "#14b8a6",
600: "#0d9488",
700: "#0f766e",
800: "#115e59",
900: "#134e4a",
950: "#042f2e",
},
surface: {
50: "#fafafa",
100: "#f4f4f5",
200: "#e4e4e7",
300: "#d4d4d8",
400: "#a1a1aa",
500: "#71717a",
600: "#52525b",
700: "#3f3f46",
800: "#27272a",
900: "#18181b",
950: "#09090b",
},
}, },
fontFamily: { fontFamily: {
sans: [ sans: [

View File

@@ -87,7 +87,7 @@ withSidebar: true
<div class="flex-shrink-0"> <div class="flex-shrink-0">
{% if channelLiveStatus and channelLiveStatus.isLive %} {% if channelLiveStatus and channelLiveStatus.isLive %}
<span class="inline-flex items-center gap-2 px-3 py-1.5 bg-red-500 text-white text-sm font-semibold rounded-full animate-pulse"> <span class="inline-flex items-center gap-2 px-3 py-1.5 bg-red-500 text-white text-sm font-semibold rounded-full animate-pulse">
<span class="w-2 h-2 bg-white rounded-full"></span> <span class="w-2 h-2 bg-surface-50 rounded-full"></span>
LIVE LIVE
</span> </span>
{% elif channelLiveStatus and channelLiveStatus.isUpcoming %} {% elif channelLiveStatus and channelLiveStatus.isUpcoming %}
@@ -149,7 +149,7 @@ withSidebar: true
{% if channelLiveStatus.isLive %} {% if channelLiveStatus.isLive %}
<div class="absolute top-4 left-4"> <div class="absolute top-4 left-4">
<span class="inline-flex items-center gap-1.5 px-2 py-1 bg-red-500 text-white text-xs font-bold rounded"> <span class="inline-flex items-center gap-1.5 px-2 py-1 bg-red-500 text-white text-xs font-bold rounded">
<span class="w-1.5 h-1.5 bg-white rounded-full animate-pulse"></span> <span class="w-1.5 h-1.5 bg-surface-50 rounded-full animate-pulse"></span>
LIVE LIVE
</span> </span>
</div> </div>
@@ -173,7 +173,7 @@ withSidebar: true
{% if channelVideos and channelVideos.length %} {% if channelVideos and channelVideos.length %}
<div class="grid gap-4 sm:gap-6 sm:grid-cols-2 lg:grid-cols-3"> <div class="grid gap-4 sm:gap-6 sm:grid-cols-2 lg:grid-cols-3">
{% for video in channelVideos | head(9) %} {% for video in channelVideos | head(9) %}
<article class="group bg-white dark:bg-surface-800 rounded-xl overflow-hidden border border-surface-200 dark:border-surface-700 hover:border-red-400 dark:hover:border-red-600 transition-colors"> <article class="group bg-surface-50 dark:bg-surface-800 rounded-xl overflow-hidden border border-surface-200 dark:border-surface-700 hover:border-red-400 dark:hover:border-red-600 transition-colors">
<a href="{{ video.url }}" class="block" target="_blank" rel="noopener"> <a href="{{ video.url }}" class="block" target="_blank" rel="noopener">
<div class="relative aspect-video"> <div class="relative aspect-video">
{% if video.thumbnail %} {% if video.thumbnail %}
@@ -198,7 +198,7 @@ withSidebar: true
</span> </span>
{% elif video.isLive %} {% elif video.isLive %}
<span class="absolute bottom-2 right-2 px-1.5 py-0.5 bg-red-500 text-white text-xs font-bold rounded flex items-center gap-1"> <span class="absolute bottom-2 right-2 px-1.5 py-0.5 bg-red-500 text-white text-xs font-bold rounded flex items-center gap-1">
<span class="w-1.5 h-1.5 bg-white rounded-full animate-pulse"></span> <span class="w-1.5 h-1.5 bg-surface-50 rounded-full animate-pulse"></span>
LIVE LIVE
</span> </span>
{% endif %} {% endif %}