feat(ui): add A3 discovery filter rail and results layout
This commit is contained in:
@@ -56,6 +56,7 @@ export default function JobDiscoveryPage() {
|
||||
const [mutating, setMutating] = useState(false);
|
||||
const pending = useRef(false);
|
||||
const resultsRef = useRef<HTMLDivElement>(null);
|
||||
const queryRef = useRef<HTMLInputElement>(null);
|
||||
const removedControlRef = useRef<Element | null>(null);
|
||||
const busy = loading || savingSearch || updatingSavedSearchId !== null || mutating;
|
||||
|
||||
@@ -182,8 +183,12 @@ export default function JobDiscoveryPage() {
|
||||
|
||||
return (
|
||||
<Stack spacing={3} sx={{ minWidth: 0 }}>
|
||||
<Box component="form" onSubmit={search} sx={{ display: "grid", gridTemplateColumns: { xs: "1fr", md: "2fr 1fr auto" }, gap: 1.5 }}>
|
||||
<TextField label={t("jobDiscoveryRoleCompany")} value={query} disabled={busy} onChange={(event) => setQuery(event.target.value)} />
|
||||
<Alert severity="info" variant="outlined" sx={{ color: "text.primary", "& .MuiAlert-icon": { color: "info.main" } }}>{t("jobDiscoverySourceHelp")}</Alert>
|
||||
<Box data-discovery-layout sx={{ display: "grid", gap: 3, minWidth: 0, alignItems: "start", "@media (min-width:1001px)": { gridTemplateColumns: "minmax(16rem, 20rem) minmax(0, 1fr)" } }}>
|
||||
<Box component="aside" aria-label={t("jobDiscoveryFilters")} sx={{ display: "grid", gap: 2, minWidth: 0 }}>
|
||||
<PageHeader level="h2" title={t("jobDiscoveryFilters")} actions={<Button onClick={() => resultsRef.current?.focus()}>{t("jobDiscoveryJumpResults")}</Button>} />
|
||||
<Box component="form" aria-label={t("jobDiscoveryFilters")} onSubmit={search} sx={{ display: "grid", gridTemplateColumns: "minmax(0, 1fr)", gap: 1.5 }}>
|
||||
<TextField inputRef={queryRef} label={t("jobDiscoveryRoleCompany")} value={query} disabled={busy} onChange={(event) => setQuery(event.target.value)} />
|
||||
<TextField label={t("jobDiscoveryMunicipality")} value={location} disabled={busy} onChange={(event) => setLocation(event.target.value)} />
|
||||
<Button type="submit" variant="contained" startIcon={loading ? <CircularProgress aria-hidden="true" size={18} color="inherit" /> : <SearchIcon />} disabled={busy}>{t("jobDiscoverySearchNav")}</Button>
|
||||
</Box>
|
||||
@@ -223,9 +228,9 @@ export default function JobDiscoveryPage() {
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Alert severity="info" variant="outlined" sx={{ color: "text.primary", "& .MuiAlert-icon": { color: "info.main" } }}>{t("jobDiscoverySourceHelp")}</Alert>
|
||||
</Box>
|
||||
<Box role="region" aria-label={t("jobDiscoveryResults")} tabIndex={-1} ref={resultsRef} aria-busy={loading} sx={{ display: "grid", gap: 2, minWidth: 0 }}>
|
||||
{hasSearched ? <PageHeader level="h2" title={t("jobDiscoveryResults")} /> : null}
|
||||
<PageHeader level="h2" title={t("jobDiscoveryResults")} actions={<Button disabled={busy} onClick={() => queryRef.current?.focus()}>{t("jobDiscoveryReturnFilters")}</Button>} />
|
||||
<ViewStateNotice compact loading={loading} title={t(error ?? "jobDiscoveryUnavailable")}
|
||||
error={error ? { kind: "unavailable", message: t(error), retryable: error === "jobDiscoveryUnavailable" } : null}
|
||||
onRetry={() => {
|
||||
@@ -245,7 +250,7 @@ export default function JobDiscoveryPage() {
|
||||
</TextField>
|
||||
</Box>
|
||||
) : null}
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: { xs: "1fr", lg: "repeat(2, minmax(0, 1fr))" }, gap: 2 }}>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "minmax(0, 1fr)", gap: 2 }}>
|
||||
{sortedJobs.map((job) => (
|
||||
<Card key={job.id} component="article" aria-label={job.title} variant="outlined" sx={{ display: "flex", flexDirection: "column", minWidth: 0 }}>
|
||||
<CardContent sx={{ p: "var(--app-card-padding)" }}>
|
||||
@@ -274,6 +279,7 @@ export default function JobDiscoveryPage() {
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user