From 5575a1a6aa992404d3a4ffd6783fe4ccf8801fa6 Mon Sep 17 00:00:00 2001 From: Talha Ahmed Date: Thu, 27 Aug 2026 19:43:24 +0500 Subject: [PATCH] UI fixes and job lifecycle actions - Jobs list: close/reopen action per requisition with confirm on close - Settings: real timezone and currency option lists - Assigned-role chip: readable color pairing on soft background - Scrollbars: Chromium honors the styled ::-webkit-scrollbar again (scrollbar-color now gated to Firefox), slightly wider hit area - Topbar hamburger: hidden on desktop (specificity fix) and the drawer closes itself when the window grows past the mobile breakpoint - Content scroller: removed overscroll containment that killed wheel scrolling everywhere except the scrollbar thumb Co-Authored-By: Claude Fable 5 --- frontend/src/app/useShell.js | 10 ++++++++ frontend/src/screens/CandidateProfile.jsx | 5 +++- frontend/src/screens/Jobs.jsx | 21 ++++++++++++++++ frontend/src/screens/Settings.jsx | 30 +++++++++++++++++++---- frontend/src/styles/styles.css | 27 ++++++++++++++------ 5 files changed, 79 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/useShell.js b/frontend/src/app/useShell.js index 2bccdd2..cbcc6be 100644 --- a/frontend/src/app/useShell.js +++ b/frontend/src/app/useShell.js @@ -36,6 +36,16 @@ export function useNavOpen() { } }, [navOpen]) + // The drawer only exists ≤900px (styles.css). If the window grows past the + // breakpoint while it is open, nav-open would strand the scrim over the + // desktop layout with body scroll locked — close it instead. + useEffect(() => { + const mq = window.matchMedia('(max-width: 900px)') + const onChange = (e) => { if (!e.matches) setNavOpen(false) } + mq.addEventListener('change', onChange) + return () => mq.removeEventListener('change', onChange) + }, []) + return [navOpen, setNavOpen] } diff --git a/frontend/src/screens/CandidateProfile.jsx b/frontend/src/screens/CandidateProfile.jsx index 4a379d9..7acea98 100644 --- a/frontend/src/screens/CandidateProfile.jsx +++ b/frontend/src/screens/CandidateProfile.jsx @@ -367,7 +367,10 @@ export default function CandidateProfile({ <>
Assigned Role
- + {/* --primary-fg is the on-solid-primary text color (white in + light theme) — on --primary-soft it was white-on-mint, + unreadable. Soft chips pair with --primary (see .b-indigo). */} + {live.assigned_job_post.title}
diff --git a/frontend/src/screens/Jobs.jsx b/frontend/src/screens/Jobs.jsx index d699174..64a8e64 100644 --- a/frontend/src/screens/Jobs.jsx +++ b/frontend/src/screens/Jobs.jsx @@ -239,6 +239,27 @@ export default function Jobs() { {canEdit && ( )} + {canEdit && (j.status === 'Closed' ? ( + + ) : ( + + ))} ), diff --git a/frontend/src/screens/Settings.jsx b/frontend/src/screens/Settings.jsx index 52ad7d5..a86173f 100644 --- a/frontend/src/screens/Settings.jsx +++ b/frontend/src/screens/Settings.jsx @@ -147,13 +147,35 @@ export default function Settings() { ) } +/* The option label IS the stored value (org_settings rows hold the full string), + so existing saved values like "(GMT-08:00) Pacific Time" must stay verbatim. */ +const TIMEZONES = [ + '(GMT-08:00) Pacific Time', + '(GMT-07:00) Mountain Time', + '(GMT-06:00) Central Time', + '(GMT-05:00) Eastern Time', + '(GMT+00:00) UTC', + '(GMT+00:00) London', + '(GMT+01:00) Central European Time', + '(GMT+03:00) Arabia Standard Time', + '(GMT+04:00) Gulf Standard Time', + '(GMT+05:00) Pakistan Standard Time', + '(GMT+05:30) India Standard Time', + '(GMT+08:00) Singapore Standard Time', + '(GMT+09:00) Japan Standard Time', + '(GMT+10:00) Australian Eastern Time', +] + +// Codes match the offer form's currency set (Offers.jsx). +const CURRENCIES = ['USD ($)', 'EUR (€)', 'GBP (£)', 'PKR (₨)', 'AED (د.إ)'] + function General({ registerSave }) { const defaults = { 'general.company_name': 'Utopia Brands Inc.', 'general.website': 'https://utopiabrands.com', 'general.industry': 'Consumer Goods', 'general.company_size': '201–500', - 'general.timezone': '(GMT-08:00) Pacific Time', + 'general.timezone': '(GMT+05:00) Pakistan Standard Time', 'general.currency': 'USD ($)', 'general.auto_archive_stale_jobs': true, 'general.duplicate_detection': true, @@ -204,15 +226,13 @@ function General({ registerSave }) {
diff --git a/frontend/src/styles/styles.css b/frontend/src/styles/styles.css index db18a1a..9724271 100644 --- a/frontend/src/styles/styles.css +++ b/frontend/src/styles/styles.css @@ -224,14 +224,18 @@ input, select, textarea { font-family: inherit; font-size: var(--fs-base); color a { color: inherit; text-decoration: none; -webkit-tap-highlight-color: transparent; } img, svg, video, canvas { max-width: 100%; } -::-webkit-scrollbar { width: 10px; height: 10px; } -::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 20px; border: 2px solid transparent; background-clip: padding-box; } +::-webkit-scrollbar { width: 14px; height: 14px; } +::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 20px; border: 3px solid transparent; background-clip: padding-box; } ::-webkit-scrollbar-thumb:hover { background: var(--text-3); background-clip: padding-box; } ::selection { background: var(--brand-lime); color: var(--brand-ink); } -/* Firefox / non-WebKit scrollbars (WebKit ignores these). */ -@supports (scrollbar-color: auto) { - * { scrollbar-color: var(--border-strong) transparent; scrollbar-width: thin; } +/* Firefox-only scrollbar colors. Chrome 121+ also passes + @supports (scrollbar-color: auto), and any non-auto scrollbar-color/width + makes Chromium IGNORE the ::-webkit-scrollbar rules above — the old + `scrollbar-width: thin` here is what forced the skinny native bars. + Gate on -moz-appearance so only Firefox takes this path. */ +@supports (-moz-appearance: none) { + * { scrollbar-color: var(--border-strong) transparent; } } /* ============================================================ @@ -444,7 +448,10 @@ table.data thead th, .rbac-matrix th, .cal-dow, .info-item .il, display: flex; align-items: center; gap: 16px; padding: 0 22px; position: sticky; top: 0; z-index: 50; } -.menu-toggle { display: none; } +/* Double class: .icon-btn { display: grid } is declared later with equal + specificity and used to win, leaving the hamburger visible on desktop — + where clicking it stranded the scrim over the page with scroll locked. */ +.icon-btn.menu-toggle { display: none; } .topbar-search { position: relative; flex: 1; max-width: 480px; display: flex; align-items: center; } .topbar-search > svg { position: absolute; left: 14px; width: 18px; height: 18px; color: var(--text-3); pointer-events: none; } .topbar-search input { @@ -530,7 +537,11 @@ table.data thead th, .rbac-matrix th, .cal-dow, .info-item .il, .dd-scroll { max-height: 360px; overflow-y: auto; overscroll-behavior: contain; } /* ================= CONTENT / PAGE ================= */ -.content { flex: 1; overflow-y: auto; overscroll-behavior-y: contain; -webkit-overflow-scrolling: touch; padding: 26px 30px 60px; } +/* No overscroll-behavior here: #app is min-height, so .content never overflows + and the DOCUMENT is the real scroller. `contain` on this (non-scrolling) + scroll container blocked wheel chaining — the wheel was dead everywhere + except dragging the scrollbar thumb. */ +.content { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 26px 30px 60px; } .page { animation: fadeUp .3s ease; } @keyframes fadeUp { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } .page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-5); margin-bottom: var(--space-6); flex-wrap: wrap; } @@ -1363,7 +1374,7 @@ canvas { width: 100%; max-width: 100%; display: block; } .sidebar.mobile-open { transform: translateX(0); box-shadow: var(--shadow-lg); } /* The FAB floated over the scrim and stayed tappable behind the drawer. */ .nav-open .ai-fab { display: none; } - .menu-toggle { display: grid; } + .icon-btn.menu-toggle { display: grid; } .search-kbd { display: none; } .content { padding: 20px max(16px, env(safe-area-inset-left)) 50px max(16px, env(safe-area-inset-right)); } .profile-meta { display: none; }