mirror of
https://github.com/svemagie/blog-eleventy-indiekit.git
synced 2026-04-02 16:44:56 +02:00
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:
93
.interface-design/system.md
Normal file
93
.interface-design/system.md
Normal 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
|
||||
@@ -72,7 +72,7 @@
|
||||
class="widget-collapsible mb-4"
|
||||
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
|
||||
class="widget-header w-full p-4"
|
||||
@click="open = !open; localStorage.setItem('{{ widgetKey }}', open)"
|
||||
@@ -167,7 +167,7 @@
|
||||
{# 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="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'">
|
||||
<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>
|
||||
@@ -181,7 +181,7 @@
|
||||
{# Table of Contents #}
|
||||
{% 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="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'">
|
||||
<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>
|
||||
@@ -195,7 +195,7 @@
|
||||
{# 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="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'">
|
||||
<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>
|
||||
@@ -209,7 +209,7 @@
|
||||
{# 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="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'">
|
||||
<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>
|
||||
@@ -223,7 +223,7 @@
|
||||
{# 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="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'">
|
||||
<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>
|
||||
@@ -237,7 +237,7 @@
|
||||
{# 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="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'">
|
||||
<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>
|
||||
@@ -251,7 +251,7 @@
|
||||
{# 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="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'">
|
||||
<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>
|
||||
@@ -265,7 +265,7 @@
|
||||
{# 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="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'">
|
||||
<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>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
x-transition:leave-end="opacity-0"
|
||||
@click="showModal = false"></div>
|
||||
{# 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-start="opacity-0 scale-95"
|
||||
x-transition:enter-end="opacity-100 scale-100"
|
||||
@@ -60,7 +60,7 @@
|
||||
@keydown.enter.prevent="confirm()"
|
||||
type="text"
|
||||
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">
|
||||
<p class="text-xs text-red-500 mt-1" x-text="error"></p>
|
||||
</template>
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
{# Stats Summary Cards #}
|
||||
{% if summary %}
|
||||
<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-xs text-surface-500 uppercase tracking-wide">Plays</span>
|
||||
</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-xs text-surface-500 uppercase tracking-wide">Tracks</span>
|
||||
</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-xs text-surface-500 uppercase tracking-wide">Artists</span>
|
||||
</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-xs text-surface-500 uppercase tracking-wide">Listened</span>
|
||||
</div>
|
||||
@@ -26,7 +26,7 @@
|
||||
<h3 class="text-lg font-semibold text-surface-900 dark:text-surface-100 mb-4">Top Artists</h3>
|
||||
<div class="space-y-2">
|
||||
{% 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="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>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
class="widget-collapsible mb-4"
|
||||
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
|
||||
class="widget-header w-full p-4"
|
||||
@click="open = !open; localStorage.setItem('{{ widgetKey }}', open)"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="space-y-3">
|
||||
{% for item in cv.education %}
|
||||
{% 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>
|
||||
<p class="text-sm text-surface-600 dark:text-surface-400">
|
||||
{{ item.institution }}{% if item.location %} · {{ item.location }}{% endif %}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
{% if showHighlights and item.highlights and item.highlights.length %}
|
||||
<div class="flex flex-wrap gap-1.5 mt-2">
|
||||
{% 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 }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
{% 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] %}
|
||||
<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">
|
||||
{{ category }}
|
||||
</h3>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<div class="flex flex-wrap gap-3">
|
||||
{% 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="text-xs text-surface-500 capitalize">{{ lang.level }}</span>
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
{% 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 #}
|
||||
<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"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
{% 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 #}
|
||||
<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"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
{% 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 #}
|
||||
<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"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
{% 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] %}
|
||||
<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">
|
||||
{{ category }}
|
||||
</h3>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
{% set borderClass = "border-l-[3px] border-l-surface-300 dark:border-l-surface-600" %}
|
||||
{% 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 %}
|
||||
{# ── Like card ── #}
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
class="widget-collapsible mb-4"
|
||||
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
|
||||
class="widget-header w-full p-4"
|
||||
@click="open = !open; localStorage.setItem('{{ widgetKey }}', open)"
|
||||
@@ -156,7 +156,7 @@
|
||||
{# Author Card (h-card) — always shown #}
|
||||
{% 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="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'">
|
||||
<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>
|
||||
@@ -170,7 +170,7 @@
|
||||
{# Social Activity — Bluesky/Mastodon feeds #}
|
||||
{% 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="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'">
|
||||
<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>
|
||||
@@ -184,7 +184,7 @@
|
||||
{# 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="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'">
|
||||
<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>
|
||||
@@ -198,7 +198,7 @@
|
||||
{# Funkwhale — Now Playing / Listening Stats #}
|
||||
{% 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="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'">
|
||||
<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>
|
||||
@@ -212,7 +212,7 @@
|
||||
{# 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="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'">
|
||||
<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>
|
||||
@@ -227,7 +227,7 @@
|
||||
{% if blogrollStatus and blogrollStatus.source == "indiekit" %}
|
||||
{% 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="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'">
|
||||
<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>
|
||||
@@ -243,7 +243,7 @@
|
||||
{% if blogrollStatus and blogrollStatus.source == "indiekit" %}
|
||||
{% 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="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'">
|
||||
<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>
|
||||
@@ -258,7 +258,7 @@
|
||||
{# 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="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'">
|
||||
<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>
|
||||
@@ -272,7 +272,7 @@
|
||||
{# Categories/Tags #}
|
||||
{% 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="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'">
|
||||
<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>
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
name="source"
|
||||
placeholder="https://your-site.com/response"
|
||||
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
|
||||
type="submit"
|
||||
|
||||
@@ -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>
|
||||
<div class="space-y-4">
|
||||
{% 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">
|
||||
<a href="{{ post.url }}" class="hover:text-accent-600 dark:hover:text-accent-400">
|
||||
{{ post.data.title or post.data.name or "Untitled" }}
|
||||
@@ -110,7 +110,7 @@ withSidebar: true
|
||||
<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>
|
||||
<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">
|
||||
<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"/>
|
||||
@@ -119,7 +119,7 @@ withSidebar: true
|
||||
<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>
|
||||
</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">
|
||||
<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"/>
|
||||
@@ -128,7 +128,7 @@ withSidebar: true
|
||||
<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>
|
||||
</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">
|
||||
<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"/>
|
||||
|
||||
2
blog.njk
2
blog.njk
@@ -24,7 +24,7 @@ permalink: "blog/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumber
|
||||
{% if paginatedPosts.length > 0 %}
|
||||
<filter-container oninit leave-url-alone>
|
||||
<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="article">Articles</option>
|
||||
<option value="note">Notes</option>
|
||||
|
||||
@@ -65,7 +65,7 @@ permalink: /blogroll/
|
||||
<template x-for="blog in blogs" :key="blog.id">
|
||||
<a
|
||||
: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"
|
||||
rel="noopener"
|
||||
>
|
||||
@@ -109,7 +109,7 @@ permalink: /blogroll/
|
||||
{# Category Items Tab (one for each category) #}
|
||||
<div x-show="activeTab.startsWith('category:') && !loading" class="space-y-4">
|
||||
<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-1 min-w-0">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
|
||||
@@ -4,28 +4,28 @@
|
||||
*,*::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}
|
||||
|
||||
/* Dark mode base */
|
||||
body{background-color:#fff;color:#18181b}
|
||||
.dark body{background-color:#09090b;color:#f4f4f5}
|
||||
/* Dark mode base — warm stone palette */
|
||||
body{background-color:#faf8f5;color:#1c1b19}
|
||||
.dark body{background-color:#0f0e0d;color:#faf8f5}
|
||||
|
||||
/* Container */
|
||||
.container{max-width:64rem;margin-left:auto;margin-right:auto;padding-left:1rem;padding-right:1rem}
|
||||
|
||||
/* 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}
|
||||
.dark .site-header{background-color:#18181b;border-bottom-color:#3f3f46}
|
||||
.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:#1c1b19;border-bottom-color:#3f3b35}
|
||||
.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}
|
||||
.dark .site-title{color:#fff}
|
||||
.site-title{font-size:1.25rem;font-weight:700;color:#1c1b19;text-decoration:none}
|
||||
.dark .site-title{color:#faf8f5}
|
||||
|
||||
/* Header actions — hidden on mobile */
|
||||
.header-actions{display:none}
|
||||
@media(min-width:768px){.header-actions{display:flex;align-items:center;gap:1rem}}
|
||||
|
||||
/* 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}}
|
||||
.dark .menu-toggle{color:#a1a1aa}
|
||||
.dark .menu-toggle{color:#a09a90}
|
||||
|
||||
/* Hidden utility */
|
||||
.hidden{display:none!important}
|
||||
@@ -48,10 +48,10 @@ main.container{padding-top:1.5rem;padding-bottom:1.5rem}
|
||||
|
||||
/* Basic typography — prevent FOUT */
|
||||
h1,h2,h3,h4{margin:0;line-height:1.25}
|
||||
a{color:#2563eb}
|
||||
.dark a{color:#60a5fa}
|
||||
a{color:#b45309}
|
||||
.dark a{color:#fbbf24}
|
||||
|
||||
/* Prevent flash of unstyled content for nav */
|
||||
.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}
|
||||
.dark .site-nav>a,.dark .site-nav .nav-dropdown-trigger{color:#a1a1aa}
|
||||
.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:#a09a90}
|
||||
|
||||
@@ -37,12 +37,12 @@ pre[class*="language-"] {
|
||||
}
|
||||
|
||||
pre[class*="language-"] {
|
||||
background: #f6f8fa;
|
||||
background: #f4f2ee;
|
||||
border: 1px solid #e1e4e8;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*="language-"] {
|
||||
background: #f6f8fa;
|
||||
background: #f4f2ee;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
|
||||
108
css/tailwind.css
108
css/tailwind.css
@@ -103,10 +103,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark mode body background */
|
||||
/* Body background — warm stone canvas */
|
||||
@layer base {
|
||||
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 {
|
||||
/* 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 {
|
||||
@@ -149,7 +149,7 @@
|
||||
}
|
||||
|
||||
.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(100dvh - 5rem);
|
||||
}
|
||||
@@ -169,7 +169,7 @@
|
||||
|
||||
/* Mobile navigation dropdown */
|
||||
.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(100dvh - 4rem);
|
||||
}
|
||||
@@ -351,7 +351,7 @@
|
||||
|
||||
/* Widget cards */
|
||||
.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 {
|
||||
@@ -388,7 +388,7 @@
|
||||
|
||||
/* Post cards */
|
||||
.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 {
|
||||
@@ -500,7 +500,7 @@
|
||||
}
|
||||
|
||||
.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 {
|
||||
@@ -625,11 +625,11 @@
|
||||
/* Pagefind UI theme overrides — outside @layer for higher specificity over Pagefind's :root defaults */
|
||||
#search .pagefind-ui {
|
||||
--pagefind-ui-scale: 1;
|
||||
--pagefind-ui-primary: #0d9488;
|
||||
--pagefind-ui-text: #18181b;
|
||||
--pagefind-ui-background: #ffffff;
|
||||
--pagefind-ui-border: #e4e4e7;
|
||||
--pagefind-ui-tag: #f4f4f5;
|
||||
--pagefind-ui-primary: #b45309;
|
||||
--pagefind-ui-text: #1c1b19;
|
||||
--pagefind-ui-background: #faf8f5;
|
||||
--pagefind-ui-border: #e8e5df;
|
||||
--pagefind-ui-tag: #f4f2ee;
|
||||
--pagefind-ui-border-width: 1px;
|
||||
--pagefind-ui-border-radius: 8px;
|
||||
--pagefind-ui-image-border-radius: 8px;
|
||||
@@ -637,60 +637,60 @@
|
||||
}
|
||||
|
||||
.dark #search .pagefind-ui {
|
||||
--pagefind-ui-primary: #2dd4bf;
|
||||
--pagefind-ui-text: #f4f4f5;
|
||||
--pagefind-ui-background: #09090b;
|
||||
--pagefind-ui-border: #3f3f46;
|
||||
--pagefind-ui-tag: #27272a;
|
||||
--pagefind-ui-primary: #fbbf24;
|
||||
--pagefind-ui-text: #faf8f5;
|
||||
--pagefind-ui-background: #0f0e0d;
|
||||
--pagefind-ui-border: #3f3b35;
|
||||
--pagefind-ui-tag: #2a2722;
|
||||
}
|
||||
|
||||
/* Search input */
|
||||
#search .pagefind-ui__search-input {
|
||||
background-color: #ffffff;
|
||||
color: #18181b;
|
||||
border-color: #e4e4e7;
|
||||
background-color: #faf8f5;
|
||||
color: #1c1b19;
|
||||
border-color: #e8e5df;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.dark #search .pagefind-ui__search-input {
|
||||
background-color: #18181b;
|
||||
color: #f4f4f5;
|
||||
border-color: #3f3f46;
|
||||
background-color: #1c1b19;
|
||||
color: #faf8f5;
|
||||
border-color: #3f3b35;
|
||||
}
|
||||
|
||||
#search .pagefind-ui__search-input:focus {
|
||||
outline: 2px solid #3b82f6;
|
||||
outline: 2px solid #d97706;
|
||||
outline-offset: 2px;
|
||||
border-color: #3b82f6;
|
||||
border-color: #d97706;
|
||||
}
|
||||
|
||||
.dark #search .pagefind-ui__search-input:focus {
|
||||
outline-color: #60a5fa;
|
||||
border-color: #60a5fa;
|
||||
outline-color: #fbbf24;
|
||||
border-color: #fbbf24;
|
||||
}
|
||||
|
||||
/* Search clear button */
|
||||
#search .pagefind-ui__search-clear {
|
||||
color: #52525b;
|
||||
background-color: #ffffff;
|
||||
color: #5c5750;
|
||||
background-color: #faf8f5;
|
||||
}
|
||||
|
||||
.dark #search .pagefind-ui__search-clear {
|
||||
color: #a1a1aa;
|
||||
background-color: #18181b;
|
||||
color: #a09a90;
|
||||
background-color: #1c1b19;
|
||||
}
|
||||
|
||||
#search .pagefind-ui__search-clear:hover {
|
||||
color: #18181b;
|
||||
color: #1c1b19;
|
||||
}
|
||||
|
||||
.dark #search .pagefind-ui__search-clear:hover {
|
||||
color: #f4f4f5;
|
||||
color: #faf8f5;
|
||||
}
|
||||
|
||||
/* Result links */
|
||||
#search .pagefind-ui__result-link {
|
||||
color: #2563eb;
|
||||
color: #b45309;
|
||||
}
|
||||
|
||||
#search .pagefind-ui__result-link:hover {
|
||||
@@ -698,64 +698,64 @@
|
||||
}
|
||||
|
||||
.dark #search .pagefind-ui__result-link {
|
||||
color: #60a5fa;
|
||||
color: #fbbf24;
|
||||
}
|
||||
|
||||
/* Result excerpts */
|
||||
#search .pagefind-ui__result-excerpt {
|
||||
color: #52525b;
|
||||
color: #5c5750;
|
||||
}
|
||||
|
||||
.dark #search .pagefind-ui__result-excerpt {
|
||||
color: #a1a1aa;
|
||||
color: #a09a90;
|
||||
}
|
||||
|
||||
/* Highlighted search terms in results */
|
||||
#search .pagefind-ui__result-excerpt mark,
|
||||
#search mark {
|
||||
background-color: #dbeafe;
|
||||
color: #1e40af;
|
||||
background-color: #fef3c7;
|
||||
color: #92400e;
|
||||
padding: 0.1em 0.2em;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.dark #search .pagefind-ui__result-excerpt mark,
|
||||
.dark #search mark {
|
||||
background-color: #1e3a8a;
|
||||
color: #bfdbfe;
|
||||
background-color: #78350f;
|
||||
color: #fde68a;
|
||||
}
|
||||
|
||||
/* Message (result count) */
|
||||
#search .pagefind-ui__message {
|
||||
color: #52525b;
|
||||
color: #5c5750;
|
||||
}
|
||||
|
||||
.dark #search .pagefind-ui__message {
|
||||
color: #a1a1aa;
|
||||
color: #a09a90;
|
||||
}
|
||||
|
||||
/* "Load more" button */
|
||||
#search .pagefind-ui__button {
|
||||
color: #2563eb;
|
||||
background-color: #ffffff;
|
||||
border-color: #e4e4e7;
|
||||
color: #b45309;
|
||||
background-color: #faf8f5;
|
||||
border-color: #e8e5df;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#search .pagefind-ui__button:hover {
|
||||
background-color: #eff6ff;
|
||||
border-color: #2563eb;
|
||||
background-color: #fffbeb;
|
||||
border-color: #b45309;
|
||||
}
|
||||
|
||||
.dark #search .pagefind-ui__button {
|
||||
color: #60a5fa;
|
||||
background-color: #09090b;
|
||||
border-color: #3f3f46;
|
||||
color: #fbbf24;
|
||||
background-color: #0f0e0d;
|
||||
border-color: #3f3b35;
|
||||
}
|
||||
|
||||
.dark #search .pagefind-ui__button:hover {
|
||||
background-color: #18181b;
|
||||
border-color: #60a5fa;
|
||||
background-color: #1c1b19;
|
||||
border-color: #fbbf24;
|
||||
}
|
||||
|
||||
/* Filter panel labels */
|
||||
|
||||
@@ -21,7 +21,7 @@ permalink: "digest/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumb
|
||||
{% if paginatedDigests.length > 0 %}
|
||||
<ul class="space-y-4">
|
||||
{% 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">
|
||||
<h2 class="font-semibold text-surface-900 dark:text-surface-100 hover:text-accent-600 dark:hover:text-accent-400">
|
||||
{{ d.label }}
|
||||
|
||||
@@ -144,7 +144,7 @@ withSidebar: true
|
||||
{# Trends Tab #}
|
||||
<div x-show="activeTab === 'trends'" x-cloak>
|
||||
{% 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>
|
||||
<div class="flex items-end gap-1 h-32">
|
||||
{% set maxCount = 1 %}
|
||||
@@ -185,7 +185,7 @@ withSidebar: true
|
||||
{% if funkwhaleActivity.listenings.length %}
|
||||
<div class="space-y-3">
|
||||
{% 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 %}
|
||||
<img src="{{ listening.coverUrl }}" alt="" class="w-12 h-12 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
|
||||
{% else %}
|
||||
@@ -235,7 +235,7 @@ withSidebar: true
|
||||
|
||||
<div class="grid gap-3 sm:gap-4 md:grid-cols-2">
|
||||
{% 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 %}
|
||||
<img src="{{ favorite.coverUrl }}" alt="" class="w-14 h-14 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
|
||||
{% else %}
|
||||
|
||||
20
github.njk
20
github.njk
@@ -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">
|
||||
<div class="flex items-start justify-between mb-3">
|
||||
<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 }}
|
||||
</a>
|
||||
</h3>
|
||||
@@ -75,7 +75,7 @@ withSidebar: true
|
||||
{% for commit in repo.commits %}
|
||||
<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">
|
||||
<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>
|
||||
<span class="text-surface-700 dark:text-surface-300 truncate min-w-0 flex-1">{{ commit.message }}</span>
|
||||
</li>
|
||||
@@ -101,12 +101,12 @@ withSidebar: true
|
||||
{% if githubActivity.commits.length %}
|
||||
<div class="space-y-3">
|
||||
{% 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">
|
||||
{{ commit.sha }}
|
||||
</code>
|
||||
<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 }}
|
||||
</a>
|
||||
<p class="text-xs text-surface-500 mt-1">
|
||||
@@ -134,14 +134,14 @@ withSidebar: true
|
||||
|
||||
<div class="space-y-3">
|
||||
{% 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" %}
|
||||
<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 %}
|
||||
<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 %}
|
||||
<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 }}
|
||||
</a>
|
||||
<p class="text-xs text-surface-500 mt-1">
|
||||
@@ -168,9 +168,9 @@ withSidebar: true
|
||||
{% if githubRepos.length %}
|
||||
<div class="grid gap-3 sm:gap-4 md:grid-cols-2">
|
||||
{% 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">
|
||||
<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 }}
|
||||
</a>
|
||||
</h3>
|
||||
@@ -223,9 +223,9 @@ withSidebar: true
|
||||
{% if githubActivity.stars.length %}
|
||||
<div class="grid gap-3 sm:gap-4 md:grid-cols-2">
|
||||
{% 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">
|
||||
<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 }}
|
||||
</a>
|
||||
</h3>
|
||||
|
||||
@@ -179,7 +179,7 @@ withSidebar: true
|
||||
<div class="grid gap-4 sm:gap-6 md:grid-cols-2">
|
||||
{# Funkwhale 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">
|
||||
<span class="w-3 h-3 rounded-full bg-purple-500"></span>
|
||||
Funkwhale
|
||||
@@ -217,7 +217,7 @@ withSidebar: true
|
||||
|
||||
{# Last.fm 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">
|
||||
<span class="w-3 h-3 rounded-full bg-red-500"></span>
|
||||
Last.fm
|
||||
@@ -270,7 +270,7 @@ withSidebar: true
|
||||
{% if funkwhaleActivity.listenings.length %}
|
||||
<div x-show="activeSource === 'all' || activeSource === 'funkwhale'">
|
||||
{% 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 %}
|
||||
<img src="{{ listening.coverUrl }}" alt="" class="w-12 h-12 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
|
||||
{% else %}
|
||||
@@ -324,7 +324,7 @@ withSidebar: true
|
||||
{% if lastfmActivity.scrobbles.length %}
|
||||
<div x-show="activeSource === 'all' || activeSource === 'lastfm'">
|
||||
{% 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 %}
|
||||
<img src="{{ scrobble.coverUrl }}" alt="" class="w-12 h-12 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
|
||||
{% else %}
|
||||
@@ -396,7 +396,7 @@ withSidebar: true
|
||||
|
||||
<div class="grid gap-3 sm:gap-4 md:grid-cols-2">
|
||||
{% 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 %}
|
||||
<img src="{{ track.coverUrl }}" alt="" class="w-14 h-14 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
|
||||
{% else %}
|
||||
@@ -457,7 +457,7 @@ withSidebar: true
|
||||
|
||||
<div class="grid gap-3 sm:gap-4 md:grid-cols-2">
|
||||
{% 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 %}
|
||||
<img src="{{ favorite.coverUrl }}" alt="" class="w-14 h-14 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
|
||||
{% else %}
|
||||
|
||||
6
news.njk
6
news.njk
@@ -125,7 +125,7 @@ withSidebar: true
|
||||
{# List View #}
|
||||
<div x-show="viewMode === 'list'" class="space-y-3">
|
||||
<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
|
||||
x-show="item.imageUrl"
|
||||
:src="item.imageUrl"
|
||||
@@ -190,7 +190,7 @@ withSidebar: true
|
||||
{# Card View #}
|
||||
<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">
|
||||
<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">
|
||||
<img
|
||||
:src="item.imageUrl"
|
||||
@@ -243,7 +243,7 @@ withSidebar: true
|
||||
{# Full/Expanded View #}
|
||||
<div x-show="viewMode === 'full'" class="space-y-6">
|
||||
<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">
|
||||
<img
|
||||
:src="item.imageUrl"
|
||||
|
||||
@@ -66,7 +66,7 @@ permalink: /podroll/
|
||||
{# Episodes List #}
|
||||
<div x-show="episodes.length > 0" class="space-y-4">
|
||||
<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 #}
|
||||
<div class="flex items-start gap-4 mb-4">
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
@@ -41,7 +41,7 @@ permalink: /readlater/
|
||||
<select
|
||||
x-model="selectedSource"
|
||||
@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>
|
||||
<template x-for="src in sources" :key="src">
|
||||
@@ -58,7 +58,7 @@ permalink: /readlater/
|
||||
x-model.debounce.300ms="searchQuery"
|
||||
@input="fetchData()"
|
||||
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">
|
||||
<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>
|
||||
<button
|
||||
@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'"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
@@ -80,7 +80,7 @@ permalink: /readlater/
|
||||
{# Items List #}
|
||||
<div x-show="!loading" class="space-y-4">
|
||||
<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-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">
|
||||
|
||||
10
starred.njk
10
starred.njk
@@ -108,7 +108,7 @@ eleventyExcludeFromCollections: true
|
||||
x-model="searchQuery"
|
||||
@input="resetView()"
|
||||
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">
|
||||
<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
|
||||
x-model="sortBy"
|
||||
@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="starredAt">Sort: Recently Starred</option>
|
||||
@@ -138,7 +138,7 @@ eleventyExcludeFromCollections: true
|
||||
<select
|
||||
x-model="languageFilter"
|
||||
@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>
|
||||
<template x-for="lang in availableLanguages" :key="lang">
|
||||
@@ -153,7 +153,7 @@ eleventyExcludeFromCollections: true
|
||||
@click="starCountMin = opt.value; resetView()"
|
||||
:class="starCountMin === opt.value
|
||||
? '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"
|
||||
x-text="opt.label"
|
||||
></button>
|
||||
@@ -184,7 +184,7 @@ eleventyExcludeFromCollections: true
|
||||
{# ===== REPO 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">
|
||||
<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">
|
||||
<template x-if="repo.ownerAvatar">
|
||||
<img :src="repo.ownerAvatar" :alt="repo.ownerLogin" class="w-5 h-5 rounded-full" loading="lazy">
|
||||
|
||||
@@ -13,6 +13,35 @@ export default {
|
||||
theme: {
|
||||
extend: {
|
||||
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: {
|
||||
50: "#eff6ff",
|
||||
100: "#dbeafe",
|
||||
@@ -26,32 +55,6 @@ export default {
|
||||
900: "#1e3a8a",
|
||||
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: {
|
||||
sans: [
|
||||
|
||||
@@ -87,7 +87,7 @@ withSidebar: true
|
||||
<div class="flex-shrink-0">
|
||||
{% 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="w-2 h-2 bg-white rounded-full"></span>
|
||||
<span class="w-2 h-2 bg-surface-50 rounded-full"></span>
|
||||
LIVE
|
||||
</span>
|
||||
{% elif channelLiveStatus and channelLiveStatus.isUpcoming %}
|
||||
@@ -149,7 +149,7 @@ withSidebar: true
|
||||
{% if channelLiveStatus.isLive %}
|
||||
<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="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
|
||||
</span>
|
||||
</div>
|
||||
@@ -173,7 +173,7 @@ withSidebar: true
|
||||
{% if channelVideos and channelVideos.length %}
|
||||
<div class="grid gap-4 sm:gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{% 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">
|
||||
<div class="relative aspect-video">
|
||||
{% if video.thumbnail %}
|
||||
@@ -198,7 +198,7 @@ withSidebar: true
|
||||
</span>
|
||||
{% 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="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
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user