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:
hamed
2026-07-27 16:41:52 +03:30
parent c29035c21e
commit 55ab2f5dfc
73 changed files with 1485 additions and 1110 deletions
@@ -56,20 +56,20 @@ export function NewAppointmentsTable({ rows, loading, queryKey, emptyText }: Pro
}
if (!rows.length) {
return (
<p className="text-center py-[32px] text-[13.5px] text-[#7E7E7E] dark:text-[#A1A1A1]">
<p className="text-center py-[32px] text-[13.5px] text-[var(--text-2)]">
{emptyText ?? 'نوبتی برای امروز ثبت نشده'}
</p>
);
}
return (
<div className="w-full overflow-x-auto rounded-[8px] border border-solid border-[#E7E7E7] dark:border-[#35343D]">
<div className="w-full overflow-x-auto rounded-[8px] border border-solid border-[var(--border)]">
<table className="w-full border-collapse">
<thead>
<tr className="bg-[#EFEFEF] dark:bg-[#35343D]">
<tr className="bg-[var(--surface-2)]">
{HEAD.map((h, i) => (
<th
key={h}
className={`text-[#616161] dark:text-[#D7D8ED] text-[14px] font-normal py-[10px] px-[18px] whitespace-nowrap ${i === HEAD.length - 1 ? 'text-center' : 'text-start'}`}
className={`text-[var(--text-2)] dark:text-[var(--text)] text-[14px] font-normal py-[10px] px-[18px] whitespace-nowrap ${i === HEAD.length - 1 ? 'text-center' : 'text-start'}`}
>
{h}
</th>
@@ -80,7 +80,7 @@ export function NewAppointmentsTable({ rows, loading, queryKey, emptyText }: Pro
{rows.map((r, idx) => (
<tr
key={r.uuid}
className="border-b border-[#DBDBDB] dark:border-transparent hover:bg-[#f4f5fd] dark:hover:bg-[#2a2c3d] transition-colors"
className="border-b border-[var(--border-2)] dark:border-transparent hover:bg-[var(--primary-soft)] dark:hover:bg-[var(--surface-2)] transition-colors"
>
<Cell>{new Intl.NumberFormat('fa-IR').format(idx + 1)}</Cell>
<Cell>{r.patient_name || '—'}</Cell>
@@ -97,7 +97,7 @@ export function NewAppointmentsTable({ rows, loading, queryKey, emptyText }: Pro
<td className="py-[10px] px-[18px] text-center">
<Link
to={isoDay(r.slot_start) ? `/admin/appointments?date=${isoDay(r.slot_start)}` : '/admin/appointments'}
className="text-[#5559ce] text-[12px] font-medium hover:underline whitespace-nowrap"
className="text-[var(--primary)] text-[12px] font-medium hover:underline whitespace-nowrap"
>
مشاهده
</Link>
@@ -112,7 +112,7 @@ export function NewAppointmentsTable({ rows, loading, queryKey, emptyText }: Pro
/** نمایش فقط‌خواندنی وضعیت — وقتی version یا queryKey در دسترس نیست. */
function StatusPill({ status }: { status: string }) {
const meta = STATUS_META[status] ?? { label: status, color: '#9ca3af' };
const meta = STATUS_META[status] ?? { label: status, color: 'var(--text-3)' };
return (
<span
className="inline-flex items-center gap-[5px] px-[10px] py-[3px] rounded-full text-[12px] font-bold whitespace-nowrap"
@@ -128,7 +128,7 @@ function StatusPill({ status }: { status: string }) {
function Cell({ children, className = '' }: { children: React.ReactNode; className?: string }) {
return (
<td
className={`text-[#616161] dark:text-[#A1A1A1] text-[16px] font-medium py-[10px] px-[18px] whitespace-nowrap text-start ${className}`}
className={`text-[var(--text-2)] text-[16px] font-medium py-[10px] px-[18px] whitespace-nowrap text-start ${className}`}
>
{children}
</td>