Adopt shared WebUI structural primitives
This commit is contained in:
@@ -15,13 +15,16 @@ import { ActionToolbar,
|
|||||||
Button,
|
Button,
|
||||||
DocumentationHelpLink,
|
DocumentationHelpLink,
|
||||||
DismissibleAlert,
|
DismissibleAlert,
|
||||||
|
FilterBar,
|
||||||
IconButton,
|
IconButton,
|
||||||
LoadingIndicator,
|
LoadingIndicator,
|
||||||
PageScrollViewport,
|
PageScrollViewport,
|
||||||
|
StatePanel,
|
||||||
StatusBadge,
|
StatusBadge,
|
||||||
hasScope,
|
hasScope,
|
||||||
i18nMessage,
|
i18nMessage,
|
||||||
usePlatformLanguage,
|
usePlatformLanguage,
|
||||||
|
WorkspaceFrame,
|
||||||
type PlatformRouteContext
|
type PlatformRouteContext
|
||||||
} from "@govoplan/core-webui";
|
} from "@govoplan/core-webui";
|
||||||
import {
|
import {
|
||||||
@@ -182,12 +185,12 @@ export default function CommitteePage({ settings, auth }: PlatformRouteContext)
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="committee-page">
|
<main className="committee-page">
|
||||||
<div className="committee-shell">
|
<WorkspaceFrame className="committee-shell" label="Committee workspace" interfaceId="committee.workspace" helpContextId="committee.page.workspace" helpModuleId="committee">
|
||||||
<ActionToolbar className="committee-toolbar">
|
<ActionToolbar surface="panel-header" className="committee-toolbar">
|
||||||
<form onSubmit={(event) => { event.preventDefault(); void refresh(); }} className="committee-search">
|
<FilterBar as="form" surface="control" wrap="never" width="compact" onSubmit={(event) => { event.preventDefault(); void refresh(); }} className="committee-search">
|
||||||
<Search size={16} aria-hidden="true" />
|
<Search size={16} aria-hidden="true" />
|
||||||
<input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Search bodies" aria-label="Search committee bodies" />
|
<input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Search bodies" aria-label="Search committee bodies" />
|
||||||
</form>
|
</FilterBar>
|
||||||
<Button variant="ghost" onClick={() => void refresh()} disabled={loading} disabledReason={loading ? COMMITTEE_INTERFACE_I18N.loading : undefined}>
|
<Button variant="ghost" onClick={() => void refresh()} disabled={loading} disabledReason={loading ? COMMITTEE_INTERFACE_I18N.loading : undefined}>
|
||||||
<RefreshCw size={16} aria-hidden="true" />
|
<RefreshCw size={16} aria-hidden="true" />
|
||||||
Refresh
|
Refresh
|
||||||
@@ -262,7 +265,7 @@ export default function CommitteePage({ settings, auth }: PlatformRouteContext)
|
|||||||
|
|
||||||
<section className="committee-detail" aria-label="Meeting workspace">
|
<section className="committee-detail" aria-label="Meeting workspace">
|
||||||
{!selectedMeeting ? (
|
{!selectedMeeting ? (
|
||||||
<div className="committee-empty">Select or create a meeting.</div>
|
<StatePanel size="fill" title="Meetings" description="Select or create a meeting." />
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="committee-detail-heading">
|
<div className="committee-detail-heading">
|
||||||
@@ -310,7 +313,7 @@ export default function CommitteePage({ settings, auth }: PlatformRouteContext)
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{agendaItems.length === 0 ? <div className="committee-empty compact">No agenda items.</div> : null}
|
{agendaItems.length === 0 ? <StatePanel size="inline" description="No agenda items." /> : null}
|
||||||
</div>
|
</div>
|
||||||
</WorkspaceSection>
|
</WorkspaceSection>
|
||||||
|
|
||||||
@@ -373,7 +376,7 @@ export default function CommitteePage({ settings, auth }: PlatformRouteContext)
|
|||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</WorkspaceFrame>
|
||||||
|
|
||||||
{editor ? (
|
{editor ? (
|
||||||
<CommitteeRecordDialog
|
<CommitteeRecordDialog
|
||||||
@@ -410,7 +413,7 @@ function RecordList({ records, selectedId, onSelect, secondary }: {
|
|||||||
onSelect: (id: string) => void;
|
onSelect: (id: string) => void;
|
||||||
secondary?: (record: CommitteeRecord) => string;
|
secondary?: (record: CommitteeRecord) => string;
|
||||||
}) {
|
}) {
|
||||||
if (records.length === 0) return <div className="committee-empty compact">No records.</div>;
|
if (records.length === 0) return <StatePanel size="inline" description="No records." />;
|
||||||
return <div className="committee-record-list">{records.map((record) => (
|
return <div className="committee-record-list">{records.map((record) => (
|
||||||
<button key={record.object_id} type="button" className={record.object_id === selectedId ? "is-selected" : ""} onClick={() => onSelect(record.object_id)}>
|
<button key={record.object_id} type="button" className={record.object_id === selectedId ? "is-selected" : ""} onClick={() => onSelect(record.object_id)}>
|
||||||
<strong>{record.title}</strong>
|
<strong>{record.title}</strong>
|
||||||
@@ -430,7 +433,7 @@ function RecordRows({ records, editDisabledReason, onEdit, detail, secondaryActi
|
|||||||
detail: (record: CommitteeRecord) => string;
|
detail: (record: CommitteeRecord) => string;
|
||||||
secondaryAction?: (record: CommitteeRecord) => ReactNode;
|
secondaryAction?: (record: CommitteeRecord) => ReactNode;
|
||||||
}) {
|
}) {
|
||||||
if (records.length === 0) return <div className="committee-empty compact">No records.</div>;
|
if (records.length === 0) return <StatePanel size="inline" description="No records." />;
|
||||||
return <div className="committee-record-rows">{records.map((record) => (
|
return <div className="committee-record-rows">{records.map((record) => (
|
||||||
<div key={record.object_id}>
|
<div key={record.object_id}>
|
||||||
<span><strong>{record.title}</strong><small>{detail(record)}</small></span>
|
<span><strong>{record.title}</strong><small>{detail(record)}</small></span>
|
||||||
|
|||||||
@@ -1,39 +1,14 @@
|
|||||||
.committee-page,
|
.committee-page {
|
||||||
.committee-shell {
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.committee-shell {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background: var(--surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
.committee-toolbar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 9px;
|
|
||||||
min-height: 58px;
|
|
||||||
padding: 10px 16px;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
background: var(--surface-raised);
|
|
||||||
}
|
|
||||||
|
|
||||||
.committee-search {
|
.committee-search {
|
||||||
display: flex;
|
flex: 1 1 460px;
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
width: min(460px, 100%);
|
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.committee-search input {
|
|
||||||
min-width: 140px;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.committee-alert {
|
.committee-alert {
|
||||||
margin: 10px 16px 0;
|
margin: 10px 16px 0;
|
||||||
}
|
}
|
||||||
@@ -231,17 +206,6 @@
|
|||||||
gap: 4px !important;
|
gap: 4px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.committee-empty {
|
|
||||||
display: grid;
|
|
||||||
min-height: 180px;
|
|
||||||
place-items: center;
|
|
||||||
color: var(--text-soft);
|
|
||||||
}
|
|
||||||
|
|
||||||
.committee-empty.compact {
|
|
||||||
min-height: 72px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.committee-record-dialog {
|
.committee-record-dialog {
|
||||||
width: min(820px, calc(100vw - 32px));
|
width: min(820px, calc(100vw - 32px));
|
||||||
max-height: min(820px, calc(100vh - 32px));
|
max-height: min(820px, calc(100vh - 32px));
|
||||||
@@ -292,15 +256,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 760px) {
|
@media (max-width: 760px) {
|
||||||
.committee-toolbar {
|
|
||||||
align-items: stretch;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.committee-search {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.committee-workspace {
|
.committee-workspace {
|
||||||
grid-template-columns: minmax(150px, 0.8fr) minmax(0, 1.8fr);
|
grid-template-columns: minmax(150px, 0.8fr) minmax(0, 1.8fr);
|
||||||
grid-template-rows: repeat(2, minmax(0, 1fr));
|
grid-template-rows: repeat(2, minmax(0, 1fr));
|
||||||
|
|||||||
Reference in New Issue
Block a user