Files
backspace/packages/web/src/utils/gradients.ts
T
Jannis Braun 003eff2268 feat: user profile customization with banner, accent color, bio, and full profile modal
Add banner image, accent color, and bio fields to user profiles with
full-stack support: schema migration, API validation (hex color format,
190-char bio limit), sanitizeUser propagation, and new GET /users/:id/mutuals
endpoint. Rewrite AccountPanel with live preview card, avatar/banner upload
via ImageCropModal, 16-preset accent color picker, and bio editor. Enhance
UserProfilePopout with banner display, accent-colored names, bio rendering,
and mutual counts. Add new UserProfileModal with About/Mutual Friends/Mutual
Spaces tabs and friend action buttons.
2026-03-10 17:08:29 +01:00

67 lines
3.2 KiB
TypeScript

/**
* Aether Drift gradient palettes for avatars and server icons.
* Deterministic color assignment based on entity ID (snowflake) or name.
*/
export interface GradientEntry {
gradient: string;
glow: string;
}
// ── 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
];
// ── 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
];
// ── Home button (DM / Backspace) — fixed indigo-purple gradient ──
export const HOME_GRADIENT: GradientEntry = {
gradient: 'linear-gradient(135deg, #6366f1, #8b5cf6)',
glow: '#8b5cf6',
};
/** djb2 hash → stable unsigned 32-bit integer. */
function hashString(str: string): number {
let hash = 5381;
for (let i = 0; i < str.length; i++) {
hash = ((hash << 5) + hash + str.charCodeAt(i)) >>> 0;
}
return hash;
}
/** Deterministic gradient for a user avatar. Prefers ID for stability; falls back to name. */
export function getAvatarGradient(id?: string | null, name?: string): GradientEntry {
const key = id || name || 'unknown';
return AVATAR_GRADIENTS[hashString(key) % AVATAR_GRADIENTS.length]!;
}
/** Deterministic gradient for a space icon. Prefers ID for stability; falls back to name. */
export function getSpaceGradient(id?: string | null, name?: string): GradientEntry {
const key = id || name || 'unknown';
return SPACE_GRADIENTS[hashString(key) % SPACE_GRADIENTS.length]!;
}
/** Shift each RGB component of a hex color by `amount` (positive = lighter, negative = darker). */
export function adjustColor(hex: string, amount: number): string {
const r = Math.max(0, Math.min(255, parseInt(hex.slice(1, 3), 16) + amount));
const g = Math.max(0, Math.min(255, parseInt(hex.slice(3, 5), 16) + amount));
const b = Math.max(0, Math.min(255, parseInt(hex.slice(5, 7), 16) + amount));
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
}