feat: comprehensive UI overhaul + budget allocation redesign
Audit & Quality: - RTL: replaced 121 LTR-only utilities (text-left, pl-, left-) with logical properties - A11y: focus traps + ARIA on Modal/SlidePanel/TabbedModal, clickable divs→buttons - Theming: bg-white→bg-surface (170 instances), text-gray→semantic tokens - Performance: useMemo on filters, loading="lazy" on 24 images - CSS: prefers-reduced-motion, removed dead animations Component Splits: - PostDetailPanel: 1332→623 lines + 4 sub-components - ArtefactDetailPanel: 972→590 lines + 1 sub-component Brand Identity — Rawaj (رواج): - New name, DM Sans font, deep teal palette (#0d9488) - Custom SVG logo, forest-tinted dark mode - All emails branded with app name in subject line Design Refinement: - Dashboard: merged posts+deadlines into tabbed ActivityFeed, inline stats - Quieter: removed card lift, brand glow, gradient text, mesh backgrounds - CampaignDetail: prominent budget card, compact team avatars, Lucide icons - Consistent page titles via Header.jsx, standardized section headers - Finance page fully i18n'd (20+ hardcoded strings replaced) Budget Allocation Redesign: - Single source of truth: BudgetEntries (Campaign.budget deprecated) - Validation at all levels: main→campaign→track, expenses blocked if insufficient - Budget request workflow with CEO approval via public link - BudgetRequests table, CRUD routes, public approval page - Budget mutex for race condition prevention - Idempotent migration for existing campaign budgets Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -116,7 +116,7 @@ export default function CommentsSection({ entityType, entityId }) {
|
||||
<div key={c.id} className="flex items-start gap-2 group">
|
||||
<div className="w-7 h-7 rounded-full bg-brand-primary/10 text-brand-primary flex items-center justify-center text-[10px] font-bold shrink-0 mt-0.5">
|
||||
{c.user_avatar ? (
|
||||
<img src={c.user_avatar} className="w-full h-full rounded-full object-cover" alt="" />
|
||||
<img src={c.user_avatar} className="w-full h-full rounded-full object-cover" alt="" loading="lazy" />
|
||||
) : (
|
||||
getInitials(c.user_name)
|
||||
)}
|
||||
@@ -125,7 +125,7 @@ export default function CommentsSection({ entityType, entityId }) {
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs font-medium text-text-primary">{c.user_name}</span>
|
||||
<span className="text-[10px] text-text-tertiary">{relativeTime(c.created_at, t)}</span>
|
||||
<div className="flex items-center gap-0.5 ml-auto opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<div className="flex items-center gap-0.5 ms-auto opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
{canEdit(c) && editingId !== c.id && (
|
||||
<button
|
||||
onClick={() => startEdit(c)}
|
||||
|
||||
Reference in New Issue
Block a user