Files
nas-tools/dashboard/frontend/src/routes/Gitea.svelte
T
Gan, Jimmy 62856c9343
Deploy Dashboard (Dev) / deploy-dev (push) Successful in 1m11s
fix: comprehensive dark mode support across all pages
- Fix body/html dark background to surface-950
- Add dark scrollbar styling
- Fix App.svelte wrapper to use Tailwind dark: classes instead of conditional strings
- Add dark:bg-surface-800 and dark:border-surface-700 to all cards in Dashboard, Docker, Files, Gitea
- Add dark text variants for headings, labels, and content text
- Add dark hover states for interactive elements
- Enable cross-category sidebar drag-and-drop
2026-03-01 14:59:23 +08:00

125 lines
5.1 KiB
Svelte

<script>
import { onMount } from "svelte";
import { get } from "../lib/api.js";
let repos = $state([]);
let commits = $state([]);
let selectedRepo = $state("");
let loading = $state(true);
let loadingCommits = $state(false);
async function load() {
loading = true;
const data = await get("/gitea/repos");
repos = Array.isArray(data) ? data : data?.data || [];
loading = false;
}
async function showCommits(owner, repo) {
selectedRepo = `${owner}/${repo}`;
loadingCommits = true;
const data = await get(`/gitea/repos/${owner}/${repo}/commits`);
commits = Array.isArray(data) ? data : [];
loadingCommits = false;
}
function timeAgo(d) {
const s = Math.floor((Date.now() - new Date(d)) / 1000);
if (s < 60) return "just now";
if (s < 3600) return Math.floor(s / 60) + "m ago";
if (s < 86400) return Math.floor(s / 3600) + "h ago";
return Math.floor(s / 86400) + "d ago";
}
const langColors = {
Python: "#3572A5", JavaScript: "#f1e05a", Shell: "#89e051", Go: "#00ADD8",
TypeScript: "#3178c6", Markdown: "#083fa1", CSS: "#563d7c", HTML: "#e34c26",
};
onMount(load);
</script>
<div class="space-y-6">
<div>
<h1 class="text-2xl font-bold text-surface-900 dark:text-white tracking-tight">Repositories</h1>
<p class="text-sm text-surface-400 mt-1">{repos.length} repositories on Gitea</p>
</div>
{#if loading}
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
{#each Array(4) as _}
<div class="h-[100px] rounded-xl bg-surface-100 dark:bg-surface-800 animate-pulse"></div>
{/each}
</div>
{:else}
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
{#each repos as r}
<button
class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-4 text-left shadow-sm hover:shadow-md hover:border-primary-200 dark:hover:border-primary-700 transition-all duration-200 group {selectedRepo === `${r.owner?.login}/${r.name}` ? 'ring-2 ring-primary-500 border-primary-300' : ''}"
onclick={() => showCommits(r.owner?.login, r.name)}
>
<div class="flex items-start justify-between">
<div class="min-w-0">
<p class="text-sm font-semibold text-surface-800 dark:text-surface-100 group-hover:text-primary-600 transition-colors truncate">{r.name}</p>
<p class="text-xs text-surface-400 mt-1 line-clamp-1">{r.description || "No description"}</p>
</div>
{#if r.language}
<span class="flex items-center gap-1 text-[11px] text-surface-500 shrink-0 ml-2">
<span class="w-2 h-2 rounded-full" style="background: {langColors[r.language] || '#888'}"></span>
{r.language}
</span>
{/if}
</div>
<p class="text-[11px] text-surface-400 mt-2.5">Updated {timeAgo(r.updated_at)}</p>
</button>
{/each}
</div>
{/if}
<!-- Commits Panel -->
{#if selectedRepo}
<div class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-5 shadow-sm">
<div class="flex items-center justify-between mb-4">
<div>
<h3 class="text-sm font-bold text-surface-800 dark:text-surface-100">Recent Commits</h3>
<p class="text-xs text-surface-400 mt-0.5">{selectedRepo}</p>
</div>
<button
aria-label="Close commits"
class="text-xs text-surface-400 hover:text-surface-600 transition-colors"
onclick={() => { selectedRepo = ""; commits = []; }}
>
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
</button>
</div>
{#if loadingCommits}
<div class="space-y-3">
{#each Array(3) as _}
<div class="h-12 rounded-lg bg-surface-100 animate-pulse"></div>
{/each}
</div>
{:else}
<div class="space-y-0">
{#each commits.slice(0, 15) as c, i}
<div class="flex gap-3 py-2.5 {i < commits.length - 1 ? 'border-b border-surface-100 dark:border-surface-700' : ''}">
<div class="flex flex-col items-center pt-1">
<div class="w-2 h-2 rounded-full bg-primary-400 shrink-0"></div>
{#if i < commits.length - 1}
<div class="w-px flex-1 bg-surface-200 mt-1"></div>
{/if}
</div>
<div class="min-w-0 flex-1">
<p class="text-sm text-surface-700 dark:text-surface-200 truncate">{c.commit?.message?.split("\n")[0]}</p>
<p class="text-[11px] text-surface-400 mt-0.5">
<span class="font-medium">{c.commit?.author?.name}</span> · {timeAgo(c.commit?.author?.date)}
</p>
</div>
<span class="text-[10px] font-mono text-surface-400 bg-surface-50 dark:bg-surface-700 px-1.5 py-0.5 rounded h-fit shrink-0">{c.sha?.slice(0, 7)}</span>
</div>
{/each}
</div>
{/if}
</div>
{/if}
</div>