feat: Phase 4 Aether Drift — auth, modals & UI component token migration
Migrate all auth pages, modals, and shared UI components from Discord visual language to Aether Drift design tokens. Zero discord-* classes or raw Tailwind palette colors remain in components/auth/, modals/, ui/. - Avatar: status dots use status-online/idle/dnd/offline tokens - Tooltip, ContextMenu, UserProfilePopout: z-index raised to z-[200] - LoginPage, RegisterPage: warm bg-surface-base with lavender glow - All modals: inputs use surface-input, buttons use accent-primary - Toggles: bg-status-online (on), bg-surface-input (off) - ServerSettings: slider tracks, pills, danger zone fully tokenized - Purged raw Tailwind green-500 leak in StreamingLimitsPanel success msg
This commit is contained in:
@@ -13,10 +13,10 @@ interface AvatarProps {
|
||||
}
|
||||
|
||||
const statusColors: Record<string, string> = {
|
||||
online: 'bg-discord-green',
|
||||
idle: 'bg-discord-yellow',
|
||||
dnd: 'bg-discord-red',
|
||||
offline: 'bg-discord-text-muted',
|
||||
online: 'bg-status-online',
|
||||
idle: 'bg-status-idle',
|
||||
dnd: 'bg-status-dnd',
|
||||
offline: 'bg-status-offline',
|
||||
};
|
||||
|
||||
export function Avatar({ src, name, size = 40, status, className = '', onClick, user }: AvatarProps) {
|
||||
@@ -59,14 +59,14 @@ export function Avatar({ src, name, size = 40, status, className = '', onClick,
|
||||
/>
|
||||
) : null}
|
||||
<div
|
||||
className={`avatar-fallback w-full h-full rounded-full bg-discord-blurple flex items-center justify-center ${fontSize} font-semibold text-white ${src ? 'hidden' : 'flex'}`}
|
||||
className={`avatar-fallback w-full h-full rounded-full bg-accent-primary flex items-center justify-center ${fontSize} font-semibold text-white ${src ? 'hidden' : 'flex'}`}
|
||||
style={src ? { display: 'none' } : undefined}
|
||||
>
|
||||
{initials}
|
||||
</div>
|
||||
{status && (
|
||||
<div
|
||||
className={`absolute -bottom-0.5 -right-0.5 rounded-full border-[3px] border-discord-bg-secondary ${statusColors[status] ?? 'bg-discord-text-muted'}`}
|
||||
className={`absolute -bottom-0.5 -right-0.5 rounded-full border-[3px] border-surface-channel ${statusColors[status] ?? 'bg-status-offline'}`}
|
||||
style={{
|
||||
width: size * 0.35,
|
||||
height: size * 0.35,
|
||||
|
||||
@@ -62,7 +62,7 @@ export function ContextMenu({ items, children }: ContextMenuProps) {
|
||||
{isOpen && (
|
||||
<div
|
||||
ref={menuRef}
|
||||
className="fixed z-50 min-w-[180px] py-1.5 bg-discord-bg-floating rounded-md shadow-elevation-high animate-fade-in"
|
||||
className="fixed z-[200] min-w-[180px] py-1.5 bg-surface-elevated rounded-md shadow-elevation-high animate-fade-in"
|
||||
style={{ left: position.x, top: position.y }}
|
||||
>
|
||||
{items.map((item, i) => (
|
||||
@@ -70,8 +70,8 @@ export function ContextMenu({ items, children }: ContextMenuProps) {
|
||||
key={i}
|
||||
className={`w-full text-left px-2 py-1.5 mx-1.5 text-sm rounded-sm flex items-center gap-2 ${
|
||||
item.danger
|
||||
? 'text-discord-red hover:bg-discord-red hover:text-white'
|
||||
: 'text-discord-text-secondary hover:bg-discord-blurple hover:text-white'
|
||||
? 'text-txt-danger hover:bg-accent-rose hover:text-white'
|
||||
: 'text-txt-secondary hover:bg-accent-primary hover:text-white'
|
||||
}`}
|
||||
style={{ width: 'calc(100% - 12px)' }}
|
||||
onClick={(e) => {
|
||||
|
||||
@@ -38,7 +38,7 @@ export function Tooltip({ content, children, position = 'right', delay = 200 }:
|
||||
{children}
|
||||
{isVisible && (
|
||||
<div
|
||||
className={`absolute z-50 px-3 py-1.5 text-sm font-medium text-discord-text-primary bg-discord-bg-floating rounded-md shadow-elevation-high whitespace-nowrap pointer-events-none ${positionClasses[position]}`}
|
||||
className={`absolute z-[200] px-3 py-1.5 text-sm font-medium text-txt-primary bg-surface-elevated rounded-md shadow-elevation-high whitespace-nowrap pointer-events-none ${positionClasses[position]}`}
|
||||
>
|
||||
{content}
|
||||
</div>
|
||||
|
||||
@@ -31,15 +31,15 @@ export function UserProfilePopout({ user, onClose, position }: UserProfilePopout
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed z-50 w-[300px] bg-discord-bg-floating rounded-[8px] shadow-elevation-high overflow-hidden animate-fade-in select-none"
|
||||
className="fixed z-[200] w-[300px] bg-surface-elevated rounded-[8px] shadow-elevation-high overflow-hidden animate-fade-in select-none"
|
||||
style={position ? { top: position.top, left: position.left } : { top: '50%', left: '50%', transform: 'translate(-50%, -50%)' }}
|
||||
>
|
||||
{/* Banner */}
|
||||
<div className="h-[60px] bg-discord-blurple" />
|
||||
<div className="h-[60px] bg-accent-primary" />
|
||||
|
||||
{/* Avatar Container */}
|
||||
<div className="px-4 pb-4 relative">
|
||||
<div className="absolute -top-8 left-4 rounded-full border-[6px] border-discord-bg-floating bg-discord-bg-floating">
|
||||
<div className="absolute -top-8 left-4 rounded-full border-[6px] border-surface-elevated bg-surface-elevated">
|
||||
<Avatar
|
||||
src={user.avatar}
|
||||
name={displayName}
|
||||
@@ -49,27 +49,27 @@ export function UserProfilePopout({ user, onClose, position }: UserProfilePopout
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="mt-12 bg-discord-bg-tertiary rounded-[8px] p-3">
|
||||
<div className="text-[20px] font-bold text-discord-text-header leading-tight mb-1">
|
||||
<div className="mt-12 bg-surface-input rounded-[8px] p-3">
|
||||
<div className="text-[20px] font-bold text-txt-primary leading-tight mb-1">
|
||||
{displayName}
|
||||
</div>
|
||||
<div className="text-[14px] text-discord-text-normal font-medium mb-3">
|
||||
<div className="text-[14px] text-txt-secondary font-medium mb-3">
|
||||
@{user.username}
|
||||
</div>
|
||||
|
||||
<div className="w-full h-[1px] bg-discord-modifier-accent mb-3" />
|
||||
|
||||
|
||||
<div className="w-full h-[1px] bg-border-soft mb-3" />
|
||||
|
||||
<div className="mb-3">
|
||||
<div className="text-[12px] font-bold text-discord-text-header uppercase mb-1">Backspace Member Since</div>
|
||||
<div className="text-[12px] text-discord-text-normal font-medium">
|
||||
<div className="text-[12px] font-bold text-txt-primary uppercase mb-1">Backspace Member Since</div>
|
||||
<div className="text-[12px] text-txt-secondary font-medium">
|
||||
{new Date(user.createdAt).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' })}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{user.customStatus && (
|
||||
<div className="mb-3">
|
||||
<div className="text-[12px] font-bold text-discord-text-header uppercase mb-1">Status</div>
|
||||
<div className="text-[14px] text-discord-text-normal">{user.customStatus}</div>
|
||||
<div className="text-[12px] font-bold text-txt-primary uppercase mb-1">Status</div>
|
||||
<div className="text-[14px] text-txt-secondary">{user.customStatus}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -79,7 +79,7 @@ export function UserProfilePopout({ user, onClose, position }: UserProfilePopout
|
||||
<div className="px-4 pb-4">
|
||||
<button
|
||||
onClick={handleSendMessage}
|
||||
className="w-full py-2 bg-discord-blurple hover:bg-discord-blurple-hover text-white text-[14px] font-medium rounded-[4px] transition-colors"
|
||||
className="w-full py-2 bg-accent-primary hover:bg-accent-primary/80 text-white text-[14px] font-medium rounded-[4px] transition-colors"
|
||||
>
|
||||
Send Message
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user