Implement comprehensive dark/light mode overhaul for admin panel
- Refactor color palette in `ui-design-spec.md` to utilize CSS variables exclusively, eliminating fixed hex values and Tailwind utility classes. - Complete dark mode implementation in `uiStore.ts`, ensuring proper theme application via `applyTheme()` and `applyBrand()`. - Create `admin-theme-dark-light-audit.md` to document the transition process, outlining issues with inline styles and fixed colors. - Introduce `theme-tokens.test.ts` to enforce rules against fixed hex colors and ensure compliance with the design system. - Update various components and styles to replace inline styles and fixed colors with CSS variables, ensuring consistent theming across light and dark modes. - Ensure all changes maintain visual integrity in both light and dark modes, with a focus on accessibility and contrast standards.
This commit is contained in:
@@ -55,8 +55,8 @@ export interface SessionCardData {
|
||||
function Row({ label, value, valueStyle }: { label: string; value: string; valueStyle?: CSSProperties }) {
|
||||
return (
|
||||
<div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 6, margin: '6px 0' }}>
|
||||
<span style={{ fontSize: 12, color: '#616161' }} className="dark:text-[#A1A1A1]">{label}:</span>
|
||||
<span style={{ fontSize: 14, color: '#525252', textAlign: 'left', ...valueStyle }} className="dark:text-[#D7D8ED]">{value}</span>
|
||||
<span style={{ fontSize: 12, color: 'var(--text-2)' }}>{label}:</span>
|
||||
<span style={{ fontSize: 14, color: 'var(--text)', textAlign: 'left', ...valueStyle }}>{value}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -99,27 +99,27 @@ export default function SessionServiceCard({ session, onSettle, onViewInvoice, o
|
||||
|
||||
return (
|
||||
<div
|
||||
className="bg-white dark:bg-[#222433] border border-[#EDEDED] dark:border-[#35343D]"
|
||||
className="bg-[var(--surface)] border border-[var(--border)]"
|
||||
style={{ minWidth: 277, minHeight: 331, borderRadius: 12, padding: 14, display: 'flex', flexDirection: 'column', gap: 10, overflow: 'hidden', boxShadow: '0 1px 6px rgba(15,23,42,0.06)' }}
|
||||
>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 2 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
|
||||
<FilesServiceSuccess />
|
||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 3, minWidth: 0 }}>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 14, fontWeight: 600, color: '#525252', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: 180 }}>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 14, fontWeight: 600, color: 'var(--text)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: 180 }}>
|
||||
{title}
|
||||
{session.archived && <span className="badge" style={{ fontSize: 10, color: '#9CA3AF', border: '1px solid #E0E0E0', borderRadius: 4, padding: '1px 6px' }}>آرشیو</span>}
|
||||
{session.archived && <span className="badge" style={{ fontSize: 10, color: 'var(--text-3)', border: '1px solid var(--border-2)', borderRadius: 4, padding: '1px 6px' }}>آرشیو</span>}
|
||||
</span>
|
||||
<span className="dark:text-[#A1A1A1]" style={{ fontSize: 12, color: '#6B7280', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: 200 }}>{subtitle}</span>
|
||||
<span style={{ fontSize: 12, color: 'var(--text-2)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: 200 }}>{subtitle}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div ref={menuRef} style={{ position: 'relative', flexShrink: 0 }}>
|
||||
<button type="button" aria-label="عملیات" onClick={() => setMenuOpen((o) => !o)}
|
||||
style={{ background: 'transparent', border: 'none', cursor: 'pointer', padding: 2, display: 'flex' }}>
|
||||
<FilesServiceMore style={{ color: '#9CA3AF' }} />
|
||||
<FilesServiceMore style={{ color: 'var(--text-3)' }} />
|
||||
</button>
|
||||
{menuOpen && (
|
||||
<div className="card dark:bg-[#222433] dark:border-[#35343D]" style={{ position: 'absolute', insetInlineEnd: 0, top: '100%', marginTop: 4, minWidth: 150, zIndex: 20, padding: 4, background: '#fff', border: '1px solid var(--border)', borderRadius: 8, boxShadow: 'var(--shadow-lg)' }}>
|
||||
<div className="card" style={{ position: 'absolute', insetInlineEnd: 0, top: '100%', marginTop: 4, minWidth: 150, zIndex: 20, padding: 4, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 8, boxShadow: 'var(--shadow-lg)' }}>
|
||||
<button type="button" onClick={() => { setMenuOpen(false); onViewInvoice(session); }}
|
||||
style={{ display: 'block', width: '100%', textAlign: 'right', padding: '8px 10px', fontSize: 13, background: 'transparent', border: 'none', borderRadius: 6, cursor: 'pointer', color: 'var(--text)', fontFamily: 'inherit' }}>
|
||||
مشاهده فاکتور
|
||||
@@ -138,7 +138,7 @@ export default function SessionServiceCard({ session, onSettle, onViewInvoice, o
|
||||
)}
|
||||
{onArchive && (
|
||||
<button type="button" onClick={() => { setMenuOpen(false); onArchive(session, !session.archived); }}
|
||||
style={{ display: 'block', width: '100%', textAlign: 'right', padding: '8px 10px', fontSize: 13, background: 'transparent', border: 'none', borderRadius: 6, cursor: 'pointer', color: session.archived ? 'var(--text)' : '#EF4444', fontFamily: 'inherit' }}>
|
||||
style={{ display: 'block', width: '100%', textAlign: 'right', padding: '8px 10px', fontSize: 13, background: 'transparent', border: 'none', borderRadius: 6, cursor: 'pointer', color: session.archived ? 'var(--text)' : 'var(--danger)', fontFamily: 'inherit' }}>
|
||||
{session.archived ? 'خروج از آرشیو' : 'آرشیو'}
|
||||
</button>
|
||||
)}
|
||||
@@ -147,7 +147,7 @@ export default function SessionServiceCard({ session, onSettle, onViewInvoice, o
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="dark:border-[#35343D]" style={{ borderTop: '1px solid #F1F1F1' }} />
|
||||
<div style={{ borderTop: '1px solid var(--border)' }} />
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: 0, overflow: 'hidden', lineHeight: 1.9 }}>
|
||||
<Row label="انجام دهنده" value={session.doctor_name || '—'} />
|
||||
@@ -155,7 +155,7 @@ export default function SessionServiceCard({ session, onSettle, onViewInvoice, o
|
||||
<Row label="توضیحات" value={session.notes || '—'} valueStyle={{ display: 'flex', textAlign: 'right', width: '100%' }} />
|
||||
</div>
|
||||
|
||||
<div className="dark:border-[#35343D]" style={{ borderTop: '1px solid #F1F1F1' }} />
|
||||
<div style={{ borderTop: '1px solid var(--border)' }} />
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', width: '100%' }}>
|
||||
{session.insurance_service_category_label && (
|
||||
@@ -163,10 +163,10 @@ export default function SessionServiceCard({ session, onSettle, onViewInvoice, o
|
||||
)}
|
||||
{session.insurance_base_name && <Row label="بیمه" value={session.insurance_base_name} />}
|
||||
{(session.base_insurance_rials ?? 0) > 0 && (
|
||||
<Row label="سهم بیمه" value={formatRial(session.base_insurance_rials ?? 0)} valueStyle={{ color: '#16A34A', fontWeight: 500 }} />
|
||||
<Row label="سهم بیمه" value={formatRial(session.base_insurance_rials ?? 0)} valueStyle={{ color: 'var(--success)', fontWeight: 500 }} />
|
||||
)}
|
||||
<Row label="هزینه" value={formatRial(session.final_price_rials ?? 0)} valueStyle={{ fontWeight: 500 }} />
|
||||
{!paid && <Row label="مانده بدهی" value={formatRial(debt)} valueStyle={{ color: '#EF4444', fontWeight: 500 }} />}
|
||||
{!paid && <Row label="مانده بدهی" value={formatRial(debt)} valueStyle={{ color: 'var(--danger)', fontWeight: 500 }} />}
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: 'auto' }}>
|
||||
@@ -175,7 +175,7 @@ export default function SessionServiceCard({ session, onSettle, onViewInvoice, o
|
||||
type="button"
|
||||
disabled={issuing}
|
||||
onClick={() => onViewInvoice(session)}
|
||||
style={{ marginTop: 8, height: 40, width: '100%', borderRadius: 4, fontSize: 13, fontWeight: 500, cursor: 'pointer', color: '#4F46E5', background: 'transparent', border: '1px solid #5559ce' }}
|
||||
style={{ marginTop: 8, height: 40, width: '100%', borderRadius: 4, fontSize: 13, fontWeight: 500, cursor: 'pointer', color: 'var(--primary)', background: 'transparent', border: '1px solid var(--primary)' }}
|
||||
>
|
||||
{issuing ? 'در حال صدور…' : 'مشاهده فاکتور'}
|
||||
</button>
|
||||
@@ -184,7 +184,7 @@ export default function SessionServiceCard({ session, onSettle, onViewInvoice, o
|
||||
type="button"
|
||||
disabled={settling}
|
||||
onClick={() => onSettle(session.uuid)}
|
||||
style={{ marginTop: 8, height: 40, width: '100%', borderRadius: 4, fontSize: 13, fontWeight: 500, cursor: 'pointer', color: '#fff', background: '#5559ce', border: '1px solid #5559ce' }}
|
||||
style={{ marginTop: 8, height: 40, width: '100%', borderRadius: 4, fontSize: 13, fontWeight: 500, cursor: 'pointer', color: 'var(--on-primary)', background: 'var(--primary)', border: '1px solid var(--primary)' }}
|
||||
>
|
||||
تکمیل پرداخت
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user