From 40e829369512acf0ca4b3fbb9f2798391519a152 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Tue, 10 Mar 2026 21:40:57 +0100 Subject: [PATCH] fix: banner/avatar overlap in settings preview and refine profile color system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move bg-surface-channel from info section to card wrapper in AccountPanel so the avatar's negative margin overlaps into the banner correctly. Replace accent color presets with 7×3 banner color palette, remove accent color tinting from display names in popout/modal, and refactor gradient entries to expose from/to hex stops. --- .../components/modals/UserProfileModal.tsx | 20 +----- .../modals/settingsPanels/AccountPanel.tsx | 48 ++++++++------- .../src/components/ui/UserProfilePopout.tsx | 3 +- packages/web/src/utils/gradients.ts | 61 +++++++++++-------- 4 files changed, 64 insertions(+), 68 deletions(-) diff --git a/packages/web/src/components/modals/UserProfileModal.tsx b/packages/web/src/components/modals/UserProfileModal.tsx index 01607dfb..83116d26 100644 --- a/packages/web/src/components/modals/UserProfileModal.tsx +++ b/packages/web/src/components/modals/UserProfileModal.tsx @@ -251,7 +251,7 @@ export function UserProfileModal() { {/* Header (avatar + name) */} -
+
{domain ? ( @@ -346,23 +345,6 @@ export function UserProfileModal() {
- {/* Accent color */} - {user.accentColor && ( -
- - Accent Color - -
-
- - {user.accentColor} - -
-
- )}
)} diff --git a/packages/web/src/components/modals/settingsPanels/AccountPanel.tsx b/packages/web/src/components/modals/settingsPanels/AccountPanel.tsx index 8ff0e82e..a1e2b287 100644 --- a/packages/web/src/components/modals/settingsPanels/AccountPanel.tsx +++ b/packages/web/src/components/modals/settingsPanels/AccountPanel.tsx @@ -3,7 +3,7 @@ import { useAuthStore } from '../../../stores/authStore'; import { Avatar } from '../../ui/Avatar'; import { ImageCropModal } from '../../ui/ImageCropModal'; import { api } from '../../../api/client'; -import { getAvatarGradient, adjustColor, AVATAR_GRADIENT_MAP, ACCENT_PRESETS } from '../../../utils/gradients'; +import { getAvatarGradient, adjustColor, AVATAR_GRADIENT_MAP, BANNER_COLOR_PRESETS } from '../../../utils/gradients'; import { AVATAR_COLORS } from '@backspace/shared'; import type { User, UserStatus, AvatarColor } from '@backspace/shared'; @@ -212,17 +212,17 @@ export function AccountPanel() {
{/* Live Preview Card */} -
+
{/* Banner area */}
{/* Avatar + info */} -
+
{effectiveDisplayName}
@@ -410,24 +409,29 @@ export function AccountPanel() {
- {/* Accent Color */} + {/* Banner Color */}
- +
- {ACCENT_PRESETS.map((color) => ( -
{/* Body */} -
+
{/* Avatar */}
{domain ? ( diff --git a/packages/web/src/utils/gradients.ts b/packages/web/src/utils/gradients.ts index 13652802..b076501b 100644 --- a/packages/web/src/utils/gradients.ts +++ b/packages/web/src/utils/gradients.ts @@ -6,19 +6,25 @@ import type { AvatarColor } from '@backspace/shared'; export interface GradientEntry { - gradient: string; - glow: string; + from: string; // hex start color + to: string; // hex end color + gradient: string; // CSS linear-gradient (derived from from/to) + glow: string; // hex glow color (hand-curated most prominent color) +} + +function grad(from: string, to: string, glow: string): GradientEntry { + return { from, to, gradient: `linear-gradient(135deg, ${from}, ${to})`, glow }; } // ── Avatar gradients (user fallbacks) ── const AVATAR_GRADIENTS: GradientEntry[] = [ - { gradient: 'linear-gradient(135deg, #059669, #10b981)', glow: '#10b981' }, // mint - { gradient: 'linear-gradient(135deg, #3b82f6, #6366f1)', glow: '#6366f1' }, // sky - { gradient: 'linear-gradient(135deg, #a78bfa, #c084fc)', glow: '#c084fc' }, // lavender - { gradient: 'linear-gradient(135deg, #f97316, #ef4444)', glow: '#f97316' }, // coral - { gradient: 'linear-gradient(135deg, #f43f5e, #ec4899)', glow: '#ec4899' }, // rose - { gradient: 'linear-gradient(135deg, #14b8a6, #06b6d4)', glow: '#06b6d4' }, // teal - { gradient: 'linear-gradient(135deg, #f59e0b, #eab308)', glow: '#f59e0b' }, // amber + grad('#059669', '#10b981', '#10b981'), // mint + grad('#3b82f6', '#6366f1', '#6366f1'), // sky + grad('#a78bfa', '#c084fc', '#c084fc'), // lavender + grad('#f97316', '#ef4444', '#f97316'), // coral + grad('#f43f5e', '#ec4899', '#ec4899'), // rose + grad('#14b8a6', '#06b6d4', '#06b6d4'), // teal + grad('#f59e0b', '#eab308', '#f59e0b'), // amber ]; export const AVATAR_GRADIENT_MAP: Record = { @@ -33,20 +39,17 @@ export const AVATAR_GRADIENT_MAP: Record = { // ── Space icon gradients (space fallbacks) ── const SPACE_GRADIENTS: GradientEntry[] = [ - { gradient: 'linear-gradient(135deg, #ef4444, #f97316)', glow: '#f97316' }, // red-orange - { gradient: 'linear-gradient(135deg, #ec4899, #f472b6)', glow: '#ec4899' }, // pink - { gradient: 'linear-gradient(135deg, #14b8a6, #06b6d4)', glow: '#06b6d4' }, // teal-cyan - { gradient: 'linear-gradient(135deg, #f59e0b, #eab308)', glow: '#f59e0b' }, // amber-yellow - { gradient: 'linear-gradient(135deg, #3b82f6, #6366f1)', glow: '#6366f1' }, // blue-indigo - { gradient: 'linear-gradient(135deg, #a78bfa, #c084fc)', glow: '#c084fc' }, // lavender - { gradient: 'linear-gradient(135deg, #059669, #10b981)', glow: '#10b981' }, // mint + grad('#ef4444', '#f97316', '#f97316'), // red-orange + grad('#ec4899', '#f472b6', '#ec4899'), // pink + grad('#14b8a6', '#06b6d4', '#06b6d4'), // teal-cyan + grad('#f59e0b', '#eab308', '#f59e0b'), // amber-yellow + grad('#3b82f6', '#6366f1', '#6366f1'), // blue-indigo + grad('#a78bfa', '#c084fc', '#c084fc'), // lavender + grad('#059669', '#10b981', '#10b981'), // mint ]; // ── Home button (DM / Backspace) — fixed indigo-purple gradient ── -export const HOME_GRADIENT: GradientEntry = { - gradient: 'linear-gradient(135deg, #6366f1, #8b5cf6)', - glow: '#8b5cf6', -}; +export const HOME_GRADIENT: GradientEntry = grad('#6366f1', '#8b5cf6', '#8b5cf6'); /** djb2 hash → stable unsigned 32-bit integer. */ function hashString(str: string): number { @@ -72,11 +75,19 @@ export function getSpaceGradient(id?: string | null, name?: string): GradientEnt return SPACE_GRADIENTS[hashString(key) % SPACE_GRADIENTS.length]!; } -/** Flat accent-color presets derived from the avatar gradient palette. Both stops per gradient. */ -export const ACCENT_PRESETS: string[] = AVATAR_GRADIENTS.flatMap(g => { - const matches = g.gradient.match(/#[0-9a-fA-F]{6}/g); - return matches ?? []; -}); +/** Banner-color presets: 7 families × 3 shades (deep, vibrant, soft). */ +export const BANNER_COLOR_PRESETS: string[][] = [ + ['#047857', '#10b981', '#6ee7b7'], // mint + ['#4338ca', '#6366f1', '#a5b4fc'], // sky + ['#7c3aed', '#c084fc', '#e9d5ff'], // lavender + ['#c2410c', '#f97316', '#fdba74'], // coral + ['#be185d', '#ec4899', '#f9a8d4'], // rose + ['#0e7490', '#06b6d4', '#67e8f9'], // teal + ['#b45309', '#f59e0b', '#fcd34d'], // amber +]; + +/** @deprecated Use BANNER_COLOR_PRESETS instead. */ +export const ACCENT_PRESETS: string[] = BANNER_COLOR_PRESETS.map(f => f[1]!); /** Shift each RGB component of a hex color by `amount` (positive = lighter, negative = darker). */ export function adjustColor(hex: string, amount: number): string {