fix(web): unify display-field spacing (shared Field) + clearer layout help
- Every option in the custom form now renders through one `Field` wrapper (label → control → help at a consistent `space-y-3`), so the label→input gap is roomier and identical across keep-alive, the button groups, and max-displays — the first field no longer spaces differently from the rest. - Reworded the multi-monitor layout help: it now says Auto is side-by-side and Manual gives a per-display X/Y editor "in the Live displays section below once two or more are streaming" — instead of pointing at an "arrangement table" that isn't visible until clients connect. web tsc + vite build + biome-lint green; deployed on .21. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -100,7 +100,7 @@
|
||||
"display_identity_per_client": "Pro Client",
|
||||
"display_identity_per_client_mode": "Pro Client + Auflösung",
|
||||
"display_layout_mode": "Multi-Monitor-Anordnung",
|
||||
"display_layout_help": "Wie mehrere Anzeigen auf dem Desktop angeordnet werden. Manuell nutzt die Anordnungstabelle unten (ab 2 Anzeigen).",
|
||||
"display_layout_help": "Automatisch ordnet die Anzeigen nebeneinander an (links nach rechts). Manuell: Du platzierst jede selbst — ein X/Y-Editor pro Anzeige erscheint im Abschnitt „Aktive Displays“ unten, sobald zwei oder mehr streamen.",
|
||||
"display_layout_auto_row": "Automatisch (nebeneinander)",
|
||||
"display_layout_manual": "Manuell",
|
||||
"clients_title": "Gekoppelte Geräte",
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
"display_identity_per_client": "Per client",
|
||||
"display_identity_per_client_mode": "Per client + resolution",
|
||||
"display_layout_mode": "Multi-monitor layout",
|
||||
"display_layout_help": "How several displays are arranged on the desktop. Manual uses the arrangement table below (with 2+ displays).",
|
||||
"display_layout_help": "Auto lays displays out side by side, left to right. Manual: you position each one yourself — a per-display X/Y editor appears in the Live displays section below once two or more are streaming.",
|
||||
"display_layout_auto_row": "Auto (side by side)",
|
||||
"display_layout_manual": "Manual",
|
||||
"clients_title": "Paired clients",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { Button } from "@unom/ui/button";
|
||||
import { type FC, useEffect, useState } from "react";
|
||||
import { type FC, type ReactNode, useEffect, useState } from "react";
|
||||
import {
|
||||
getGetDisplayStateQueryKey,
|
||||
getGetDisplaySettingsQueryKey,
|
||||
@@ -210,8 +210,7 @@ const DisplayForm: FC<{
|
||||
{/* Custom: every option by hand */}
|
||||
{isCustom && (
|
||||
<div className="space-y-6 rounded-lg border p-5">
|
||||
<div className="space-y-2.5">
|
||||
<Label>{m.display_keep_alive()}</Label>
|
||||
<Field label={m.display_keep_alive()} help={m.display_keep_alive_help()}>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
@@ -251,8 +250,7 @@ const DisplayForm: FC<{
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">{m.display_keep_alive_help()}</p>
|
||||
</div>
|
||||
</Field>
|
||||
|
||||
<Choice
|
||||
label={m.display_topology()}
|
||||
@@ -296,10 +294,8 @@ const DisplayForm: FC<{
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="space-y-2.5">
|
||||
<Label htmlFor="disp-max">{m.display_max()}</Label>
|
||||
<Field label={m.display_max()}>
|
||||
<Input
|
||||
id="disp-max"
|
||||
type="number"
|
||||
min={1}
|
||||
max={16}
|
||||
@@ -313,7 +309,7 @@ const DisplayForm: FC<{
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</Field>
|
||||
|
||||
<div className="border-t pt-4">
|
||||
<Button onClick={() => apply(draft)} disabled={busy}>
|
||||
@@ -340,7 +336,21 @@ const DisplayForm: FC<{
|
||||
);
|
||||
};
|
||||
|
||||
/** A labeled row of mutually-exclusive option buttons (topology / conflict / identity / layout). */
|
||||
/** A labeled config field — label, then the control, then optional help. The single source of the
|
||||
* label→control→help spacing so every field (keep-alive, the button groups, max-displays) lines up. */
|
||||
const Field: FC<{ label: string; help?: string; children: ReactNode }> = ({
|
||||
label,
|
||||
help,
|
||||
children,
|
||||
}) => (
|
||||
<div className="space-y-3">
|
||||
<Label className="block">{label}</Label>
|
||||
{children}
|
||||
{help && <p className="text-xs text-muted-foreground">{help}</p>}
|
||||
</div>
|
||||
);
|
||||
|
||||
/** A [`Field`] whose control is a row of mutually-exclusive option buttons (topology / conflict / …). */
|
||||
const Choice: FC<{
|
||||
label: string;
|
||||
help?: string;
|
||||
@@ -350,8 +360,7 @@ const Choice: FC<{
|
||||
disabled: boolean;
|
||||
onPick: (v: string) => void;
|
||||
}> = ({ label, help, value, options, labels, disabled, onPick }) => (
|
||||
<div className="space-y-2.5">
|
||||
<Label>{label}</Label>
|
||||
<Field label={label} help={help}>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{options.map((o) => (
|
||||
<Button
|
||||
@@ -365,8 +374,7 @@ const Choice: FC<{
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
{help && <p className="text-xs text-muted-foreground">{help}</p>}
|
||||
</div>
|
||||
</Field>
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user