mirror of
https://github.com/Corfirean/coa-server-manager.git
synced 2026-11-11 03:51:01 +00:00
Keep window density stable and group update and launch actions
This commit is contained in:
1 parent
5525325160
commit
733d73ef76
8 files changed
+47
-31
No files matched your search
@@ -0,0 +1,7 @@
|
||||
---
|
||||
area: manager
|
||||
type: changed
|
||||
audience: admins
|
||||
title: Update and launch without updating share a divided button
|
||||
---
|
||||
Server and game client actions each use two adjacent segments of equal height. Both actions remain visible and keep their own availability checks.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
area: manager
|
||||
type: fixed
|
||||
audience: admins
|
||||
title: Maximizing the window keeps text and controls at a comfortable size
|
||||
---
|
||||
The interface no longer enlarges with window width. System display scaling and browser zoom still work, and large action buttons use more compact spacing.
|
||||
@@ -15,7 +15,7 @@ const buttonVariants = cva(
|
||||
size: {
|
||||
sm: "h-9 px-3 text-sm",
|
||||
md: "h-11 px-5 text-[15px]",
|
||||
xl: "h-16 px-10 text-lg tracking-wide",
|
||||
xl: "h-12 px-6 text-base",
|
||||
},
|
||||
},
|
||||
defaultVariants: { variant: "secondary", size: "md" },
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Button, type ButtonProps } from "./button";
|
||||
|
||||
/** Two explicit actions, each with its own enabled state and keyboard focus. */
|
||||
export function SplitButton({ label, primary, secondary }: {
|
||||
label: string;
|
||||
primary: ButtonProps;
|
||||
secondary: ButtonProps;
|
||||
}) {
|
||||
return <div role="group" aria-label={label} className="inline-flex max-w-full items-stretch rounded-md">
|
||||
<Button type="button" variant="primary" {...primary}
|
||||
className="h-auto min-h-12 min-w-0 rounded-r-none px-5 py-2 text-sm whitespace-normal" />
|
||||
<Button type="button" variant="secondary" {...secondary}
|
||||
className="h-auto min-h-12 min-w-0 rounded-l-none border-l border-l-gold/30 px-4 py-2 text-sm whitespace-normal" />
|
||||
</div>;
|
||||
}
|
||||
+3
-3
@@ -16,10 +16,10 @@
|
||||
--font-sans: "Segoe UI Variable Text", "Segoe UI", "Microsoft YaHei UI", "Microsoft YaHei", system-ui, sans-serif;
|
||||
}
|
||||
|
||||
/* Everything is sized in rem, so scaling the root font grows the whole interface with the window
|
||||
(16px up to about 1280px wide, then gradually larger; capped at 26px). */
|
||||
/* Window size changes layout, not UI density. Keep rem tied to the user's default
|
||||
font size; browser zoom and operating-system display scaling still apply. */
|
||||
html {
|
||||
font-size: clamp(16px, calc(0.75vw + 6.4px), 26px);
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
html,
|
||||
|
||||
+12
-26
@@ -15,6 +15,7 @@ import { PublishRealmDialog } from "@/screens/PublishDialog";
|
||||
import { useRegistryStatus } from "@/lib/registry";
|
||||
import { usePublishRealms, type PublishRealm } from "@/lib/publishRealms";
|
||||
import { useAutoRestart } from "@/lib/autoRestartPrefs";
|
||||
import { SplitButton } from "@/components/ui/split-button";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card } from "@/components/ui/card";
|
||||
|
||||
@@ -410,32 +411,21 @@ export function Overview({ server, companions = true, onForget, onOpenUpdates, o
|
||||
|
||||
<div className="mt-7 flex flex-wrap items-center gap-x-4 gap-y-3">
|
||||
{running ? (
|
||||
<Button variant="secondary" size="xl" disabled={transitioning} onClick={() => run("stopping")} className="min-w-56">
|
||||
<Button variant="secondary" size="xl" disabled={transitioning} onClick={() => run("stopping")} className="min-w-40">
|
||||
{transitioning && <Loader2 className="h-5 w-5 animate-spin" aria-hidden />}
|
||||
{t("btn.stop")}
|
||||
</Button>
|
||||
) : upd.available ? (
|
||||
<Button
|
||||
variant="primary"
|
||||
size="xl"
|
||||
disabled={transitioning || upd.applying}
|
||||
onClick={() => (needsDecision ? onOpenUpdates() : void runServerUpdate())}
|
||||
className="min-w-56"
|
||||
>
|
||||
{upd.applying && <Loader2 className="h-5 w-5 animate-spin" aria-hidden />}
|
||||
{upd.applying ? t("btn.updating") : needsDecision ? t("overview.openUpdates") : t("btn.update")}
|
||||
</Button>
|
||||
<SplitButton label={t("overview.server")}
|
||||
primary={{ disabled: transitioning || upd.applying, onClick: () => (needsDecision ? onOpenUpdates() : void runServerUpdate()), children: <>{upd.applying && <Loader2 className="h-4 w-4 animate-spin" aria-hidden />}{upd.applying ? t("btn.updating") : needsDecision ? t("overview.openUpdates") : t("btn.update")}</> }}
|
||||
secondary={{ disabled: transitioning || upd.applying, onClick: () => run("starting"), children: t("btn.startWithoutUpdate") }}
|
||||
/>
|
||||
) : (
|
||||
<Button variant="primary" size="xl" disabled={transitioning} onClick={() => run("starting")} className="min-w-56">
|
||||
<Button variant="primary" size="xl" disabled={transitioning} onClick={() => run("starting")} className="min-w-40">
|
||||
{transitioning && <Loader2 className="h-5 w-5 animate-spin" aria-hidden />}
|
||||
{transitioning ? (action === "stopping" ? t("btn.stoppingCaps") : t("btn.startingCaps")) : t("btn.start")}
|
||||
</Button>
|
||||
)}
|
||||
{!running && upd.available && (
|
||||
<Button variant="secondary" size="sm" disabled={transitioning || upd.applying} onClick={() => run("starting")}>
|
||||
{t("btn.startWithoutUpdate")}
|
||||
</Button>
|
||||
)}
|
||||
{running && (
|
||||
<Button variant="ghost" size="sm" disabled={transitioning || upd.applying} onClick={() => run("restarting")}>
|
||||
{t("btn.restart")}
|
||||
@@ -456,7 +446,7 @@ export function Overview({ server, companions = true, onForget, onOpenUpdates, o
|
||||
{client && <RealmlistMenu serverId={server.id} />}
|
||||
{client && jobBusy ? (
|
||||
<div
|
||||
className="relative flex h-16 min-w-64 items-center overflow-hidden rounded-md border border-gold/50 bg-card-2"
|
||||
className="relative flex h-12 min-w-64 items-center overflow-hidden rounded-md border border-gold/50 bg-card-2"
|
||||
role="progressbar"
|
||||
aria-valuenow={jobPct}
|
||||
aria-valuemin={0}
|
||||
@@ -482,9 +472,10 @@ export function Overview({ server, companions = true, onForget, onOpenUpdates, o
|
||||
</button>
|
||||
</div>
|
||||
) : client && (clientStatus?.update_available || job.phase === "choose") ? (
|
||||
<Button variant="primary" size="xl" disabled={playing || job.phase === "choose"} onClick={() => void startClientUpdate(server.id)} className="min-w-40">
|
||||
{t("btn.updateClient")}
|
||||
</Button>
|
||||
<SplitButton label={t("btn.play")}
|
||||
primary={{ disabled: playing || job.phase === "choose", onClick: () => void startClientUpdate(server.id), children: t("btn.updateClient") }}
|
||||
secondary={{ disabled: realmBusy || playing || upd.applying, onClick: () => void play(), children: <>{playing && <Loader2 className="h-4 w-4 animate-spin" aria-hidden />}{t("btn.playWithoutUpdate")}</> }}
|
||||
/>
|
||||
) : client ? (
|
||||
<Button variant="primary" size="xl" disabled={realmBusy || playing} onClick={() => void play()} className="min-w-40">
|
||||
{playing && <Loader2 className="h-5 w-5 animate-spin" aria-hidden />}
|
||||
@@ -495,11 +486,6 @@ export function Overview({ server, companions = true, onForget, onOpenUpdates, o
|
||||
{t("btn.setupClient")}
|
||||
</Button>
|
||||
) : null}
|
||||
{client && !jobBusy && (clientStatus?.update_available || job.phase === "choose") && (
|
||||
<Button variant="secondary" size="sm" disabled={realmBusy || playing || upd.applying} onClick={() => void play()}>
|
||||
{t("btn.playWithoutUpdate")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 flex flex-wrap items-center justify-between gap-3 border-t border-line/60 pt-4 text-xs text-muted">
|
||||
|
||||
@@ -92,7 +92,7 @@ export function RealmlistMenu({ serverId, className }: { serverId: string; class
|
||||
onClick={() => setOpen((v) => !v)}
|
||||
aria-haspopup="menu"
|
||||
aria-expanded={open}
|
||||
className="flex h-16 cursor-pointer items-center gap-3 rounded-md border border-line bg-card-2 px-4 text-left transition-colors hover:border-gold/50"
|
||||
className="flex h-12 cursor-pointer items-center gap-3 rounded-md border border-line bg-card-2 px-4 text-left transition-colors hover:border-gold/50"
|
||||
>
|
||||
<span>
|
||||
<span className="block text-[11px] uppercase tracking-wide text-muted">{t("realm.label")}</span>
|
||||
|
||||
@@ -28,6 +28,7 @@ const bundle = await rolldown({
|
||||
external: (id, importer) => id === "react/jsx-runtime" || id === "lucide-react" || (id === "react" && !importer?.endsWith("Overview.tsx")),
|
||||
plugins: [{ name: "overview-test",
|
||||
resolveId(id, importer) {
|
||||
if (id === "@/components/ui/split-button") return fileURLToPath(new URL("../src/components/ui/split-button.tsx", import.meta.url));
|
||||
if (id.startsWith("@/") || (id === "react" && importer?.endsWith("Overview.tsx"))) return "\0" + id;
|
||||
},
|
||||
load(id) {
|
||||
|
||||
Reference in new issue
Block a user