fix: comprehensive dark mode support across all pages
Deploy Dashboard (Dev) / deploy-dev (push) Successful in 1m11s
Deploy Dashboard (Dev) / deploy-dev (push) Successful in 1m11s
- 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
This commit is contained in:
@@ -40,21 +40,21 @@
|
||||
|
||||
<div class="space-y-8">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-surface-900 tracking-tight">Overview</h1>
|
||||
<h1 class="text-2xl font-bold text-surface-900 dark:text-white tracking-tight">Overview</h1>
|
||||
<p class="text-sm text-surface-400 mt-1">System status at a glance</p>
|
||||
</div>
|
||||
|
||||
{#if loading}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{#each Array(4) as _}
|
||||
<div class="h-[120px] rounded-xl bg-surface-100 animate-pulse"></div>
|
||||
<div class="h-[120px] rounded-xl bg-surface-100 dark:bg-surface-800 animate-pulse"></div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Stats Cards -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<!-- CPU -->
|
||||
<div class="bg-white rounded-xl border border-surface-200 p-5 shadow-sm hover:shadow-md transition-shadow duration-200">
|
||||
<div class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-5 shadow-sm hover:shadow-md transition-shadow duration-200">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<p class="text-xs font-semibold uppercase tracking-wider text-surface-400">CPU</p>
|
||||
<div class="w-8 h-8 rounded-lg bg-sky-50 flex items-center justify-center">
|
||||
@@ -66,7 +66,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Memory -->
|
||||
<div class="bg-white rounded-xl border border-surface-200 p-5 shadow-sm hover:shadow-md transition-shadow duration-200">
|
||||
<div class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-5 shadow-sm hover:shadow-md transition-shadow duration-200">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<p class="text-xs font-semibold uppercase tracking-wider text-surface-400">Memory</p>
|
||||
<div class="w-8 h-8 rounded-lg bg-violet-50 flex items-center justify-center">
|
||||
@@ -78,7 +78,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Disk -->
|
||||
<div class="bg-white rounded-xl border border-surface-200 p-5 shadow-sm hover:shadow-md transition-shadow duration-200">
|
||||
<div class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-5 shadow-sm hover:shadow-md transition-shadow duration-200">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<p class="text-xs font-semibold uppercase tracking-wider text-surface-400">Disk</p>
|
||||
<div class="w-8 h-8 rounded-lg bg-amber-50 flex items-center justify-center">
|
||||
@@ -90,14 +90,14 @@
|
||||
</div>
|
||||
|
||||
<!-- Uptime -->
|
||||
<div class="bg-white rounded-xl border border-surface-200 p-5 shadow-sm hover:shadow-md transition-shadow duration-200">
|
||||
<div class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-5 shadow-sm hover:shadow-md transition-shadow duration-200">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<p class="text-xs font-semibold uppercase tracking-wider text-surface-400">Uptime</p>
|
||||
<div class="w-8 h-8 rounded-lg bg-emerald-50 flex items-center justify-center">
|
||||
<svg class="w-4 h-4 text-emerald-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" /></svg>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-2xl font-bold text-surface-800">{stats?.uptime || "—"}</p>
|
||||
<p class="text-2xl font-bold text-surface-800 dark:text-surface-100">{stats?.uptime || "—"}</p>
|
||||
<p class="text-xs text-surface-400 mt-1 truncate" title={stats?.platform}>{stats?.platform || "—"}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -105,9 +105,9 @@
|
||||
<!-- Services Grid -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<!-- Docker Summary -->
|
||||
<div class="bg-white rounded-xl border border-surface-200 p-5 shadow-sm">
|
||||
<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">
|
||||
<h3 class="text-sm font-semibold text-surface-700">Docker Containers</h3>
|
||||
<h3 class="text-sm font-semibold text-surface-700 dark:text-surface-200">Docker Containers</h3>
|
||||
<span class="text-xs font-medium text-emerald-600 bg-emerald-50 px-2 py-0.5 rounded-full">{containers.filter(c => c.status === "running").length}/{containers.length} running</span>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
@@ -115,7 +115,7 @@
|
||||
<div class="flex items-center justify-between py-1.5 text-sm">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="w-1.5 h-1.5 rounded-full {c.status !== 'running' ? 'bg-surface-300' : c.health === 'unhealthy' ? 'bg-rose-400' : c.health === 'healthy' ? 'bg-emerald-400' : 'bg-sky-400'}"></span>
|
||||
<span class="font-medium text-surface-700">{c.name}</span>
|
||||
<span class="font-medium text-surface-700 dark:text-surface-200">{c.name}</span>
|
||||
</div>
|
||||
<span class="text-xs text-surface-400 truncate max-w-[180px]">{c.image}</span>
|
||||
</div>
|
||||
@@ -127,9 +127,9 @@
|
||||
</div>
|
||||
|
||||
<!-- Repos Summary -->
|
||||
<div class="bg-white rounded-xl border border-surface-200 p-5 shadow-sm">
|
||||
<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">
|
||||
<h3 class="text-sm font-semibold text-surface-700">Git Repositories</h3>
|
||||
<h3 class="text-sm font-semibold text-surface-700 dark:text-surface-200">Git Repositories</h3>
|
||||
<span class="text-xs font-medium text-primary-600 bg-primary-50 px-2 py-0.5 rounded-full">{repos.length} repos</span>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
@@ -137,7 +137,7 @@
|
||||
<div class="flex items-center justify-between py-1.5 text-sm">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-3.5 h-3.5 text-surface-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" /></svg>
|
||||
<span class="font-medium text-surface-700">{r.name}</span>
|
||||
<span class="font-medium text-surface-700 dark:text-surface-200">{r.name}</span>
|
||||
</div>
|
||||
<span class="text-xs text-surface-400">{r.language || "—"}</span>
|
||||
</div>
|
||||
@@ -151,8 +151,8 @@
|
||||
|
||||
<!-- Storage Usage -->
|
||||
{#if stats?.volumes?.length}
|
||||
<div class="bg-white rounded-xl border border-surface-200 p-5 shadow-sm">
|
||||
<h3 class="text-sm font-semibold text-surface-700 mb-3">Storage Usage</h3>
|
||||
<div class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-5 shadow-sm">
|
||||
<h3 class="text-sm font-semibold text-surface-700 dark:text-surface-200 mb-3">Storage Usage</h3>
|
||||
<div class="space-y-3">
|
||||
{#each stats.volumes as vol}
|
||||
<div>
|
||||
@@ -160,7 +160,7 @@
|
||||
<span class="font-medium">{vol.mount}</span>
|
||||
<span>{vol.percent}%</span>
|
||||
</div>
|
||||
<div class="w-full h-3 bg-surface-100 rounded-full overflow-hidden">
|
||||
<div class="w-full h-3 bg-surface-100 dark:bg-surface-700 rounded-full overflow-hidden">
|
||||
<div
|
||||
class="h-full rounded-full transition-all duration-700 ease-out {vol.percent > 90 ? 'bg-gradient-to-r from-rose-400 to-rose-500' : vol.percent > 70 ? 'bg-gradient-to-r from-amber-400 to-amber-500' : 'bg-gradient-to-r from-emerald-400 to-emerald-500'}"
|
||||
style="width: {vol.percent}%"
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<div class="space-y-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-surface-900 tracking-tight">Docker</h1>
|
||||
<h1 class="text-2xl font-bold text-surface-900 dark:text-white tracking-tight">Docker</h1>
|
||||
<p class="text-sm text-surface-400 mt-1">{containers.length} containers · {containers.filter(c => c.status === "running").length} running</p>
|
||||
</div>
|
||||
<button onclick={load} class="text-xs font-medium text-primary-600 bg-primary-50 hover:bg-primary-100 px-3 py-1.5 rounded-lg transition-colors">
|
||||
@@ -47,13 +47,13 @@
|
||||
{#if loading}
|
||||
<div class="space-y-3">
|
||||
{#each Array(5) as _}
|
||||
<div class="h-[72px] rounded-xl bg-surface-100 animate-pulse"></div>
|
||||
<div class="h-[72px] rounded-xl bg-surface-100 dark:bg-surface-800 animate-pulse"></div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="space-y-2">
|
||||
{#each containers as c}
|
||||
<div class="bg-white rounded-xl border border-surface-200 p-4 flex items-center justify-between shadow-sm hover:shadow-md transition-all duration-200 group">
|
||||
<div class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-4 flex items-center justify-between shadow-sm hover:shadow-md transition-all duration-200 group">
|
||||
<div class="flex items-center gap-3 min-w-0">
|
||||
<span class="relative flex h-2.5 w-2.5 shrink-0">
|
||||
{#if c.status === "running"}
|
||||
@@ -64,7 +64,7 @@
|
||||
{/if}
|
||||
</span>
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm font-semibold text-surface-800 truncate">{c.name}</p>
|
||||
<p class="text-sm font-semibold text-surface-800 dark:text-surface-100 truncate">{c.name}</p>
|
||||
<p class="text-xs text-surface-400 truncate mt-0.5">{c.image}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -108,10 +108,10 @@
|
||||
<!-- Log Modal -->
|
||||
{#if logTarget}
|
||||
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm flex items-center justify-center z-50" role="dialog" aria-modal="true" onclick={() => { logTarget = ""; logContent = ""; }} onkeydown={(e) => e.key === "Escape" && (logTarget = "", logContent = "")}>
|
||||
<div class="bg-white rounded-2xl shadow-2xl w-[90vw] max-w-4xl max-h-[80vh] flex flex-col" role="document" onclick={(e) => e.stopPropagation()} onkeydown={(e) => e.stopPropagation()}>
|
||||
<div class="flex items-center justify-between px-5 py-4 border-b border-surface-200">
|
||||
<div class="bg-white dark:bg-surface-800 rounded-2xl shadow-2xl w-[90vw] max-w-4xl max-h-[80vh] flex flex-col" role="document" onclick={(e) => e.stopPropagation()} onkeydown={(e) => e.stopPropagation()}>
|
||||
<div class="flex items-center justify-between px-5 py-4 border-b border-surface-200 dark:border-surface-700">
|
||||
<div>
|
||||
<h3 class="text-sm font-bold text-surface-800">Container Logs</h3>
|
||||
<h3 class="text-sm font-bold text-surface-800 dark:text-surface-100">Container Logs</h3>
|
||||
<p class="text-xs text-surface-400 mt-0.5">{logTarget}</p>
|
||||
</div>
|
||||
<button aria-label="Close logs" class="text-surface-400 hover:text-surface-600 transition-colors" onclick={() => { logTarget = ""; logContent = ""; }}>
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
<div class="space-y-5">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-surface-900 tracking-tight">Files</h1>
|
||||
<h1 class="text-2xl font-bold text-surface-900 dark:text-white tracking-tight">Files</h1>
|
||||
<p class="text-sm text-surface-400 mt-1">/volume1{currentPath ? "/" + currentPath : ""}</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -96,7 +96,7 @@
|
||||
{/each}
|
||||
{#if currentPath}
|
||||
<button
|
||||
class="ml-auto text-xs font-medium text-surface-500 bg-surface-100 hover:bg-surface-200 px-2.5 py-1 rounded-lg transition-colors flex items-center gap-1"
|
||||
class="ml-auto text-xs font-medium text-surface-500 bg-surface-100 dark:bg-surface-700 hover:bg-surface-200 dark:hover:bg-surface-600 px-2.5 py-1 rounded-lg transition-colors flex items-center gap-1"
|
||||
onclick={goUp}
|
||||
>
|
||||
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M5 10l7-7m0 0l7 7m-7-7v18" /></svg>
|
||||
@@ -109,27 +109,27 @@
|
||||
{#if loading}
|
||||
<div class="space-y-1">
|
||||
{#each Array(8) as _}
|
||||
<div class="h-11 rounded-lg bg-surface-100 animate-pulse"></div>
|
||||
<div class="h-11 rounded-lg bg-surface-100 dark:bg-surface-800 animate-pulse"></div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="bg-white rounded-xl border border-surface-200 shadow-sm overflow-hidden">
|
||||
<div class="bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 shadow-sm overflow-hidden">
|
||||
<!-- Header -->
|
||||
<div class="grid grid-cols-[1fr_100px_100px] px-4 py-2 text-[11px] font-semibold uppercase tracking-wider text-surface-400 border-b border-surface-100">
|
||||
<div class="grid grid-cols-[1fr_100px_100px] px-4 py-2 text-[11px] font-semibold uppercase tracking-wider text-surface-400 border-b border-surface-100 dark:border-surface-700">
|
||||
<span>Name</span>
|
||||
<span class="text-right">Size</span>
|
||||
<span class="text-right">Actions</span>
|
||||
</div>
|
||||
<!-- Entries -->
|
||||
{#each entries as e}
|
||||
<div class="grid grid-cols-[1fr_100px_100px] items-center px-4 py-2.5 hover:bg-surface-50 border-b border-surface-100 last:border-0 transition-colors group">
|
||||
<div class="grid grid-cols-[1fr_100px_100px] items-center px-4 py-2.5 hover:bg-surface-50 dark:hover:bg-surface-700 border-b border-surface-100 dark:border-surface-700 last:border-0 transition-colors group">
|
||||
{#if e.is_dir}
|
||||
<button class="flex items-center gap-2.5 text-sm font-medium text-surface-700 hover:text-primary-600 transition-colors text-left truncate" onclick={() => browse(currentPath ? `${currentPath}/${e.name}` : e.name)}>
|
||||
<button class="flex items-center gap-2.5 text-sm font-medium text-surface-700 dark:text-surface-200 hover:text-primary-600 transition-colors text-left truncate" onclick={() => browse(currentPath ? `${currentPath}/${e.name}` : e.name)}>
|
||||
<svg class="w-4 h-4 text-amber-400 shrink-0" fill="currentColor" viewBox="0 0 20 20"><path d="M2 6a2 2 0 012-2h5l2 2h5a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" /></svg>
|
||||
{e.name}
|
||||
</button>
|
||||
{:else}
|
||||
<span class="flex items-center gap-2.5 text-sm text-surface-600 truncate">
|
||||
<span class="flex items-center gap-2.5 text-sm text-surface-600 dark:text-surface-300 truncate">
|
||||
<svg class="w-4 h-4 text-surface-300 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" /></svg>
|
||||
{e.name}
|
||||
</span>
|
||||
|
||||
@@ -41,26 +41,26 @@
|
||||
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-surface-900 tracking-tight">Repositories</h1>
|
||||
<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 animate-pulse"></div>
|
||||
<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 rounded-xl border border-surface-200 p-4 text-left shadow-sm hover:shadow-md hover:border-primary-200 transition-all duration-200 group {selectedRepo === `${r.owner?.login}/${r.name}` ? 'ring-2 ring-primary-500 border-primary-300' : ''}"
|
||||
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 group-hover:text-primary-600 transition-colors truncate">{r.name}</p>
|
||||
<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}
|
||||
@@ -78,10 +78,10 @@
|
||||
|
||||
<!-- Commits Panel -->
|
||||
{#if selectedRepo}
|
||||
<div class="bg-white rounded-xl border border-surface-200 p-5 shadow-sm">
|
||||
<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">Recent Commits</h3>
|
||||
<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
|
||||
@@ -101,7 +101,7 @@
|
||||
{: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' : ''}">
|
||||
<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}
|
||||
@@ -109,12 +109,12 @@
|
||||
{/if}
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="text-sm text-surface-700 truncate">{c.commit?.message?.split("\n")[0]}</p>
|
||||
<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 px-1.5 py-0.5 rounded h-fit shrink-0">{c.sha?.slice(0, 7)}</span>
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user