From 5219237613af5872d96bcff7f3f043928cf0e75f Mon Sep 17 00:00:00 2001 From: cesnimda Date: Mon, 13 Jul 2026 14:22:07 +0200 Subject: [PATCH] style(ui): redesign error pages and job table empty/loading state No mockup exists for 404/500 pages, so these follow the visual language already established elsewhere this session: floating-shadow card, big bold status number (matching the dashboard stat tiles' bold-number treatment) instead of a small overline. JobTable's first-run empty state gets an icon chip matching the landing page's feature-card icon treatment (rounded square, tinted primary background) instead of plain text -- the filtered "no results" one-liner stays as-is, that's a different, correctly minimal case. Main table Paper wrapper gets the same floating-shadow treatment as every other card this session. ViewStateNotice (the shared loading/error component used across the app) reviewed and left untouched -- it's an MUI Alert used as an inline banner, which is the correct pattern; it was never a "fake card" to begin with. --- job-tracker-ui/src/components/JobTable.tsx | 28 +++++++++++++++++++-- job-tracker-ui/src/views/NotFoundPage.tsx | 11 ++++++-- job-tracker-ui/src/views/RouteErrorPage.tsx | 13 ++++++++-- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/job-tracker-ui/src/components/JobTable.tsx b/job-tracker-ui/src/components/JobTable.tsx index 71f933f..fe3fe7d 100644 --- a/job-tracker-ui/src/components/JobTable.tsx +++ b/job-tracker-ui/src/components/JobTable.tsx @@ -39,6 +39,7 @@ import RestoreFromTrashOutlinedIcon from "@mui/icons-material/RestoreFromTrashOu import MoreHorizIcon from "@mui/icons-material/MoreHoriz"; import ViewColumnIcon from "@mui/icons-material/ViewColumn"; import SearchIcon from "@mui/icons-material/Search"; +import WorkOutlineIcon from "@mui/icons-material/WorkOutline"; import { api } from "../api"; import ViewStateNotice from "./ViewStateNotice"; @@ -115,7 +116,22 @@ function EmptyJobsState({ firstTime, onOpenSettings, t }: { firstTime: boolean; return {t("jobTableNoJobsFound")}; } return ( - + + alpha(theme.palette.primary.main, 0.12), + color: "primary.main", + }} + > + + {t("jobTableEmptyFirstTimeTitle")} {t("jobTableEmptyFirstTimeBody")} @@ -514,7 +530,15 @@ export default function JobTable({ refreshToken, pageSize, onPageSizeChange, col /> ) : null} - + {isMobile ? ( diff --git a/job-tracker-ui/src/views/NotFoundPage.tsx b/job-tracker-ui/src/views/NotFoundPage.tsx index 6965f0e..744bbb4 100644 --- a/job-tracker-ui/src/views/NotFoundPage.tsx +++ b/job-tracker-ui/src/views/NotFoundPage.tsx @@ -8,9 +8,16 @@ export default function NotFoundPage() { const { t } = useI18n(); return ( - + - + 404 diff --git a/job-tracker-ui/src/views/RouteErrorPage.tsx b/job-tracker-ui/src/views/RouteErrorPage.tsx index 270f87b..6f2d587 100644 --- a/job-tracker-ui/src/views/RouteErrorPage.tsx +++ b/job-tracker-ui/src/views/RouteErrorPage.tsx @@ -16,9 +16,18 @@ export default function RouteErrorPage() { return ( - + - + {error?.status || 500}