Adopt shared WebUI layout primitives

This commit is contained in:
2026-08-18 10:42:51 +02:00
parent b6f939eaba
commit a6e10fd120
6 changed files with 47 additions and 64 deletions
@@ -6,7 +6,7 @@ import {
type FormEvent,
} from "react";
import { ArrowRightLeft, ListChecks, RefreshCw, Trash2 } from "lucide-react";
import {
import { FormGrid, DialogForm,
ActionBlockerHint,
Button,
ColorPickerField,
@@ -372,7 +372,7 @@ export function CalendarCollectionDialog({
</>
}>
<form id={formId} className="calendar-dialog-form" onSubmit={submit}>
<DialogForm id={formId} className="calendar-dialog-form" onSubmit={submit}>
<div className="calendar-dialog-documentation">
<DocumentationHelpLink reference={CALENDAR_SOURCE_DOCUMENTATION} />
</div>
@@ -443,7 +443,7 @@ export function CalendarCollectionDialog({
</span>
}
</div>
<div className="calendar-caldav-setup">
<FormGrid columns={2} gap="small" collapseAt="narrow" className="calendar-caldav-setup">
<label className="calendar-dialog-wide">
<span>{calendarSourceUrlLabel(sourceMode)}</span>
<input
@@ -532,7 +532,7 @@ export function CalendarCollectionDialog({
}
{effectiveCollectionUrl && <span>{effectiveCollectionUrl}</span>}
</div>
</div>
</FormGrid>
{discoveryError && <p className="calendar-form-error">{discoveryError}</p>}
{calendarSourceUsesCalDav(sourceMode) && discoveredCalendars.length > 0 &&
<label>
@@ -548,13 +548,13 @@ export function CalendarCollectionDialog({
}
<details className="calendar-advanced-settings">
<summary>i18n:govoplan-calendar.advanced.4d064726</summary>
<div className="calendar-dialog-grid-two">
<FormGrid columns={2} gap="small" collapseAt="narrow">
<label>
<span>i18n:govoplan-calendar.display_name.c7874aaa</span>
<input value={displayName} onChange={(item) => setDisplayName(item.target.value)} maxLength={255} disabled={saving || !canEditMutableSourceSettings} />
</label>
</div>
<div className="calendar-sync-settings">
</FormGrid>
<FormGrid columns={2} gap="small" collapseAt="narrow">
<ToggleSwitch label="i18n:govoplan-calendar.automatic_sync.084644b2" checked={syncEnabled} disabled={saving || !canEditMutableSourceSettings} onChange={setSyncEnabled} />
<label>
<span>i18n:govoplan-calendar.interval.011efcd5</span>
@@ -574,7 +574,7 @@ export function CalendarCollectionDialog({
<option value="overwrite">i18n:govoplan-calendar.overwrite_remote.39625e32</option>
</select>
</label>
</div>
</FormGrid>
</details>
{source &&
<div className="calendar-sync-status-panel">
@@ -614,7 +614,7 @@ export function CalendarCollectionDialog({
{needsSourceSecret && <p className="calendar-form-note">i18n:govoplan-calendar.enter_a_password_or_token_for_this_source.74c09a54</p>}
</section>
}
</form>
</DialogForm>
</Dialog>);
}
@@ -4,7 +4,7 @@ import {
type FormEvent,
} from "react";
import { Trash2 } from "lucide-react";
import {
import { FormGrid, DialogForm,
ActionBlockerHint,
Button,
ConfirmDialog,
@@ -301,7 +301,7 @@ export function CalendarEventDialog({
</>
}>
<form id={formId} className="calendar-dialog-form" onSubmit={submit}>
<DialogForm id={formId} className="calendar-dialog-form" onSubmit={submit}>
<div className="calendar-dialog-documentation">
<DocumentationHelpLink reference={CALENDAR_DOCUMENTATION} />
</div>
@@ -398,7 +398,7 @@ export function CalendarEventDialog({
<summary>i18n:govoplan-calendar.vevent.9cf5be75</summary>
<section className="calendar-vevent-section">
<h3>i18n:govoplan-calendar.identity.7e5a975b</h3>
<div className="calendar-dialog-grid-three">
<FormGrid columns={3} gap="small" collapseAt="narrow">
<label>
<span>i18n:govoplan-calendar.uid.d946adf5</span>
<input value={uid} onChange={(item) => setUid(item.target.value)} maxLength={255} disabled={saving || !canWrite || Boolean(event)} />
@@ -411,11 +411,11 @@ export function CalendarEventDialog({
<span>i18n:govoplan-calendar.sequence.5c8f4e0e</span>
<input type="number" min={0} step={1} value={sequence} onChange={(item) => setSequence(item.target.value)} disabled={saving || !canWrite} />
</label>
</div>
</FormGrid>
</section>
<section className="calendar-vevent-section">
<h3>i18n:govoplan-calendar.state.a7250206</h3>
<div className="calendar-dialog-grid-three">
<FormGrid columns={3} gap="small" collapseAt="narrow">
<label>
<span>i18n:govoplan-calendar.status.bae7d5be</span>
<select value={status} onChange={(item) => setStatus(item.target.value)} disabled={saving || !canWrite}>
@@ -447,11 +447,11 @@ export function CalendarEventDialog({
<span>i18n:govoplan-calendar.categories.6ccb6007</span>
<input value={categoriesText} onChange={(item) => setCategoriesText(item.target.value)} disabled={saving || !canWrite} />
</label>
</div>
</FormGrid>
</section>
<section className="calendar-vevent-section">
<h3>i18n:govoplan-calendar.participants.cd56e083</h3>
<div className="calendar-dialog-grid-two">
<FormGrid columns={2} gap="small" collapseAt="narrow">
<label>
<span>i18n:govoplan-calendar.organizer_json.3add6f9f</span>
<textarea value={organizerJson} onChange={(item) => setOrganizerJson(item.target.value)} rows={5} disabled={saving || !canWrite} />
@@ -460,7 +460,7 @@ export function CalendarEventDialog({
<span>i18n:govoplan-calendar.attendees_json.aeb487bb</span>
<textarea value={attendeesJson} onChange={(item) => setAttendeesJson(item.target.value)} rows={5} disabled={saving || !canWrite} />
</label>
</div>
</FormGrid>
</section>
<section className="calendar-vevent-section">
<h3>i18n:govoplan-calendar.recurrence.f7ad40f5</h3>
@@ -468,7 +468,7 @@ export function CalendarEventDialog({
<span>i18n:govoplan-calendar.rrule.c7b2f8a3</span>
<input value={rruleText} onChange={(item) => setRruleText(item.target.value)} disabled={saving || !canWrite} />
</label>
<div className="calendar-dialog-grid-two">
<FormGrid columns={2} gap="small" collapseAt="narrow">
<label>
<span>i18n:govoplan-calendar.rdate_json.5b51fca4</span>
<textarea value={rdateJson} onChange={(item) => setRdateJson(item.target.value)} rows={5} disabled={saving || !canWrite} />
@@ -477,11 +477,11 @@ export function CalendarEventDialog({
<span>i18n:govoplan-calendar.exdate_json.7d0c538d</span>
<textarea value={exdateJson} onChange={(item) => setExdateJson(item.target.value)} rows={5} disabled={saving || !canWrite} />
</label>
</div>
</FormGrid>
</section>
<section className="calendar-vevent-section">
<h3>i18n:govoplan-calendar.related.917df91e</h3>
<div className="calendar-dialog-grid-three">
<FormGrid columns={3} gap="small" collapseAt="narrow">
<label>
<span>i18n:govoplan-calendar.reminders_json.ca25e08f</span>
<textarea value={remindersJson} onChange={(item) => setRemindersJson(item.target.value)} rows={5} disabled={saving || !canWrite} />
@@ -494,11 +494,11 @@ export function CalendarEventDialog({
<span>i18n:govoplan-calendar.related_to_json.2d4e8f59</span>
<textarea value={relatedToJson} onChange={(item) => setRelatedToJson(item.target.value)} rows={5} disabled={saving || !canWrite} />
</label>
</div>
</FormGrid>
</section>
<section className="calendar-vevent-section">
<h3>i18n:govoplan-calendar.source.6da13add</h3>
<div className="calendar-dialog-grid-three">
<FormGrid columns={3} gap="small" collapseAt="narrow">
<label>
<span>i18n:govoplan-calendar.source_kind.7eda9bc4</span>
<input value={sourceKind} onChange={(item) => setSourceKind(item.target.value)} maxLength={30} disabled={saving || !canWrite} />
@@ -511,11 +511,11 @@ export function CalendarEventDialog({
<span>i18n:govoplan-calendar.etag.11d00f6e</span>
<input value={etag} onChange={(item) => setEtag(item.target.value)} maxLength={255} disabled={saving || !canWrite} />
</label>
</div>
</FormGrid>
</section>
<section className="calendar-vevent-section">
<h3>i18n:govoplan-calendar.raw.da433cd4</h3>
<div className="calendar-dialog-grid-two">
<FormGrid columns={2} gap="small" collapseAt="narrow">
<label>
<span>i18n:govoplan-calendar.icalendar_json.fb6cc33e</span>
<textarea value={icalendarJson} onChange={(item) => setICalendarJson(item.target.value)} rows={8} disabled={saving || !canWrite} />
@@ -524,10 +524,10 @@ export function CalendarEventDialog({
<span>i18n:govoplan-calendar.metadata_json.b0e4c283</span>
<textarea value={metadataJson} onChange={(item) => setMetadataJson(item.target.value)} rows={8} disabled={saving || !canWrite} />
</label>
</div>
</FormGrid>
</section>
</details>
</form>
</DialogForm>
</Dialog>
<ConfirmDialog
open={Boolean(event && confirmingDelete)}
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import { RefreshCw, RotateCcw, ScanSearch, Trash2 } from "lucide-react";
import {
import { ActionToolbar,
ActionBlockerHint,
Button,
ConfirmDialog,
@@ -113,7 +113,7 @@ export function CalendarOutboxDialog({
<p className="calendar-outbox-calendar-name">{calendar.name}</p>
<DocumentationHelpLink reference={CALENDAR_RECOVERY_DOCUMENTATION} />
{error && <DismissibleAlert tone="danger" resetKey={error}>{error}</DismissibleAlert>}
<div className="calendar-outbox-toolbar">
<ActionToolbar className="calendar-outbox-toolbar">
<SegmentedControl<OutboxFilter>
value={filter}
ariaLabel="i18n:govoplan-calendar.outbox_filter.8305af40"
@@ -128,7 +128,7 @@ export function CalendarOutboxDialog({
<div><dt>i18n:govoplan-calendar.conflicts_dead.31252c3a</dt><dd>{conflictCount}</dd></div>
<div><dt>i18n:govoplan-calendar.shown.498e85a1</dt><dd>{visibleOperations.length}</dd></div>
</dl>
</div>
</ActionToolbar>
{loading && !operations.length
? <p className="calendar-form-note">i18n:govoplan-calendar.loading_outbound_changes.3fc59656</p>
: visibleOperations.length
+9 -9
View File
@@ -8,7 +8,7 @@ import {
type WheelEvent as ReactWheelEvent } from
"react";
import { CalendarDays, ChevronLeft, ChevronRight, Pencil, Plus, RefreshCw } from "lucide-react";
import {
import { ToolbarGroup, ActionToolbar,
AdminIconButton,
Button,
DismissibleAlert,
@@ -854,8 +854,8 @@ export default function CalendarPage({ settings, auth }: {settings: ApiSettings;
</aside>
<section className="calendar-main-panel" aria-label="i18n:govoplan-calendar.calendar.adab5090">
<div className="calendar-view-toolbar" aria-label="i18n:govoplan-calendar.calendar_controls.974f4fa1">
<div className="calendar-toolbar-left">
<ActionToolbar className="calendar-view-toolbar" aria-label="i18n:govoplan-calendar.calendar_controls.974f4fa1">
<ToolbarGroup grow className="calendar-toolbar-left">
<SegmentedControl
className="calendar-mode-switch"
size="equal"
@@ -870,9 +870,9 @@ export default function CalendarPage({ settings, auth }: {settings: ApiSettings;
}}
options={modeOptions}
/>
</div>
</ToolbarGroup>
<div className="calendar-toolbar-center">
<ToolbarGroup align="center" className="calendar-toolbar-center">
<div className="calendar-icon-group" aria-label="i18n:govoplan-calendar.calendar_navigation.7ba43cd2">
<AdminIconButton
label="i18n:govoplan-calendar.previous.50f94286"
@@ -892,9 +892,9 @@ export default function CalendarPage({ settings, auth }: {settings: ApiSettings;
<strong>{heading}</strong>
</div>
</div>
</div>
</ToolbarGroup>
<div className="calendar-toolbar-right">
<ToolbarGroup align="end" className="calendar-toolbar-right">
<DocumentationHelpLink reference={CALENDAR_DOCUMENTATION} />
<AdminIconButton
label="i18n:govoplan-calendar.refresh.56e3badc"
@@ -906,8 +906,8 @@ export default function CalendarPage({ settings, auth }: {settings: ApiSettings;
<Plus size={17} /> i18n:govoplan-calendar.new.6403f2b7
</Button>
}
</div>
</div>
</ToolbarGroup>
</ActionToolbar>
<div className={`calendar-view-shell is-${mode}`}>
{mode === "continuous" ?
@@ -1,6 +1,6 @@
import { useEffect, useMemo, useState } from "react";
import { Save } from "lucide-react";
import {
import { FormGrid, ContentGrid,
Button,
Card,
DismissibleAlert,
@@ -124,12 +124,12 @@ export default function CalendarSettingsPanel({
});
return (
<div className="dashboard-grid settings-dashboard-grid calendar-settings-panel">
<ContentGrid columns={2} collapseAt="workspace" className="calendar-settings-panel">
<div className="calendar-settings-documentation">
<DocumentationHelpLink reference={CALENDAR_DOCUMENTATION} />
</div>
<Card title="Calendar display">
<div className="form-grid">
<FormGrid columns={1} collapseAt="standard" className="">
<ToggleSwitch
label="Dim weekends"
help="Use a quieter background for Saturday and Sunday in week views."
@@ -147,7 +147,7 @@ export default function CalendarSettingsPanel({
setDraft((current) => ({ ...current, dim_off_hours }))
}
/>
<div className="calendar-dialog-grid-two">
<FormGrid columns={2} gap="small" collapseAt="narrow">
<FormField label="Workday starts">
<input
type="number"
@@ -178,11 +178,11 @@ export default function CalendarSettingsPanel({
}
/>
</FormField>
</div>
</div>
</FormGrid>
</FormGrid>
</Card>
<Card title="Continuous view">
<div className="form-grid">
<FormGrid columns={1} collapseAt="standard" className="">
<ToggleSwitch
label="Virtualize distant weeks"
help="Keep the continuous calendar responsive by rendering only nearby weeks."
@@ -240,9 +240,9 @@ export default function CalendarSettingsPanel({
{message}
</DismissibleAlert>
)}
</div>
</FormGrid>
</Card>
</div>
</ContentGrid>
);
}
-17
View File
@@ -944,19 +944,6 @@
gap: 10px;
}
.calendar-dialog-grid-two,
.calendar-dialog-grid-three,
.calendar-caldav-setup,
.calendar-sync-settings {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.calendar-dialog-grid-three {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.calendar-dialog-wide {
grid-column: 1 / -1;
}
@@ -1524,10 +1511,6 @@
.calendar-dialog-row,
.calendar-dialog-date-row,
.calendar-dialog-name-color-row,
.calendar-dialog-grid-two,
.calendar-dialog-grid-three,
.calendar-caldav-setup,
.calendar-sync-settings,
.calendar-sync-status-panel dl {
grid-template-columns: 1fr;
}