From 166f039ae697e4ab73f23464f5e4fa58a510ea7c Mon Sep 17 00:00:00 2001 From: josh Date: Fri, 18 Sep 2026 01:09:05 -0400 Subject: [PATCH] Add responsive mobile layouts and navigation --- src/app.html | 2 +- src/lib/ui/components/ArtifactDetail.svelte | 8 +- src/lib/ui/components/BetaPlanBuilder.svelte | 2 +- src/lib/ui/components/BlueprintBuilder.svelte | 11 ++- src/lib/ui/components/LogPanel.svelte | 4 + src/lib/ui/components/PlayerRoster.svelte | 6 ++ src/lib/ui/components/Toaster.svelte | 6 +- .../components/primitives/Breadcrumbs.svelte | 3 + .../ui/components/primitives/Button.svelte | 4 + src/lib/ui/components/primitives/Card.svelte | 4 + .../primitives/SectionHeader.svelte | 3 + .../ui/components/primitives/Select.svelte | 2 + src/lib/ui/components/primitives/Tabs.svelte | 5 ++ src/routes/+layout.svelte | 79 ++++++++++++++++--- src/routes/betas/+page.svelte | 10 ++- src/routes/campaigns/[id]/+page.svelte | 5 ++ src/routes/configs/+page.svelte | 2 +- src/routes/deployments/[id]/+page.svelte | 3 + src/routes/plugins/+page.svelte | 2 +- src/routes/scripts/+page.svelte | 1 + src/routes/servers/[name]/+page.svelte | 11 ++- 21 files changed, 147 insertions(+), 26 deletions(-) diff --git a/src/app.html b/src/app.html index 4ed2044..6ddbf0e 100644 --- a/src/app.html +++ b/src/app.html @@ -3,7 +3,7 @@ - + Electric Cherry %sveltekit.head% diff --git a/src/lib/ui/components/ArtifactDetail.svelte b/src/lib/ui/components/ArtifactDetail.svelte index 1509d54..b8e4536 100644 --- a/src/lib/ui/components/ArtifactDetail.svelte +++ b/src/lib/ui/components/ArtifactDetail.svelte @@ -442,7 +442,7 @@ .kv-grid { display: grid; - grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); gap: var(--space-3); } .kv { @@ -555,7 +555,11 @@ .dlg-actions { display: flex; gap: var(--space-2); justify-content: flex-end; } - @media (max-width: 720px) { + @media (max-width: 1000px) { .version-row { grid-template-columns: 1fr; } } + @media (max-width: 720px) { + .panel-head, .head-actions, .dlg-actions { flex-wrap: wrap; } + .dlg { padding: var(--space-4); } + } diff --git a/src/lib/ui/components/BetaPlanBuilder.svelte b/src/lib/ui/components/BetaPlanBuilder.svelte index e8d68bf..7f76b76 100644 --- a/src/lib/ui/components/BetaPlanBuilder.svelte +++ b/src/lib/ui/components/BetaPlanBuilder.svelte @@ -241,7 +241,7 @@ .editor-fields { display: grid; gap: 12px; padding: 6px 16px 16px; } .fields, .add-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: end; } .add-row label { flex: 1 1 220px; } - label { display: grid; gap: 7px; flex: 1 1 180px; font-size: 12px; color: var(--text-secondary); } + label { display: grid; gap: 7px; flex: 1 1 180px; min-width: 0; font-size: 12px; color: var(--text-secondary); } input, select, button { color: var(--text-primary); background: var(--surface-sunken); border: 1px solid var(--border-strong); border-radius: 6px; padding: 10px 12px; min-width: 0; font: inherit; } input, select { width: 100%; font-size: 13px; min-height: 40px; box-sizing: border-box; } button { cursor: pointer; } diff --git a/src/lib/ui/components/BlueprintBuilder.svelte b/src/lib/ui/components/BlueprintBuilder.svelte index 2ef6d36..89b4a8a 100644 --- a/src/lib/ui/components/BlueprintBuilder.svelte +++ b/src/lib/ui/components/BlueprintBuilder.svelte @@ -99,5 +99,14 @@ .eyebrow { display: block; color: var(--text-secondary); font-size: 10px; text-transform: uppercase; letter-spacing: .12em; margin-bottom: 8px; } h2, h3, p { margin: 0; } h2 { font-size: 25px; letter-spacing: -.03em; } h3 { font-size: 16px; }.muted { color: var(--text-secondary); font-size: 13px; line-height: 1.6; } form, .lineup { display: grid; gap: 18px; }.identity { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } label { display: grid; gap: 7px; font-size: 12px; min-width: 0; } input, select { width: 100%; min-width: 0; box-sizing: border-box; padding: 11px; border: 1px solid var(--border-strong); border-radius: 8px; background: var(--surface-sunken); color: inherit; font: inherit; } .lineup { border-block: 1px solid var(--border-subtle); padding: 20px 0; }.map-row { display: grid; grid-template-columns: 24px 1fr 1.5fr 80px 24px; gap: 12px; align-items: end; padding: 14px; background: var(--surface-sunken); border-radius: 10px; }.number { font-family: var(--font-mono); font-size: 11px; color: var(--text-secondary); align-self: center; }.count { font-size: 12px; padding: 6px 10px; border: 1px solid var(--border-strong); border-radius: 99px; }.close, .remove { background: none; border: 0; color: var(--text-secondary); font-size: 25px; cursor: pointer; }.remove { padding: 7px 0; }.error { color: var(--state-danger); font-size: 13px; }button:disabled { opacity: .5; cursor: default; } - @media (max-width: 620px) { .builder { padding: 20px; }.identity { grid-template-columns: 1fr; }.map-row { grid-template-columns: 1fr 85px 25px; }.number { display: none; }.map-row label:first-of-type { grid-column: 1 / -1; }.actions { align-items: stretch; flex-direction: column; } } + @media (max-width: 620px) { + .builder { padding: 20px; } + header { display: grid; grid-template-columns: minmax(0, 1fr) 44px; align-items: start; } + .close, .remove { min-width: 44px; } + .identity { grid-template-columns: 1fr; } + .map-row { grid-template-columns: minmax(0, 1fr) 44px; } + .number { display: none; } + .map-row label:first-of-type, .map-row label:nth-of-type(2) { grid-column: 1 / -1; } + .actions { align-items: stretch; flex-direction: column; } + } diff --git a/src/lib/ui/components/LogPanel.svelte b/src/lib/ui/components/LogPanel.svelte index ff69f33..e680c94 100644 --- a/src/lib/ui/components/LogPanel.svelte +++ b/src/lib/ui/components/LogPanel.svelte @@ -170,6 +170,7 @@ } .tabs { display: flex; + flex-wrap: wrap; gap: 6px; align-items: center; border-bottom: 1px solid var(--border); @@ -273,4 +274,7 @@ font-size: var(--text-mono-sm); text-align: right; } + @media (max-width: 640px) { + .right { width: 100%; margin-left: 0; flex-wrap: wrap; } + } diff --git a/src/lib/ui/components/PlayerRoster.svelte b/src/lib/ui/components/PlayerRoster.svelte index 4da0a32..647d628 100644 --- a/src/lib/ui/components/PlayerRoster.svelte +++ b/src/lib/ui/components/PlayerRoster.svelte @@ -30,6 +30,8 @@ {:else if !roster || roster.length === 0}
lobby is empty
{:else} + +
@@ -52,9 +54,13 @@ {/each}
+
{/if} diff --git a/src/lib/ui/components/primitives/Breadcrumbs.svelte b/src/lib/ui/components/primitives/Breadcrumbs.svelte index 889e3f5..d2c344a 100644 --- a/src/lib/ui/components/primitives/Breadcrumbs.svelte +++ b/src/lib/ui/components/primitives/Breadcrumbs.svelte @@ -39,6 +39,9 @@ color: var(--text-tertiary); } .crumbs li { + min-width: 0; + max-width: 100%; + overflow-wrap: anywhere; display: inline-flex; align-items: center; gap: var(--space-2); diff --git a/src/lib/ui/components/primitives/Button.svelte b/src/lib/ui/components/primitives/Button.svelte index f8cfbef..1bbe20a 100644 --- a/src/lib/ui/components/primitives/Button.svelte +++ b/src/lib/ui/components/primitives/Button.svelte @@ -72,6 +72,7 @@ diff --git a/src/lib/ui/components/primitives/Card.svelte b/src/lib/ui/components/primitives/Card.svelte index c33f29d..cee1d8f 100644 --- a/src/lib/ui/components/primitives/Card.svelte +++ b/src/lib/ui/components/primitives/Card.svelte @@ -51,6 +51,7 @@ diff --git a/src/lib/ui/components/primitives/SectionHeader.svelte b/src/lib/ui/components/primitives/SectionHeader.svelte index 9f1d5de..c0296b9 100644 --- a/src/lib/ui/components/primitives/SectionHeader.svelte +++ b/src/lib/ui/components/primitives/SectionHeader.svelte @@ -74,12 +74,15 @@ } .actions { display: flex; + flex-wrap: wrap; align-items: center; gap: var(--space-2); flex-shrink: 0; } @media (max-width: 640px) { + .s-lg .title { font-size: var(--text-2xl); } + .s-md .title { font-size: var(--text-xl); } .row { flex-direction: column; align-items: flex-start; gap: var(--space-4); } .actions { width: 100%; } } diff --git a/src/lib/ui/components/primitives/Select.svelte b/src/lib/ui/components/primitives/Select.svelte index c5e52f2..4a3c27b 100644 --- a/src/lib/ui/components/primitives/Select.svelte +++ b/src/lib/ui/components/primitives/Select.svelte @@ -50,6 +50,8 @@ diff --git a/src/routes/campaigns/[id]/+page.svelte b/src/routes/campaigns/[id]/+page.svelte index 68764fc..38e0227 100644 --- a/src/routes/campaigns/[id]/+page.svelte +++ b/src/routes/campaigns/[id]/+page.svelte @@ -376,4 +376,9 @@ color: var(--text-primary); word-break: break-all; } + @media (max-width: 720px) { + .srv-row { align-items: flex-start; flex-direction: column; } + .srv-l, .file-row { flex-wrap: wrap; } + .diff-modal { padding: var(--space-4); max-height: 92dvh; } + } diff --git a/src/routes/configs/+page.svelte b/src/routes/configs/+page.svelte index ca78c27..8703dd2 100644 --- a/src/routes/configs/+page.svelte +++ b/src/routes/configs/+page.svelte @@ -362,7 +362,7 @@ .upload-form .full { grid-column: 1 / -1; } .scope-row { display: flex; gap: var(--space-2); flex-wrap: wrap; } .scope-row :global(.wrap) { flex: 1 1 140px; min-width: 140px; } - .form-actions { grid-column: 1 / -1; display: flex; align-items: center; gap: var(--space-4); } + .form-actions { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4); } .flash { color: var(--state-danger); font-family: var(--font-mono); font-size: var(--text-xs); } .section { display: flex; flex-direction: column; gap: var(--space-3); } diff --git a/src/routes/deployments/[id]/+page.svelte b/src/routes/deployments/[id]/+page.svelte index 37b8dfb..0b68bdf 100644 --- a/src/routes/deployments/[id]/+page.svelte +++ b/src/routes/deployments/[id]/+page.svelte @@ -152,4 +152,7 @@ .timeline li { position: relative; padding: 0 0 24px 12px; overflow-wrap: anywhere; } .timeline li::before { content: ''; position: absolute; left: -24px; top: 5px; width: 10px; height: 10px; border-radius: 50%; background: var(--accent-primary); } .timeline p { margin-top: 6px; } .error { color: var(--state-danger); } .warning { color: var(--state-warning); } + @media (max-width: 640px) { + .timing { flex-direction: column; gap: var(--space-2); } + } diff --git a/src/routes/plugins/+page.svelte b/src/routes/plugins/+page.svelte index 14f467f..88e363d 100644 --- a/src/routes/plugins/+page.svelte +++ b/src/routes/plugins/+page.svelte @@ -249,7 +249,7 @@ .upload-form { display: grid; gap: var(--space-4); grid-template-columns: 1fr 1fr; } .scope-row { display: flex; gap: var(--space-2); flex-wrap: wrap; } .scope-row :global(.wrap) { flex: 1 1 140px; min-width: 140px; } - .form-actions { grid-column: 1 / -1; display: flex; align-items: center; gap: var(--space-4); } + .form-actions { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4); } .flash { color: var(--state-danger); font-family: var(--font-mono); font-size: var(--text-xs); } .section { display: flex; flex-direction: column; gap: var(--space-3); } diff --git a/src/routes/scripts/+page.svelte b/src/routes/scripts/+page.svelte index 61f8b42..ad3cd4d 100644 --- a/src/routes/scripts/+page.svelte +++ b/src/routes/scripts/+page.svelte @@ -316,6 +316,7 @@ .preview.warn { background: rgba(255, 176, 32, 0.06); color: var(--state-warning); border: 1px solid rgba(255, 176, 32, 0.28); } .form-actions { + flex-wrap: wrap; grid-column: 1 / -1; display: flex; align-items: center; diff --git a/src/routes/servers/[name]/+page.svelte b/src/routes/servers/[name]/+page.svelte index 811249f..6096292 100644 --- a/src/routes/servers/[name]/+page.svelte +++ b/src/routes/servers/[name]/+page.svelte @@ -395,6 +395,8 @@ {#if netDiagnosis} {#if netDiagnosis.ok && netDiagnosis.results} + +
@@ -421,6 +423,7 @@ {/each}
+
{#if netDiagnosis.config}
KOMODO_ADDRESS = {netDiagnosis.config.komodoAddress ?? '(unset)'} @@ -607,7 +610,7 @@ /* Diagnostics KV grid */ .diag-grid { display: grid; - grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); gap: var(--space-2); margin-top: var(--space-2); } @@ -714,7 +717,10 @@ } /* Network table */ + .table-scroll { max-width: 100%; overflow-x: auto; } + .table-scroll:focus-visible { box-shadow: var(--focus-ring); } .net-table { + min-width: 600px; width: 100%; margin-top: var(--space-4); border-collapse: separate; @@ -810,7 +816,8 @@ .hist-err { color: var(--state-danger); font-size: var(--text-xs); font-family: var(--font-mono); } @media (max-width: 640px) { - .metrics { grid-template-columns: 1fr 1fr; } + .metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .panel-head, .alert { flex-wrap: wrap; } .hist-row { grid-template-columns: 1fr; gap: var(--space-1);