From 46c43b95c27895be6d2697330cef1c9ac0e75e4d Mon Sep 17 00:00:00 2001 From: pptx704 Date: Sun, 12 Apr 2026 02:44:40 +0600 Subject: [PATCH] Visual polish --- frontend/src/routes/admin/hosts/+page.svelte | 255 ++++++++++++------- 1 file changed, 170 insertions(+), 85 deletions(-) diff --git a/frontend/src/routes/admin/hosts/+page.svelte b/frontend/src/routes/admin/hosts/+page.svelte index 16c7476..362b9ff 100644 --- a/frontend/src/routes/admin/hosts/+page.svelte +++ b/frontend/src/routes/admin/hosts/+page.svelte @@ -168,45 +168,48 @@
-
-
+
+ +
+ +
-

+

Hosts

-

+

Platform and BYOC compute across all teams.

{#if activeTab === 'platform'} {/if}
- + {#if !loading && !error} -
-
- {totalCount} +
+
+ {totalCount} total
-
- - - +
+ + + - {onlineCount} + {onlineCount} online
{#if pendingCount > 0} -
- {pendingCount} +
+ {pendingCount} pending
{/if} @@ -214,30 +217,32 @@ {/if}
- -
+ +
{#each [['platform', 'Platform', platformHosts.length], ['byoc', 'BYOC', byocHosts.length]] as [id, label, count] (id)} {/each}
-
+
{#if loading} {@render skeletonRows()} {:else if error} @@ -251,16 +256,16 @@ {#if byocHosts.length === 0} {@render emptyState('byoc')} {:else} -
+
{#each byocGroups as group (group.teamId ?? '__none__')} {@const groupPageHosts = byocPageHosts.filter(h => h.team_id === group.teamId || (group.teamId === null && !h.team_id))} {#if groupPageHosts.length > 0}
-
+
{group.teamName} - + {group.hosts.length}
@@ -271,22 +276,22 @@ {#if byocPageCount > 1} -
+
- Page {byocPage + 1} of {byocPageCount} · {byocHosts.length} hosts + Page {byocPage + 1} of {byocPageCount} · {byocHosts.length} hosts
@@ -301,34 +306,34 @@
{#snippet skeletonRows()} -
+
- - - - - - + + + + + + {#each Array(5) as _, i} - - + - - - - @@ -342,26 +347,28 @@ {#if hosts.length === 0} {@render emptyState('platform')} {:else} -
+
HostStatus
HostStatus
+
+
+
- - - - - - + + + + + + - {#each hosts as host (host.id)} + {#each hosts as host, i (host.id)} - - - - -
HostStatus
HostStatus
-
{host.id}
+
+
{host.id}
{#if host.address}
{host.address}
{/if} @@ -371,31 +378,31 @@ {/if}
- + + {#if host.status === 'online'} - - - + + + {:else} - + {/if} {host.status} + @@ -409,18 +416,31 @@ {/snippet} {#snippet emptyState(type: 'platform' | 'byoc')} -
-
- +
+ +
+
+
+ +
-

- {type === 'platform' ? 'No platform hosts yet.' : 'No BYOC hosts across any team.'} +

+ {type === 'platform' ? 'No platform hosts yet' : 'No BYOC hosts across any team'}

-

+

{type === 'platform' ? 'Add a host to start scheduling capsules onto your own compute.' : 'Teams that register their own compute will appear here.'}

+ {#if type === 'platform'} + + {/if}
{/snippet} @@ -435,10 +455,14 @@ onkeydown={(e) => { if (e.key === 'Escape' && !creating) showCreate = false; }} >
-

+ +
+ +
+

Add Platform Host

@@ -491,7 +515,7 @@

+

{/if} @@ -510,11 +535,15 @@
+ +
+ +
-
+
-

+

Host registered

@@ -558,11 +587,12 @@

+
{/if} @@ -578,10 +608,14 @@ onkeydown={(e) => { if (e.key === 'Escape' && !deleting) deleteTarget = null; }} >
-

+ +
+ +
+

Delete Host

@@ -621,7 +655,7 @@

+

{/if} @@ -676,4 +711,54 @@ .checkmark-drawn { stroke-dashoffset: 0; } + + /* Stat pill — shared base */ + .stat-pill { + display: flex; + align-items: baseline; + gap: 6px; + border-radius: var(--radius-button); + border-width: 1px; + padding: 6px 12px; + transition: transform 0.15s ease, box-shadow 0.15s ease; + } + .stat-pill:hover { + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25); + } + + /* Table header */ + .table-header { + padding: 10px 20px; + text-align: left; + font-size: var(--text-label); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--color-text-tertiary); + } + + /* Staggered row entrance */ + .table-row-animate { + animation: fadeUp 0.25s ease both; + } + + /* Tab button */ + .tab-button { + position: relative; + padding: 14px 20px 14px 0; + font-size: var(--text-ui); + transition: color 0.15s ease; + cursor: pointer; + } + + /* Online host row — subtle left accent */ + .host-row-online { + box-shadow: inset 3px 0 0 var(--color-accent); + } + + /* Empty state icon float */ + .empty-icon-float { + animation: iconFloat 3s ease-in-out infinite; + }