UI fixes and job lifecycle actions
Deploy to S3 / deploy (push) Successful in 35s Details

- 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 <noreply@anthropic.com>
pull/29/head
Talha Ahmed 2026-08-27 19:43:24 +05:00
parent 1ae5249d18
commit 5575a1a6aa
5 changed files with 79 additions and 14 deletions

View File

@ -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]
}

View File

@ -367,7 +367,10 @@ export default function CandidateProfile({
<>
<div style={LABEL}>Assigned Role</div>
<div className="k-tags" style={{ marginBottom: 14 }}>
<span className="tag" style={{ background: 'var(--primary-soft)', color: 'var(--primary-fg)' }}>
{/* --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). */}
<span className="tag" style={{ background: 'var(--primary-soft)', color: 'var(--primary)' }}>
{live.assigned_job_post.title}
</span>
</div>

View File

@ -239,6 +239,27 @@ export default function Jobs() {
{canEdit && (
<button className="act-btn" data-tip="Edit" aria-label="Edit job" onClick={() => setEditing(j)}><Icon name="edit" /></button>
)}
{canEdit && (j.status === 'Closed' ? (
<button
className="act-btn"
data-tip="Reopen"
aria-label="Reopen job"
disabled={setJobStatus.isPending}
onClick={() => setJobStatus.mutate({ id: j.id, status: 'Open' })}
><Icon name="refresh" /></button>
) : (
<button
className="act-btn"
data-tip="Close job"
aria-label="Close job"
disabled={setJobStatus.isPending}
onClick={() => {
if (window.confirm(`Close “${j.title}”? It stays on the board and can be reopened later.`)) {
setJobStatus.mutate({ id: j.id, status: 'Closed' })
}
}}
><Icon name="x-circle" /></button>
))}
<button className="act-btn" data-tip="Publish" aria-label="Publish job" onClick={() => navigate('/jobboard', { state: { publishJob: j.id } })}><Icon name="send" /></button>
</div>
),

View File

@ -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': '201500',
'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 }) {
<div className="form-field">
<label>Default Time Zone</label>
<select value={draft['general.timezone'] ?? ''} onChange={(e) => setField('general.timezone', e.target.value)}>
<option>(GMT-08:00) Pacific Time</option>
<option>(GMT-05:00) Eastern Time</option>
<option>(GMT+00:00) UTC</option>
{TIMEZONES.map((tz) => <option key={tz}>{tz}</option>)}
</select>
</div>
<div className="form-field">
<label>Default Currency</label>
<select value={draft['general.currency'] ?? ''} onChange={(e) => setField('general.currency', e.target.value)}>
<option>USD ($)</option><option>EUR ()</option><option>GBP (£)</option>
{CURRENCIES.map((c) => <option key={c}>{c}</option>)}
</select>
</div>
</div>

View File

@ -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; }