refactor: replace hardcoded hex values with Tailwind semantic tokens
3,200+ hardcoded color values replaced with CSS variable-backed Tailwind classes (bg-card, text-foreground, border-border, etc.). Enables light mode via CSS variable swap. Only syntax highlighting colors and intentional one-offs remain hardcoded (~15 values). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -80,7 +80,7 @@ export function AppLayout() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setMobileMenuOpen(true)}
|
||||
className="fixed left-4 top-3.5 z-50 rounded-lg p-2 text-[#848b9b] hover:bg-[#14161d] hover:text-[#e2e5eb] transition-colors md:hidden"
|
||||
className="fixed left-4 top-3.5 z-50 rounded-lg p-2 text-muted-foreground hover:bg-card hover:text-foreground transition-colors md:hidden"
|
||||
aria-label="Open menu"
|
||||
>
|
||||
<Menu size={20} />
|
||||
@@ -101,12 +101,12 @@ export function AppLayout() {
|
||||
<div className="flex h-14 items-center justify-between px-4" style={{ borderBottom: '1px solid #1e2130' }}>
|
||||
<Link to="/" className="flex items-center gap-2.5">
|
||||
<BrandLogo size="sm" />
|
||||
<span className="text-sm font-heading font-bold text-[#f0f2f5]">ResolutionFlow</span>
|
||||
<span className="text-sm font-heading font-bold text-text-heading">ResolutionFlow</span>
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
className="rounded-lg p-2 text-[#848b9b] hover:bg-[#14161d] hover:text-[#e2e5eb]"
|
||||
className="rounded-lg p-2 text-muted-foreground hover:bg-card hover:text-foreground"
|
||||
aria-label="Close menu"
|
||||
>
|
||||
<X size={18} />
|
||||
@@ -116,9 +116,9 @@ export function AppLayout() {
|
||||
<div className="flex flex-col p-3">
|
||||
{/* User info */}
|
||||
<div className="mb-3 pb-3 px-3" style={{ borderBottom: '1px solid #1e2130' }}>
|
||||
<p className="text-sm font-medium text-[#e2e5eb]">{user?.name || user?.email}</p>
|
||||
<p className="text-sm font-medium text-foreground">{user?.name || user?.email}</p>
|
||||
{effectiveRole && effectiveRole !== 'engineer' && (
|
||||
<span className="mt-1 inline-flex items-center gap-1 text-xs text-[#848b9b]">
|
||||
<span className="mt-1 inline-flex items-center gap-1 text-xs text-muted-foreground">
|
||||
<Shield size={10} />
|
||||
{effectiveRole === 'super_admin' ? 'Super Admin' : effectiveRole === 'owner' ? 'Owner' : 'Viewer'}
|
||||
</span>
|
||||
@@ -139,8 +139,8 @@ export function AppLayout() {
|
||||
className={cn(
|
||||
'flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors',
|
||||
isActive
|
||||
? 'bg-[rgba(34,211,238,0.10)] text-[#e2e5eb]'
|
||||
: 'text-[#848b9b] hover:bg-[#191c25] hover:text-[#e2e5eb]'
|
||||
? 'bg-accent-dim text-foreground'
|
||||
: 'text-muted-foreground hover:bg-input hover:text-foreground'
|
||||
)}
|
||||
>
|
||||
<Icon size={18} />
|
||||
@@ -155,7 +155,7 @@ export function AppLayout() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleLogout}
|
||||
className="flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium text-[#848b9b] hover:bg-[#191c25] hover:text-[#e2e5eb] transition-colors"
|
||||
className="flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium text-muted-foreground hover:bg-input hover:text-foreground transition-colors"
|
||||
>
|
||||
<LogOut size={18} />
|
||||
Logout
|
||||
|
||||
@@ -48,7 +48,7 @@ export function NavItem({ href, icon: Icon, label, badge, iconColor, matchPaths,
|
||||
title={label}
|
||||
>
|
||||
{isActive && (
|
||||
<div className="absolute left-0 top-1/2 h-6 w-[3px] -translate-y-1/2 rounded-r-full bg-[#22d3ee]" />
|
||||
<div className="absolute left-0 top-1/2 h-6 w-[3px] -translate-y-1/2 rounded-r-full bg-primary" />
|
||||
)}
|
||||
<Icon size={18} className={cn('shrink-0', isActive ? 'opacity-100' : 'opacity-70')} style={iconColor ? { color: iconColor } : undefined} />
|
||||
{badge !== undefined && badge !== 0 && badge !== 'dot' && (
|
||||
@@ -76,7 +76,7 @@ export function NavItem({ href, icon: Icon, label, badge, iconColor, matchPaths,
|
||||
>
|
||||
{/* Active indicator bar */}
|
||||
{isActive && !isParentDimmed && (
|
||||
<div className="absolute left-0 top-1/2 h-6 w-[3px] -translate-y-1/2 rounded-r-full bg-[#22d3ee]" />
|
||||
<div className="absolute left-0 top-1/2 h-6 w-[3px] -translate-y-1/2 rounded-r-full bg-primary" />
|
||||
)}
|
||||
|
||||
<Icon size={18} className={cn('shrink-0', isActive ? 'opacity-100' : 'opacity-70')} style={iconColor ? { color: iconColor } : undefined} />
|
||||
|
||||
@@ -254,15 +254,15 @@ export function Sidebar() {
|
||||
className={cn(
|
||||
'group relative flex flex-col items-center justify-center rounded-lg px-1 py-2 transition-all duration-150',
|
||||
active
|
||||
? 'bg-[rgba(34,211,238,0.10)] text-[#67e8f9]'
|
||||
: 'text-[#6b7280] hover:text-[#848b9b]'
|
||||
? 'bg-accent-dim text-accent-text'
|
||||
: 'text-text-rail-label hover:text-muted-foreground'
|
||||
)}
|
||||
title={item.label}
|
||||
>
|
||||
<span className="relative">
|
||||
<Icon size={20} className={active ? 'opacity-100' : 'opacity-60 group-hover:opacity-85'} />
|
||||
{item.badge !== undefined && item.badge > 0 && (
|
||||
<span className="absolute -right-1.5 -top-1.5 flex h-4 min-w-[16px] items-center justify-center rounded-full bg-[#22d3ee] px-1 text-[0.5rem] font-bold text-[#0c0d10]">
|
||||
<span className="absolute -right-1.5 -top-1.5 flex h-4 min-w-[16px] items-center justify-center rounded-full bg-primary px-1 text-[0.5rem] font-bold text-[#0c0d10]">
|
||||
{item.badge > 99 ? '99+' : item.badge}
|
||||
</span>
|
||||
)}
|
||||
@@ -293,9 +293,9 @@ export function Sidebar() {
|
||||
'group relative flex items-center gap-3 rounded-lg px-3 py-2 text-[0.8125rem] font-medium transition-all duration-150',
|
||||
active
|
||||
? isParentDimmed
|
||||
? 'bg-[rgba(34,211,238,0.05)] text-[#e2e5eb]/70'
|
||||
: 'bg-[rgba(34,211,238,0.10)] text-[#e2e5eb]'
|
||||
: 'text-[#848b9b] hover:bg-[#191c25] hover:text-[#e2e5eb]'
|
||||
? 'bg-[rgba(34,211,238,0.05)] text-foreground/70'
|
||||
: 'bg-accent-dim text-foreground'
|
||||
: 'text-muted-foreground hover:bg-input hover:text-foreground'
|
||||
)}
|
||||
>
|
||||
{active && !isParentDimmed && (
|
||||
@@ -307,7 +307,7 @@ export function Sidebar() {
|
||||
<Icon size={18} className={cn('shrink-0', active ? 'opacity-100' : 'opacity-70')} />
|
||||
<span className="truncate">{item.label}</span>
|
||||
{item.badge !== undefined && item.badge > 0 && (
|
||||
<span className="ml-auto shrink-0 rounded-full px-2 text-[0.6875rem] font-mono text-[#4f5666]"
|
||||
<span className="ml-auto shrink-0 rounded-full px-2 text-[0.6875rem] font-mono text-text-muted"
|
||||
style={{ background: '#14161d', border: '1px solid #1e2130' }}>
|
||||
{item.badge}
|
||||
</span>
|
||||
@@ -331,13 +331,13 @@ export function Sidebar() {
|
||||
className={cn(
|
||||
'flex items-center gap-2 rounded-lg pl-9 pr-3 py-1.5 text-[0.8125rem] font-medium transition-colors',
|
||||
childActive
|
||||
? 'bg-[rgba(34,211,238,0.10)] text-[#e2e5eb]'
|
||||
: 'text-[#848b9b] hover:bg-[#191c25] hover:text-[#e2e5eb]'
|
||||
? 'bg-accent-dim text-foreground'
|
||||
: 'text-muted-foreground hover:bg-input hover:text-foreground'
|
||||
)}
|
||||
>
|
||||
<span className="truncate">{child.label}</span>
|
||||
{child.count !== undefined && (
|
||||
<span className="ml-auto shrink-0 rounded-full px-2 text-[0.6875rem] font-mono text-[#4f5666]"
|
||||
<span className="ml-auto shrink-0 rounded-full px-2 text-[0.6875rem] font-mono text-text-muted"
|
||||
style={{ background: '#14161d', border: '1px solid #1e2130' }}>
|
||||
{child.count}
|
||||
</span>
|
||||
@@ -373,7 +373,7 @@ export function Sidebar() {
|
||||
{sections.map((section, si) => (
|
||||
<div key={section.title}>
|
||||
{si > 0 && (
|
||||
<div className="font-mono text-[0.5625rem] uppercase tracking-[0.12em] text-[#4f5666] px-3 pt-3 pb-1">
|
||||
<div className="font-mono text-[0.5625rem] uppercase tracking-[0.12em] text-text-muted px-3 pt-3 pb-1">
|
||||
{section.title}
|
||||
</div>
|
||||
)}
|
||||
@@ -390,7 +390,7 @@ export function Sidebar() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={toggleSidebarPinned}
|
||||
className="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-[0.8125rem] font-medium text-[#848b9b] hover:bg-[#191c25] hover:text-[#e2e5eb] transition-colors"
|
||||
className="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-[0.8125rem] font-medium text-muted-foreground hover:bg-input hover:text-foreground transition-colors"
|
||||
title="Unpin sidebar"
|
||||
>
|
||||
<PinOff size={18} className="shrink-0" />
|
||||
@@ -427,7 +427,7 @@ export function Sidebar() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={toggleSidebarPinned}
|
||||
className="flex flex-col items-center justify-center rounded-lg px-1 py-2 text-[#6b7280] hover:text-[#848b9b] transition-colors"
|
||||
className="flex flex-col items-center justify-center rounded-lg px-1 py-2 text-text-rail-label hover:text-muted-foreground transition-colors"
|
||||
title="Pin sidebar"
|
||||
>
|
||||
<Pin size={18} className="opacity-60 hover:opacity-85" />
|
||||
@@ -455,7 +455,7 @@ export function Sidebar() {
|
||||
>
|
||||
{/* Drawer header */}
|
||||
<div className="px-3 mb-3">
|
||||
<h3 className="text-[0.6875rem] font-mono uppercase tracking-[0.12em] text-[#4f5666]">
|
||||
<h3 className="text-[0.6875rem] font-mono uppercase tracking-[0.12em] text-text-muted">
|
||||
{activeFlyoutGroup.label}
|
||||
</h3>
|
||||
</div>
|
||||
@@ -469,13 +469,13 @@ export function Sidebar() {
|
||||
className={cn(
|
||||
'flex items-center justify-between rounded-md px-3 py-2 text-[0.8125rem] transition-colors',
|
||||
isChildActive(child)
|
||||
? 'bg-[rgba(34,211,238,0.10)] text-[#67e8f9]'
|
||||
: 'text-[#848b9b] hover:bg-[#191c25] hover:text-[#e2e5eb]'
|
||||
? 'bg-accent-dim text-accent-text'
|
||||
: 'text-muted-foreground hover:bg-input hover:text-foreground'
|
||||
)}
|
||||
>
|
||||
<span>{child.label}</span>
|
||||
{child.count !== undefined && (
|
||||
<span className="text-[0.6875rem] font-mono text-[#4f5666]">{child.count}</span>
|
||||
<span className="text-[0.6875rem] font-mono text-text-muted">{child.count}</span>
|
||||
)}
|
||||
</Link>
|
||||
))}
|
||||
@@ -484,7 +484,7 @@ export function Sidebar() {
|
||||
|
||||
{/* Resize handle */}
|
||||
<div
|
||||
className="w-1 cursor-col-resize hover:bg-[#22d3ee]/20 active:bg-[#22d3ee]/30 transition-colors shrink-0"
|
||||
className="w-1 cursor-col-resize hover:bg-primary/20 active:bg-primary/30 transition-colors shrink-0"
|
||||
onPointerDown={handleResizeStart}
|
||||
title="Drag to resize"
|
||||
/>
|
||||
|
||||
@@ -67,7 +67,7 @@ export function TopBar() {
|
||||
className="flex items-center gap-2.5 pr-4 transition-all duration-200"
|
||||
>
|
||||
<BrandLogo size="sm" />
|
||||
<span className="text-sm font-heading font-bold tracking-tight whitespace-nowrap text-[#f0f2f5]">
|
||||
<span className="text-sm font-heading font-bold tracking-tight whitespace-nowrap text-text-heading">
|
||||
ResolutionFlow
|
||||
</span>
|
||||
</Link>
|
||||
@@ -81,9 +81,9 @@ export function TopBar() {
|
||||
className="hidden sm:relative sm:block w-full text-left"
|
||||
style={{ maxWidth: '480px' }}
|
||||
>
|
||||
<Search size={16} className="absolute left-3 top-1/2 -translate-y-1/2 text-[#848b9b]" />
|
||||
<Search size={16} className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground" />
|
||||
<div
|
||||
className="w-full rounded-md py-2 pl-9 pr-14 text-[0.8125rem] text-[#848b9b] cursor-pointer transition-colors"
|
||||
className="w-full rounded-md py-2 pl-9 pr-14 text-[0.8125rem] text-muted-foreground cursor-pointer transition-colors"
|
||||
style={{
|
||||
background: '#14161d',
|
||||
border: '1px solid #1e2130',
|
||||
@@ -94,7 +94,7 @@ export function TopBar() {
|
||||
Search flows, sessions, tags...
|
||||
</div>
|
||||
<span
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 rounded px-1.5 py-0.5 font-mono text-[0.625rem] text-[#4f5666]"
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 rounded px-1.5 py-0.5 font-mono text-[0.625rem] text-text-muted"
|
||||
style={{ background: '#0c0d10', border: '1px solid #1e2130' }}
|
||||
>
|
||||
{navigator.platform?.toLowerCase().includes('mac') ? '\u2318K' : 'Ctrl+K'}
|
||||
@@ -102,7 +102,7 @@ export function TopBar() {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCommandPaletteOpen(true)}
|
||||
className="sm:hidden rounded-lg p-2 text-[#848b9b] hover:text-[#e2e5eb] transition-colors"
|
||||
className="sm:hidden rounded-lg p-2 text-muted-foreground hover:text-foreground transition-colors"
|
||||
title="Search"
|
||||
>
|
||||
<Search size={18} />
|
||||
@@ -115,14 +115,14 @@ export function TopBar() {
|
||||
<div className="flex items-center gap-1">
|
||||
<button
|
||||
onClick={() => setQuickLaunchOpen(true)}
|
||||
className="rounded-lg p-2 text-[#848b9b] hover:bg-[#14161d] hover:text-[#e2e5eb] transition-colors"
|
||||
className="rounded-lg p-2 text-muted-foreground hover:bg-card hover:text-foreground transition-colors"
|
||||
title="Quick Launch"
|
||||
>
|
||||
<Zap size={18} />
|
||||
</button>
|
||||
<Link
|
||||
to="/guides"
|
||||
className="rounded-lg p-2 text-[#848b9b] hover:bg-[#14161d] hover:text-[#e2e5eb] transition-colors"
|
||||
className="rounded-lg p-2 text-muted-foreground hover:bg-card hover:text-foreground transition-colors"
|
||||
title="User Guides"
|
||||
>
|
||||
<HelpCircle size={18} />
|
||||
@@ -146,9 +146,9 @@ export function TopBar() {
|
||||
style={{ background: '#14161d', border: '1px solid #1e2130' }}
|
||||
>
|
||||
<div className="px-3 py-2.5 mb-1" style={{ borderBottom: '1px solid #1e2130' }}>
|
||||
<p className="text-sm font-medium text-[#e2e5eb] truncate">{user?.name || user?.email}</p>
|
||||
<p className="text-sm font-medium text-foreground truncate">{user?.name || user?.email}</p>
|
||||
{effectiveRole && effectiveRole !== 'engineer' && (
|
||||
<span className="mt-1 inline-flex items-center gap-1 text-xs text-[#848b9b]">
|
||||
<span className="mt-1 inline-flex items-center gap-1 text-xs text-muted-foreground">
|
||||
<Shield size={10} />
|
||||
{effectiveRole === 'super_admin' ? 'Super Admin' : effectiveRole === 'owner' ? 'Owner' : 'Viewer'}
|
||||
</span>
|
||||
@@ -157,7 +157,7 @@ export function TopBar() {
|
||||
<Link
|
||||
to="/account"
|
||||
onClick={() => setUserMenuOpen(false)}
|
||||
className="flex items-center gap-2 rounded-md px-3 py-2 text-sm text-[#848b9b] hover:bg-[#191c25] hover:text-[#e2e5eb]"
|
||||
className="flex items-center gap-2 rounded-md px-3 py-2 text-sm text-muted-foreground hover:bg-input hover:text-foreground"
|
||||
>
|
||||
<Settings size={14} />
|
||||
Account
|
||||
@@ -166,7 +166,7 @@ export function TopBar() {
|
||||
<Link
|
||||
to="/admin"
|
||||
onClick={() => setUserMenuOpen(false)}
|
||||
className="flex items-center gap-2 rounded-md px-3 py-2 text-sm text-[#848b9b] hover:bg-[#191c25] hover:text-[#e2e5eb]"
|
||||
className="flex items-center gap-2 rounded-md px-3 py-2 text-sm text-muted-foreground hover:bg-input hover:text-foreground"
|
||||
>
|
||||
<Shield size={14} />
|
||||
Admin Panel
|
||||
@@ -177,7 +177,7 @@ export function TopBar() {
|
||||
onClick={handleLogout}
|
||||
className={cn(
|
||||
'flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm',
|
||||
'text-[#848b9b] hover:bg-[#191c25] hover:text-[#e2e5eb]'
|
||||
'text-muted-foreground hover:bg-input hover:text-foreground'
|
||||
)}
|
||||
>
|
||||
<LogOut size={14} />
|
||||
|
||||
Reference in New Issue
Block a user