feat(ui): complete career and document workspaces

This commit is contained in:
cesnimda
2026-11-03 14:29:21 +01:00
parent 027907a806
commit 6f801251b0
168 changed files with 6120 additions and 39 deletions
@@ -3,7 +3,7 @@ import { createPortal } from "react-dom";
import {
Alert, Box, Button, Chip, Dialog, DialogActions, DialogContent, DialogTitle, FormControl, IconButton, InputLabel, MenuItem, Paper, Select,
Stack, Tab, Tabs, TextField, Tooltip, Typography, useMediaQuery, useTheme,
Stack, Tab, Tabs, TextField, Tooltip, Typography, useMediaQuery,
} from "@mui/material";
import RichTextField from "./RichTextField";
import Markdown from "./Markdown";
@@ -516,7 +516,7 @@ export function ApplicationCoverLetterSection({ jobId, onDirtyChange }: { jobId:
const [aiToolbarHost, setAiToolbarHost] = useState<HTMLDivElement | null>(null);
const { language, t } = useI18n();
const workspaceId = useId();
const wide = useMediaQuery(useTheme().breakpoints.up("md"));
const showBothPanes = useMediaQuery("(min-width:768px)");
const [pane, setPane] = useState("write");
const { confirm } = useConfirm();
const { data, error, loading, setData, setError, reload, isCurrent } = useAsset<CoverLetter>(
@@ -616,12 +616,12 @@ export function ApplicationCoverLetterSection({ jobId, onDirtyChange }: { jobId:
contentRef={contentRef}
>
<Stack spacing={2}>
{!wide && <Tabs value={pane} onChange={(_, value) => setPane(value)} aria-label={t("assetsLetterWorkspace")} variant="fullWidth">
{!showBothPanes && <Tabs value={pane} onChange={(_, value) => setPane(value)} aria-label={t("assetsLetterWorkspace")} variant="fullWidth">
<Tab value="write" label={t("assetsLetterWrite")} id={`${workspaceId}-write`} aria-controls={`${workspaceId}-write-panel`} />
<Tab value="preview" label={t("assetsLetterPreview")} id={`${workspaceId}-preview`} aria-controls={`${workspaceId}-preview-panel`} />
</Tabs>}
<Box sx={{ display: "grid", gridTemplateColumns: { xs: "minmax(0, 1fr)", md: "repeat(2, minmax(0, 1fr))" }, gap: 2 }}>
<Box hidden={!wide && pane !== "write"} id={`${workspaceId}-write-panel`} role={wide ? undefined : "tabpanel"} aria-labelledby={wide ? undefined : `${workspaceId}-write`} sx={{ minWidth: 0 }}>
<Box data-letter-studio-layout sx={{ display: "grid", gridTemplateColumns: "minmax(0, 1fr)", "@media (min-width:1001px)": { gridTemplateColumns: "repeat(2, minmax(0, 1fr))" }, gap: 2 }}>
<Box hidden={!showBothPanes && pane !== "write"} id={`${workspaceId}-write-panel`} role={showBothPanes ? undefined : "tabpanel"} aria-labelledby={showBothPanes ? undefined : `${workspaceId}-write`} sx={{ minWidth: 0 }}>
{settings && <CoverLetterDocumentFields settings={settings} disabled={busy || confirming || loading} onChange={next => { if (!busyRef.current) setSettingsDraft(next); }} />}
<RichTextField
minRows={12}
@@ -633,8 +633,8 @@ export function ApplicationCoverLetterSection({ jobId, onDirtyChange }: { jobId:
/>
<div ref={setAiToolbarHost} />
</Box>
<Box hidden={!wide && pane !== "preview"} id={`${workspaceId}-preview-panel`} role={wide ? undefined : "tabpanel"} aria-labelledby={wide ? undefined : `${workspaceId}-preview`} sx={{ minWidth: 0 }}>
{settings && <Box sx={{ mb: 2 }}><CoverLetterDocumentPreview key={jobId} jobId={jobId} text={text} settings={settings} active={wide || pane === "preview"} /></Box>}
<Box hidden={!showBothPanes && pane !== "preview"} id={`${workspaceId}-preview-panel`} role={showBothPanes ? undefined : "tabpanel"} aria-labelledby={showBothPanes ? undefined : `${workspaceId}-preview`} sx={{ minWidth: 0 }}>
{settings && <Box sx={{ mb: 2 }}><CoverLetterDocumentPreview key={jobId} jobId={jobId} text={text} settings={settings} active={showBothPanes || pane === "preview"} /></Box>}
{!settings && <Paper variant="outlined" role="region" aria-labelledby={`${workspaceId}-preview-title`} sx={{ p: 2, borderRadius: 2, overflowWrap: "anywhere" }}>
<Typography id={`${workspaceId}-preview-title`} component="h4" variant="subtitle2">{t("assetsLetterTextPreview")}</Typography>
<Typography variant="caption" color="text.secondary" component="p" sx={{ mb: 2 }}>{t("assetsLetterTextPreviewHelp")}</Typography>
@@ -47,10 +47,12 @@ export default function RichTextField({
};
const btn = (title: string, icon: React.ReactNode, before: string, after: string, ph: string) => (
<Tooltip title={title} slotProps={{ popper: { sx: { "&[data-popper-reference-hidden]": { visibility: "hidden" } } } }}>
<Tooltip title={title} describeChild slotProps={{ popper: { sx: { "&[data-popper-reference-hidden]": { visibility: "hidden" } } } }}>
<span style={{ display: 'inline-flex' }}>
<IconButton size="small" disabled={disabled} aria-label={title} onMouseDown={(e) => e.preventDefault()} onClick={() => apply(before, after, ph)}>
{icon}
</IconButton>
</span>
</Tooltip>
);