feat: unified THE FORGE // SECTION headers and merged proxy routes
Build / build (push) Successful in 10m37s

UI consistency
- ForgeHero now supports backHref, mono kicker, stats snippet, staggered
  entrance animation, and a registration-tick divider
- Every route now opens with the same "THE FORGE // SECTION" eyebrow: projects,
  sites, stacks, proxies, events, dns, deploy, settings, stale containers,
  site/project detail + env/volumes/browse, new site wizard
- Stacks list/detail/new moved to the shared hero and brand-anchor eyebrow
- Toolbars migrated from bespoke buttons to the shared .forge-btn utilities
- Sidebar footline adds a live UTC "forge clock" and a vim-style g-prefix
  quick-nav hint (g d/p/s/k/x/r/e/c jumps to each section)

Proxies page
- Server-side: merge static site proxy routes with instance routes and sort
  by domain (internal/api/proxies.go, internal/store/static_sites.go)
- ProxyRoute gains a Source field ("instance" | "static_site")
- Frontend adds source filter tabs and per-source labels/badges
This commit is contained in:
2026-04-22 16:27:55 +03:00
parent 0fd92fdfa3
commit ef0669d5dd
25 changed files with 702 additions and 277 deletions
+14 -8
View File
@@ -5,6 +5,7 @@
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
import EmptyState from '$lib/components/EmptyState.svelte';
import SkeletonCard from '$lib/components/SkeletonCard.svelte';
import ForgeHero from '$lib/components/ForgeHero.svelte';
import { IconTrash, IconLoader } from '$lib/components/icons';
import { toasts } from '$lib/stores/toast';
import { t } from '$lib/i18n';
@@ -75,22 +76,27 @@
</svelte:head>
<div class="space-y-6">
<!-- Header -->
<div class="flex items-center justify-between">
<h1 class="text-2xl font-bold text-[var(--text-primary)]">{$t('stale.title')}</h1>
{#snippet heroToolbar()}
{#if containers.length > 0}
<button
type="button"
disabled={bulkCleaning}
onclick={() => { confirmBulk = true; }}
class="inline-flex items-center gap-2 rounded-lg border border-[var(--color-danger)] px-4 py-2.5 text-sm font-medium text-[var(--color-danger)] transition-colors hover:bg-[var(--color-danger-light)] disabled:opacity-50 active:animate-press"
class="forge-btn-ghost forge-btn-danger"
>
{#if bulkCleaning}<IconLoader size={16} />{/if}
<IconTrash size={16} />
{$t('stale.cleanupAll')}
{#if bulkCleaning}<IconLoader size={14} />{/if}
<IconTrash size={14} />
<span>{$t('stale.cleanupAll')}</span>
</button>
{/if}
</div>
{/snippet}
<ForgeHero
backHref="/"
eyebrowSuffix="STALE"
title={$t('stale.title')}
size="lg"
toolbar={heroToolbar}
/>
<!-- Content -->
{#if loading}