fix: stable height GitHub widget and consistent tab sizing

- Add min-h-[320px] to prevent layout shift when switching tabs
- Show 5 items per tab for consistent content height
- Simplify tab buttons to text-only at text-xs for compact layout

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ricardo
2026-02-11 17:58:38 +01:00
parent 6b7bc3644d
commit eedcee70cb

View File

@@ -12,140 +12,141 @@
<button
@click="activeTab = 'commits'"
:class="activeTab === 'commits' ? '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"
class="flex items-center gap-1.5 px-2 py-2 text-xs font-medium transition-colors -mb-px"
>
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"/></svg>
Commits
</button>
<button
@click="activeTab = 'repos'"
:class="activeTab === 'repos' ? '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"
class="flex items-center gap-1.5 px-2 py-2 text-xs font-medium transition-colors -mb-px"
>
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4"/></svg>
Repos
</button>
<button
@click="activeTab = 'featured'"
:class="activeTab === 'featured' ? '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"
class="flex items-center gap-1.5 px-2 py-2 text-xs font-medium transition-colors -mb-px"
>
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z"/></svg>
Featured
</button>
<button
@click="activeTab = 'prs'"
:class="activeTab === 'prs' ? '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"
class="flex items-center gap-1.5 px-2 py-2 text-xs font-medium transition-colors -mb-px"
>
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
PRs
</button>
</div>
{# Loading state #}
<div x-show="loading" class="text-sm text-surface-500 py-4 text-center">
Loading...
</div>
{# Tab content — fixed height container to prevent layout shift #}
<div class="min-h-[320px]">
{# Commits Tab #}
<div x-show="activeTab === 'commits' && !loading" x-cloak>
<ul x-show="commits.length > 0" class="space-y-3">
<template x-for="commit in commits.slice(0, 6)" :key="commit.sha">
<li class="border-b border-surface-200 dark:border-surface-700 pb-3 last:border-0">
<a :href="commit.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 line-clamp-2" x-text="commit.message"></p>
<div class="flex items-center gap-2 mt-1.5 text-xs text-surface-500">
<code class="text-xs font-mono bg-surface-100 dark:bg-surface-800 px-1 py-0.5 rounded" x-text="commit.sha"></code>
<span class="truncate" x-text="commit.repo?.split('/')[1] || commit.repo"></span>
<span x-text="formatDate(commit.date)"></span>
</div>
</a>
</li>
</template>
</ul>
<div x-show="commits.length === 0" class="text-sm text-surface-500 py-2">No recent commits.</div>
</div>
{# Loading state #}
<div x-show="loading" class="text-sm text-surface-500 py-4 text-center">
Loading...
</div>
{# Repos Tab #}
<div x-show="activeTab === 'repos' && !loading" x-cloak>
<ul x-show="repos.length > 0" class="space-y-3">
<template x-for="repo in repos.slice(0, 8)" :key="repo.name">
<li class="border-b border-surface-200 dark:border-surface-700 pb-3 last:border-0">
<a :href="repo.html_url" target="_blank" rel="noopener" class="block group">
<div class="flex items-center gap-2">
<span class="font-medium text-sm text-primary-600 dark:text-primary-400 group-hover:underline truncate" x-text="repo.name"></span>
<span x-show="repo.language" class="text-xs px-1.5 py-0.5 rounded bg-surface-100 dark:bg-surface-800 text-surface-600 dark:text-surface-400 flex-shrink-0" x-text="repo.language"></span>
</div>
<p x-show="repo.description" class="text-xs text-surface-600 dark:text-surface-400 mt-1 line-clamp-2" x-text="repo.description"></p>
<div class="flex items-center gap-3 mt-1.5 text-xs text-surface-500">
<span x-show="repo.stargazers_count > 0" 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>
<span x-text="repo.stargazers_count"></span>
</span>
<span x-text="formatDate(repo.updated_at)"></span>
</div>
</a>
</li>
</template>
</ul>
<div x-show="repos.length === 0" class="text-sm text-surface-500 py-2">No repositories found.</div>
</div>
{# Commits Tab #}
<div x-show="activeTab === 'commits' && !loading" x-cloak>
<ul x-show="commits.length > 0" class="space-y-3">
<template x-for="commit in commits.slice(0, 5)" :key="commit.sha">
<li class="border-b border-surface-200 dark:border-surface-700 pb-3 last:border-0">
<a :href="commit.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 line-clamp-2" x-text="commit.message"></p>
<div class="flex items-center gap-2 mt-1.5 text-xs text-surface-500">
<code class="text-xs font-mono bg-surface-100 dark:bg-surface-800 px-1 py-0.5 rounded" x-text="commit.sha"></code>
<span class="truncate" x-text="commit.repo?.split('/')[1] || commit.repo"></span>
<span x-text="formatDate(commit.date)"></span>
</div>
</a>
</li>
</template>
</ul>
<div x-show="commits.length === 0" class="text-sm text-surface-500 py-2">No recent commits.</div>
</div>
{# Featured Tab #}
<div x-show="activeTab === 'featured' && !loading" x-cloak>
<ul x-show="featured.length > 0" class="space-y-3">
<template x-for="repo in featured.slice(0, 5)" :key="repo.fullName || repo.name">
<li class="border-b border-surface-200 dark:border-surface-700 pb-3 last:border-0">
<a :href="repo.url" target="_blank" rel="noopener" class="block group">
<div class="flex items-center gap-2">
<span class="font-medium text-sm text-primary-600 dark:text-primary-400 group-hover:underline truncate" x-text="repo.name"></span>
<span x-show="repo.language" class="text-xs px-1.5 py-0.5 rounded bg-surface-100 dark:bg-surface-800 text-surface-600 dark:text-surface-400 flex-shrink-0" x-text="repo.language"></span>
</div>
<p x-show="repo.description" class="text-xs text-surface-600 dark:text-surface-400 mt-1 line-clamp-2" x-text="repo.description"></p>
<div class="flex items-center gap-3 mt-1.5 text-xs text-surface-500">
<span x-show="repo.stars > 0" 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>
<span x-text="repo.stars"></span>
</span>
<span x-show="repo.forks > 0" class="flex items-center gap-1">
<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="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2"/></svg>
<span x-text="repo.forks"></span>
</span>
</div>
</a>
</li>
</template>
</ul>
<div x-show="featured.length === 0" class="text-sm text-surface-500 py-2">No featured projects.</div>
</div>
{# Repos Tab #}
<div x-show="activeTab === 'repos' && !loading" x-cloak>
<ul x-show="repos.length > 0" class="space-y-3">
<template x-for="repo in repos.slice(0, 5)" :key="repo.name">
<li class="border-b border-surface-200 dark:border-surface-700 pb-3 last:border-0">
<a :href="repo.html_url" target="_blank" rel="noopener" class="block group">
<div class="flex items-center gap-2">
<span class="font-medium text-sm text-primary-600 dark:text-primary-400 group-hover:underline truncate" x-text="repo.name"></span>
<span x-show="repo.language" class="text-xs px-1.5 py-0.5 rounded bg-surface-100 dark:bg-surface-800 text-surface-600 dark:text-surface-400 flex-shrink-0" x-text="repo.language"></span>
</div>
<p x-show="repo.description" class="text-xs text-surface-600 dark:text-surface-400 mt-1 line-clamp-2" x-text="repo.description"></p>
<div class="flex items-center gap-3 mt-1.5 text-xs text-surface-500">
<span x-show="repo.stargazers_count > 0" 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>
<span x-text="repo.stargazers_count"></span>
</span>
<span x-text="formatDate(repo.updated_at)"></span>
</div>
</a>
</li>
</template>
</ul>
<div x-show="repos.length === 0" class="text-sm text-surface-500 py-2">No repositories found.</div>
</div>
{# Featured Tab #}
<div x-show="activeTab === 'featured' && !loading" x-cloak>
<ul x-show="featured.length > 0" class="space-y-3">
<template x-for="repo in featured.slice(0, 5)" :key="repo.fullName || repo.name">
<li class="border-b border-surface-200 dark:border-surface-700 pb-3 last:border-0">
<a :href="repo.url" target="_blank" rel="noopener" class="block group">
<div class="flex items-center gap-2">
<span class="font-medium text-sm text-primary-600 dark:text-primary-400 group-hover:underline truncate" x-text="repo.name"></span>
<span x-show="repo.language" class="text-xs px-1.5 py-0.5 rounded bg-surface-100 dark:bg-surface-800 text-surface-600 dark:text-surface-400 flex-shrink-0" x-text="repo.language"></span>
</div>
<p x-show="repo.description" class="text-xs text-surface-600 dark:text-surface-400 mt-1 line-clamp-2" x-text="repo.description"></p>
<div class="flex items-center gap-3 mt-1.5 text-xs text-surface-500">
<span x-show="repo.stars > 0" 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>
<span x-text="repo.stars"></span>
</span>
<span x-show="repo.forks > 0" class="flex items-center gap-1">
<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="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2"/></svg>
<span x-text="repo.forks"></span>
</span>
</div>
</a>
</li>
</template>
</ul>
<div x-show="featured.length === 0" class="text-sm text-surface-500 py-2">No featured projects.</div>
</div>
{# PRs Tab #}
<div x-show="activeTab === 'prs' && !loading" x-cloak>
<ul x-show="contributions.length > 0" class="space-y-3">
<template x-for="item in contributions.slice(0, 5)" :key="item.url">
<li class="border-b border-surface-200 dark:border-surface-700 pb-3 last:border-0">
<a :href="item.url" target="_blank" rel="noopener" class="block group">
<div class="flex items-center gap-2">
<span
class="flex-shrink-0 w-4 h-4 rounded-full flex items-center justify-center"
:class="item.type === 'pr' ? 'bg-green-100 dark:bg-green-900 text-green-600 dark:text-green-400' : 'bg-purple-100 dark:bg-purple-900 text-purple-600 dark:text-purple-400'"
>
<svg x-show="item.type === 'pr'" 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="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
<svg x-show="item.type === 'issue'" class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" stroke-width="2"/><line x1="12" y1="8" x2="12" y2="12" stroke-width="2"/><line x1="12" y1="16" x2="12.01" y2="16" stroke-width="2"/></svg>
</span>
<span class="text-sm text-surface-700 dark:text-surface-300 group-hover:text-primary-600 dark:group-hover:text-primary-400 transition-colors truncate" x-text="item.title"></span>
</div>
<div class="flex items-center gap-2 mt-1.5 text-xs text-surface-500 pl-6">
<span x-text="item.repo?.split('/')[1] || item.repo"></span>
<span x-show="item.number" x-text="'#' + item.number"></span>
<span x-text="formatDate(item.date)"></span>
</div>
</a>
</li>
</template>
</ul>
<div x-show="contributions.length === 0" class="text-sm text-surface-500 py-2">No recent PRs or issues.</div>
</div>
{# PRs Tab #}
<div x-show="activeTab === 'prs' && !loading" x-cloak>
<ul x-show="contributions.length > 0" class="space-y-3">
<template x-for="item in contributions.slice(0, 6)" :key="item.url">
<li class="border-b border-surface-200 dark:border-surface-700 pb-3 last:border-0">
<a :href="item.url" target="_blank" rel="noopener" class="block group">
<div class="flex items-center gap-2">
<span
class="flex-shrink-0 w-4 h-4 rounded-full flex items-center justify-center"
:class="item.type === 'pr' ? 'bg-green-100 dark:bg-green-900 text-green-600 dark:text-green-400' : 'bg-purple-100 dark:bg-purple-900 text-purple-600 dark:text-purple-400'"
>
<svg x-show="item.type === 'pr'" 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="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
<svg x-show="item.type === 'issue'" class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" stroke-width="2"/><line x1="12" y1="8" x2="12" y2="12" stroke-width="2"/><line x1="12" y1="16" x2="12.01" y2="16" stroke-width="2"/></svg>
</span>
<span class="text-sm text-surface-700 dark:text-surface-300 group-hover:text-primary-600 dark:group-hover:text-primary-400 transition-colors truncate" x-text="item.title"></span>
</div>
<div class="flex items-center gap-2 mt-1.5 text-xs text-surface-500 pl-6">
<span x-text="item.repo?.split('/')[1] || item.repo"></span>
<span x-show="item.number" x-text="'#' + item.number"></span>
<span x-text="formatDate(item.date)"></span>
</div>
</a>
</li>
</template>
</ul>
<div x-show="contributions.length === 0" class="text-sm text-surface-500 py-2">No recent PRs or issues.</div>
</div>
{# Footer link #}
@@ -176,7 +177,7 @@ function githubWidget(username) {
];
if (username) {
fetches.push(
fetch(`https://api.github.com/users/${username}/repos?sort=updated&per_page=10&type=owner`, {
fetch('https://api.github.com/users/' + username + '/repos?sort=updated&per_page=10&type=owner', {
headers: { 'Accept': 'application/vnd.github.v3+json' }
}).then(r => r.ok ? r.json() : null).catch(() => null)
);