Added to sidebar author card: - p-pronoun - Structured address (p-locality, p-country-name) - p-org (organization) - u-email - u-key (PGP) - p-category (skills) - Proper Schema.org attributes
307 lines
16 KiB
Plaintext
307 lines
16 KiB
Plaintext
{# Sidebar Components #}
|
|
{# Contains: Author card, Bluesky feed, GitHub repos, RSS feed #}
|
|
|
|
{# Author Card Widget - Full h-card microformat #}
|
|
<div class="widget">
|
|
<div class="h-card p-author" itemscope itemtype="http://schema.org/Person">
|
|
<div class="flex items-center gap-4">
|
|
<a href="{{ site.author.url }}" class="u-url u-uid" rel="me">
|
|
<img
|
|
src="{{ site.author.avatar }}"
|
|
alt="{{ site.author.name }}"
|
|
class="u-photo w-16 h-16 rounded-full object-cover"
|
|
loading="lazy"
|
|
itemprop="image"
|
|
>
|
|
</a>
|
|
<div>
|
|
<a href="{{ site.author.url }}" class="u-url p-name font-bold text-lg block hover:text-primary-600 dark:hover:text-primary-400" itemprop="name">
|
|
{{ site.author.name }}
|
|
</a>
|
|
{% if site.author.pronoun %}
|
|
<span class="p-pronoun text-xs text-surface-500">({{ site.author.pronoun }})</span>
|
|
{% endif %}
|
|
<p class="p-job-title text-sm text-surface-600 dark:text-surface-400" itemprop="jobTitle">{{ site.author.title }}</p>
|
|
{# Structured address #}
|
|
<p class="p-adr h-adr text-sm text-surface-500 dark:text-surface-500" itemprop="address" itemscope itemtype="http://schema.org/PostalAddress">
|
|
{% if site.author.locality %}
|
|
<span class="p-locality" itemprop="addressLocality">{{ site.author.locality }}</span>{% if site.author.country %}, {% endif %}
|
|
{% endif %}
|
|
{% if site.author.country %}
|
|
<span class="p-country-name" itemprop="addressCountry">{{ site.author.country }}</span>
|
|
{% endif %}
|
|
{# Fallback to legacy location #}
|
|
{% if not site.author.locality and site.author.location %}
|
|
<span class="p-locality">{{ site.author.location }}</span>
|
|
{% endif %}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
{# Bio #}
|
|
<p class="p-note mt-3 text-sm text-surface-700 dark:text-surface-300" itemprop="description">{{ site.author.bio }}</p>
|
|
{# Organization #}
|
|
{% if site.author.org %}
|
|
<p class="mt-2 text-sm text-surface-600 dark:text-surface-400">
|
|
<span class="p-org" itemprop="worksFor">{{ site.author.org }}</span>
|
|
</p>
|
|
{% endif %}
|
|
{# Email and PGP Key #}
|
|
<div class="mt-2 flex flex-wrap gap-3 text-sm">
|
|
{% if site.author.email %}
|
|
<a href="mailto:{{ site.author.email }}" class="u-email text-primary-600 dark:text-primary-400 hover:underline" itemprop="email">
|
|
✉️ {{ site.author.email }}
|
|
</a>
|
|
{% endif %}
|
|
{% if site.author.keyUrl %}
|
|
<a href="{{ site.author.keyUrl }}" class="u-key text-surface-500 dark:text-surface-400 hover:underline" rel="pgpkey">
|
|
🔐 PGP Key
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
{# Categories / Skills #}
|
|
{% if site.author.categories and site.author.categories.length %}
|
|
<div class="mt-3 flex flex-wrap gap-1">
|
|
{% for category in site.author.categories %}
|
|
<span class="p-category text-xs px-2 py-0.5 bg-surface-100 dark:bg-surface-800 rounded">{{ category }}</span>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
{# Social Feed Widget - Tabbed Bluesky/Mastodon #}
|
|
{% if (blueskyFeed and blueskyFeed.length) or (mastodonFeed and mastodonFeed.length) %}
|
|
<div class="widget" x-data="{ activeTab: 'bluesky' }">
|
|
<h3 class="widget-title">Social Activity</h3>
|
|
|
|
{# Tab buttons #}
|
|
<div class="flex gap-1 mb-4 border-b border-surface-200 dark:border-surface-700">
|
|
{% if blueskyFeed and blueskyFeed.length %}
|
|
<button
|
|
@click="activeTab = 'bluesky'"
|
|
:class="activeTab === 'bluesky' ? 'border-b-2 border-primary-500 text-primary-600 dark:text-primary-400' : 'text-surface-500 hover:text-surface-700 dark:hover:text-surface-300'"
|
|
class="flex items-center gap-1.5 px-3 py-2 text-sm font-medium transition-colors -mb-px"
|
|
>
|
|
<svg class="w-4 h-4 text-[#0085ff]" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
<path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z"></path>
|
|
</svg>
|
|
Bluesky
|
|
</button>
|
|
{% endif %}
|
|
{% if mastodonFeed and mastodonFeed.length %}
|
|
<button
|
|
@click="activeTab = 'mastodon'"
|
|
:class="activeTab === 'mastodon' ? 'border-b-2 border-primary-500 text-primary-600 dark:text-primary-400' : 'text-surface-500 hover:text-surface-700 dark:hover:text-surface-300'"
|
|
class="flex items-center gap-1.5 px-3 py-2 text-sm font-medium transition-colors -mb-px"
|
|
>
|
|
<svg class="w-4 h-4 text-[#6364ff]" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
<path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.668 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12v6.406z"></path>
|
|
</svg>
|
|
Mastodon
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{# Bluesky Tab Content #}
|
|
{% if blueskyFeed and blueskyFeed.length %}
|
|
<div x-show="activeTab === 'bluesky'" x-cloak>
|
|
<ul class="space-y-3">
|
|
{% for post in blueskyFeed | head(5) %}
|
|
<li class="border-b border-surface-200 dark:border-surface-700 pb-3 last:border-0">
|
|
<a href="{{ post.url }}" target="_blank" rel="noopener" class="block group">
|
|
<p class="text-sm text-surface-700 dark:text-surface-300 group-hover:text-primary-600 dark:group-hover:text-primary-400 transition-colors">
|
|
{{ post.text | truncate(140) }}
|
|
</p>
|
|
<div class="flex items-center gap-3 mt-2 text-xs text-surface-500">
|
|
<time datetime="{{ post.createdAt }}">{{ post.createdAt | date("MMM d, yyyy") }}</time>
|
|
{% if post.likeCount > 0 %}
|
|
<span class="flex items-center gap-1">
|
|
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 24 24"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>
|
|
{{ post.likeCount }}
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
</a>
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
<a href="https://bsky.app/profile/{{ site.feeds.bluesky }}" target="_blank" rel="noopener" class="text-sm text-primary-600 dark:text-primary-400 hover:underline mt-3 inline-flex items-center gap-1">
|
|
View on Bluesky
|
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/></svg>
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{# Mastodon Tab Content #}
|
|
{% if mastodonFeed and mastodonFeed.length %}
|
|
<div x-show="activeTab === 'mastodon'" x-cloak>
|
|
<ul class="space-y-3">
|
|
{% for post in mastodonFeed | head(5) %}
|
|
<li class="border-b border-surface-200 dark:border-surface-700 pb-3 last:border-0">
|
|
<a href="{{ post.url }}" target="_blank" rel="noopener" class="block group">
|
|
<p class="text-sm text-surface-700 dark:text-surface-300 group-hover:text-primary-600 dark:group-hover:text-primary-400 transition-colors">
|
|
{{ post.text | truncate(140) }}
|
|
</p>
|
|
<div class="flex items-center gap-3 mt-2 text-xs text-surface-500">
|
|
<time datetime="{{ post.createdAt }}">{{ post.createdAt | date("MMM d, yyyy") }}</time>
|
|
{% if post.favouritesCount > 0 %}
|
|
<span class="flex items-center gap-1">
|
|
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 24 24"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></svg>
|
|
{{ post.favouritesCount }}
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
</a>
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
<a href="https://{{ site.feeds.mastodon.instance }}/@{{ site.feeds.mastodon.username }}" target="_blank" rel="noopener" class="text-sm text-primary-600 dark:text-primary-400 hover:underline mt-3 inline-flex items-center gap-1">
|
|
View on Mastodon
|
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/></svg>
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{# GitHub Repos Widget #}
|
|
{% if githubRepos and githubRepos.length %}
|
|
<div class="widget">
|
|
<h3 class="widget-title flex items-center gap-2">
|
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
<path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"></path>
|
|
</svg>
|
|
GitHub Projects
|
|
</h3>
|
|
<ul class="space-y-3">
|
|
{% for repo in githubRepos | head(5) %}
|
|
<li class="repo-card">
|
|
<a href="{{ repo.html_url }}" class="font-medium text-primary-600 dark:text-primary-400 hover:underline" target="_blank" rel="noopener">
|
|
{{ repo.name }}
|
|
</a>
|
|
{% if repo.description %}
|
|
<p class="text-sm text-surface-600 dark:text-surface-400 mt-1">{{ repo.description | truncate(80) }}</p>
|
|
{% endif %}
|
|
<div class="repo-meta">
|
|
{% if repo.language %}
|
|
<span>{{ repo.language }}</span>
|
|
{% endif %}
|
|
<span>{{ repo.stargazers_count }} stars</span>
|
|
</div>
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
<a href="https://github.com/{{ site.feeds.github }}" class="text-sm text-primary-600 dark:text-primary-400 hover:underline mt-3 block">
|
|
View all repositories
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{# Funkwhale Now Playing Widget #}
|
|
{% if funkwhaleActivity and (funkwhaleActivity.nowPlaying or funkwhaleActivity.stats) %}
|
|
<div class="widget">
|
|
<h3 class="widget-title flex items-center gap-2">
|
|
<svg class="w-5 h-5 text-purple-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"/>
|
|
</svg>
|
|
Listening
|
|
</h3>
|
|
|
|
{# Now Playing / Recently Played #}
|
|
{% if funkwhaleActivity.nowPlaying and funkwhaleActivity.nowPlaying.track %}
|
|
<div class="{% if funkwhaleActivity.nowPlaying.status == 'now-playing' %}bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800{% else %}bg-surface-50 dark:bg-surface-800{% endif %} rounded-lg p-3 mb-3">
|
|
{% if funkwhaleActivity.nowPlaying.status == 'now-playing' %}
|
|
<div class="flex items-center gap-1.5 text-xs text-green-600 dark:text-green-400 mb-2">
|
|
<span class="flex gap-0.5 items-end h-2.5">
|
|
<span class="w-0.5 bg-green-500 animate-pulse" style="height: 30%;"></span>
|
|
<span class="w-0.5 bg-green-500 animate-pulse" style="height: 70%; animation-delay: 0.2s;"></span>
|
|
<span class="w-0.5 bg-green-500 animate-pulse" style="height: 50%; animation-delay: 0.4s;"></span>
|
|
</span>
|
|
Now Playing
|
|
</div>
|
|
{% elif funkwhaleActivity.nowPlaying.status == 'recently-played' %}
|
|
<div class="text-xs text-surface-500 mb-2">Recently Played</div>
|
|
{% endif %}
|
|
|
|
<div class="flex items-center gap-3">
|
|
{% if funkwhaleActivity.nowPlaying.coverUrl %}
|
|
<img src="{{ funkwhaleActivity.nowPlaying.coverUrl }}" alt="" class="w-12 h-12 rounded object-cover flex-shrink-0" loading="lazy">
|
|
{% endif %}
|
|
<div class="min-w-0 flex-1">
|
|
<p class="font-medium text-sm text-surface-900 dark:text-surface-100 truncate">
|
|
{% if funkwhaleActivity.nowPlaying.trackUrl %}
|
|
<a href="{{ funkwhaleActivity.nowPlaying.trackUrl }}" class="hover:text-primary-600 dark:hover:text-primary-400" target="_blank" rel="noopener">
|
|
{{ funkwhaleActivity.nowPlaying.track }}
|
|
</a>
|
|
{% else %}
|
|
{{ funkwhaleActivity.nowPlaying.track }}
|
|
{% endif %}
|
|
</p>
|
|
<p class="text-xs text-surface-600 dark:text-surface-400 truncate">{{ funkwhaleActivity.nowPlaying.artist }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{# Quick Stats #}
|
|
{% if funkwhaleActivity.stats and funkwhaleActivity.stats.summary %}
|
|
{% set stats = funkwhaleActivity.stats.summary.all %}
|
|
<div class="grid grid-cols-3 gap-2 text-center mb-3">
|
|
<div class="p-2 bg-surface-50 dark:bg-surface-800 rounded">
|
|
<span class="text-lg font-bold text-primary-600 dark:text-primary-400 block">{{ stats.totalPlays or 0 }}</span>
|
|
<span class="text-[10px] text-surface-500 uppercase">plays</span>
|
|
</div>
|
|
<div class="p-2 bg-surface-50 dark:bg-surface-800 rounded">
|
|
<span class="text-lg font-bold text-primary-600 dark:text-primary-400 block">{{ stats.uniqueArtists or 0 }}</span>
|
|
<span class="text-[10px] text-surface-500 uppercase">artists</span>
|
|
</div>
|
|
<div class="p-2 bg-surface-50 dark:bg-surface-800 rounded">
|
|
<span class="text-lg font-bold text-primary-600 dark:text-primary-400 block">{{ stats.totalDurationFormatted or '0m' }}</span>
|
|
<span class="text-[10px] text-surface-500 uppercase">listened</span>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<a href="/listening/" class="text-sm text-primary-600 dark:text-primary-400 hover:underline flex items-center gap-1">
|
|
View full listening history
|
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{# Recent Posts Widget (for non-blog pages) #}
|
|
{% if recentPosts and recentPosts.length %}
|
|
<div class="widget">
|
|
<h3 class="widget-title">Recent Posts</h3>
|
|
<ul class="space-y-2">
|
|
{% for post in recentPosts | head(5) %}
|
|
<li>
|
|
<a href="{{ post.url }}" class="text-sm text-primary-600 dark:text-primary-400 hover:underline">
|
|
{{ post.data.title or post.data.name or "Untitled" }}
|
|
</a>
|
|
<time class="text-xs text-surface-500 block" datetime="{{ post.data.published }}">
|
|
{{ post.data.published | date("MMM d, yyyy") }}
|
|
</time>
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
<a href="/posts/" class="text-sm text-primary-600 dark:text-primary-400 hover:underline mt-3 block">
|
|
View all posts
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{# Categories/Tags Widget #}
|
|
{% if categories and categories.length %}
|
|
<div class="widget">
|
|
<h3 class="widget-title">Categories</h3>
|
|
<div class="flex flex-wrap gap-2">
|
|
{% for category in categories %}
|
|
<a href="/categories/{{ category | slugify }}/" class="p-category">
|
|
{{ category }}
|
|
</a>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|