feat: UI overhaul — accent color, Inter font, widget icons, diversified colors
- Add teal accent color scale and activate Inter font via @font-face - Neutralize nav/footer hovers from primary blue to surface neutrals - Apply accent color to hero subtitle, FAB, CTA buttons, card hovers - Fix reply post-type color from generic primary to distinctive sky blue - Create centralized icon macro (icon.njk) with 24 reusable SVG icons - Add per-widget-type icons and colored left-accent borders to all sidebars - Update .p-category tags from blue to neutral surface with border - Diversify color vocabulary: red (likes), amber (bookmarks/blogroll), green (reposts), purple (funkwhale), sky (replies), orange (subscribe) Confab-Link: http://localhost:8080/sessions/bd3f7012-c703-47e9-bfe2-2ad04ce1842d
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
{# Sidebar — for blog listing pages (/blog/, /notes/, /articles/...) #}
|
||||
{# Data-driven when homepageConfig.blogListingSidebar is configured, otherwise falls back to default widgets #}
|
||||
{# Each widget is wrapped in a collapsible container with localStorage persistence #}
|
||||
{% from "components/icon.njk" import icon %}
|
||||
|
||||
{% if homepageConfig and homepageConfig.blogListingSidebar and homepageConfig.blogListingSidebar.length %}
|
||||
{# === Data-driven mode: render configured widgets === #}
|
||||
@@ -25,6 +26,37 @@
|
||||
{% else %}{% set widgetTitle = widget.type %}
|
||||
{% endif %}
|
||||
|
||||
{# Resolve widget icon and accent border #}
|
||||
{% if widget.type == "social-activity" %}
|
||||
{% set widgetIcon = "globe" %}{% set widgetIconClass = "w-5 h-5 text-[#0085ff]" %}{% set widgetBorder = "border-l-[3px] border-l-[#0085ff]" %}
|
||||
{% elif widget.type == "github-repos" %}
|
||||
{% set widgetIcon = "github" %}{% set widgetIconClass = "w-5 h-5 text-surface-800 dark:text-surface-200" %}{% set widgetBorder = "border-l-[3px] border-l-surface-400 dark:border-l-surface-500" %}
|
||||
{% elif widget.type == "funkwhale" %}
|
||||
{% set widgetIcon = "headphones" %}{% set widgetIconClass = "w-5 h-5 text-purple-500" %}{% set widgetBorder = "border-l-[3px] border-l-purple-400 dark:border-l-purple-500" %}
|
||||
{% elif widget.type == "blogroll" %}
|
||||
{% set widgetIcon = "book-open" %}{% set widgetIconClass = "w-5 h-5 text-amber-500" %}{% set widgetBorder = "border-l-[3px] border-l-amber-400 dark:border-l-amber-500" %}
|
||||
{% elif widget.type == "feedland" %}
|
||||
{% set widgetIcon = "rss" %}{% set widgetIconClass = "w-5 h-5 text-amber-500" %}{% set widgetBorder = "border-l-[3px] border-l-amber-400 dark:border-l-amber-500" %}
|
||||
{% elif widget.type == "subscribe" %}
|
||||
{% set widgetIcon = "rss" %}{% set widgetIconClass = "w-5 h-5 text-orange-500" %}{% set widgetBorder = "border-l-[3px] border-l-orange-400 dark:border-l-orange-500" %}
|
||||
{% elif widget.type == "fediverse-follow" %}
|
||||
{% set widgetIcon = "user-plus" %}{% set widgetIconClass = "w-5 h-5 text-[#a730b8]" %}{% set widgetBorder = "border-l-[3px] border-l-[#a730b8]" %}
|
||||
{% elif widget.type == "author-card" or widget.type == "author-card-compact" %}
|
||||
{% set widgetIcon = "user" %}{% set widgetIconClass = "w-5 h-5 text-surface-500" %}{% set widgetBorder = "" %}
|
||||
{% elif widget.type == "recent-posts" %}
|
||||
{% set widgetIcon = "list" %}{% set widgetIconClass = "w-5 h-5 text-surface-500" %}{% set widgetBorder = "" %}
|
||||
{% elif widget.type == "categories" %}
|
||||
{% set widgetIcon = "tag" %}{% set widgetIconClass = "w-5 h-5 text-surface-500" %}{% set widgetBorder = "" %}
|
||||
{% elif widget.type == "recent-comments" %}
|
||||
{% set widgetIcon = "chat" %}{% set widgetIconClass = "w-5 h-5 text-surface-500" %}{% set widgetBorder = "" %}
|
||||
{% elif widget.type == "search" %}
|
||||
{% set widgetIcon = "search" %}{% set widgetIconClass = "w-5 h-5 text-surface-500" %}{% set widgetBorder = "" %}
|
||||
{% elif widget.type == "webmentions" %}
|
||||
{% set widgetIcon = "share" %}{% set widgetIconClass = "w-5 h-5 text-surface-500" %}{% set widgetBorder = "" %}
|
||||
{% else %}
|
||||
{% set widgetIcon = "" %}{% set widgetIconClass = "" %}{% set widgetBorder = "" %}
|
||||
{% endif %}
|
||||
|
||||
{% set widgetKey = "listing-widget-" + widget.type + "-" + loop.index0 %}
|
||||
{% set defaultOpen = "true" if loop.index0 < 3 else "false" %}
|
||||
|
||||
@@ -33,13 +65,16 @@
|
||||
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">
|
||||
<div class="bg-white 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)"
|
||||
:aria-expanded="open ? 'true' : 'false'"
|
||||
>
|
||||
<h3 class="widget-title font-bold text-lg">{{ widgetTitle }}</h3>
|
||||
<h3 class="widget-title font-bold text-lg flex items-center gap-2">
|
||||
{% if widgetIcon %}{{ icon(widgetIcon, widgetIconClass) }}{% endif %}
|
||||
{{ widgetTitle }}
|
||||
</h3>
|
||||
<svg
|
||||
class="widget-chevron"
|
||||
:class="open && 'rotate-180'"
|
||||
@@ -123,7 +158,7 @@
|
||||
<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">
|
||||
<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">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>
|
||||
</button>
|
||||
<div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" x-cloak>
|
||||
@@ -135,9 +170,9 @@
|
||||
{# 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">
|
||||
<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]">
|
||||
<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">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>
|
||||
</button>
|
||||
<div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" x-cloak>
|
||||
@@ -149,9 +184,9 @@
|
||||
{# 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">
|
||||
<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">
|
||||
<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">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>
|
||||
</button>
|
||||
<div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" x-cloak>
|
||||
@@ -163,9 +198,9 @@
|
||||
{# 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">
|
||||
<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">
|
||||
<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">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>
|
||||
</button>
|
||||
<div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" x-cloak>
|
||||
@@ -179,7 +214,7 @@
|
||||
<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">
|
||||
<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">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>
|
||||
</button>
|
||||
<div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" x-cloak>
|
||||
@@ -192,9 +227,9 @@
|
||||
{% 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">
|
||||
<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">
|
||||
<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">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>
|
||||
</button>
|
||||
<div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" x-cloak>
|
||||
@@ -208,9 +243,9 @@
|
||||
{% 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">
|
||||
<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">
|
||||
<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">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>
|
||||
</button>
|
||||
<div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" x-cloak>
|
||||
@@ -225,7 +260,7 @@
|
||||
<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">
|
||||
<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">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>
|
||||
</button>
|
||||
<div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" x-cloak>
|
||||
@@ -239,7 +274,7 @@
|
||||
<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">
|
||||
<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">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>
|
||||
</button>
|
||||
<div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" x-cloak>
|
||||
|
||||
Reference in New Issue
Block a user