Add dynamic sidebar text color with brand color contrast

- Add sidebar text color picker to Branding Settings page
- Implement auto-calculated complementary text colors based on brand color luminance
- Dark themes get light tinted text, light themes get dark tinted text
- Add navigation preview showing text on gradient background
- Support 10 new lighter color palettes (Soft Mint, Lavender, Peach, etc.)
- Add CSS utility classes for brand-text with opacity support
- Update sidebar and navigation components to use dynamic text colors
- Add sidebar_text_color field to Tenant model with migration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-16 22:16:25 -05:00
parent 6a6ad63e7b
commit 725a3c5d84
15 changed files with 365 additions and 54 deletions

View File

@@ -72,7 +72,7 @@ const Sidebar: React.FC<SidebarProps> = ({ business, user, isCollapsed, toggleCo
return (
<div
className={`flex flex-col h-full text-white shrink-0 transition-all duration-300 ${isCollapsed ? 'w-20' : 'w-64'}`}
className={`flex flex-col h-full text-brand-text shrink-0 transition-all duration-300 ${isCollapsed ? 'w-20' : 'w-64'}`}
style={{
background: `linear-gradient(to bottom right, var(--color-brand-600, ${business.primaryColor}), var(--color-brand-secondary, ${business.secondaryColor || business.primaryColor}))`
}}
@@ -112,7 +112,7 @@ const Sidebar: React.FC<SidebarProps> = ({ business, user, isCollapsed, toggleCo
{!isCollapsed && business.logoDisplayMode !== 'logo-only' && (
<div className="overflow-hidden">
<h1 className="font-bold leading-tight truncate">{business.name}</h1>
<p className="text-xs text-white/60 truncate">{business.subdomain}.smoothschedule.com</p>
<p className="text-xs text-brand-text/60 truncate">{business.subdomain}.smoothschedule.com</p>
</div>
)}
</>
@@ -331,22 +331,22 @@ const Sidebar: React.FC<SidebarProps> = ({ business, user, isCollapsed, toggleCo
</nav>
{/* User Section */}
<div className="p-4 border-t border-white/10">
<div className="p-4 border-t border-brand-text/10">
<a
href={`${window.location.protocol}//${window.location.host.split('.').slice(-2).join('.')}`}
target="_blank"
rel="noopener noreferrer"
className={`flex items-center gap-2 text-xs text-white/60 mb-3 hover:text-white/80 transition-colors ${isCollapsed ? 'justify-center' : ''}`}
className={`flex items-center gap-2 text-xs text-brand-text/60 mb-3 hover:text-brand-text/80 transition-colors ${isCollapsed ? 'justify-center' : ''}`}
>
<SmoothScheduleLogo className="w-5 h-5 text-white" />
<SmoothScheduleLogo className="w-5 h-5 text-brand-text" />
{!isCollapsed && (
<span className="text-white/60">{t('nav.smoothSchedule')}</span>
<span className="text-brand-text/60">{t('nav.smoothSchedule')}</span>
)}
</a>
<button
onClick={handleSignOut}
disabled={logoutMutation.isPending}
className={`flex items-center gap-3 px-3 py-2 text-sm font-medium text-white/70 hover:text-white hover:bg-white/5 w-full transition-colors rounded-lg ${isCollapsed ? 'justify-center' : ''} disabled:opacity-50`}
className={`flex items-center gap-3 px-3 py-2 text-sm font-medium text-brand-text/70 hover:text-brand-text hover:bg-brand-text/5 w-full transition-colors rounded-lg ${isCollapsed ? 'justify-center' : ''} disabled:opacity-50`}
>
<LogOut size={18} className="shrink-0" />
{!isCollapsed && <span>{t('auth.signOut')}</span>}