feat: Phase 1 Aether Drift — mobile-first grid layout and token migration

Replace Discord flex layout with CSS Grid on desktop (312px sidebar +
1fr main) and overlay drawer on mobile. Migrate all discord-* class
references to Aether Drift design tokens across 15 files (~200 refs).

Layout: ServerSidebar becomes a fixed glass strip (md:glass-strip),
ChannelSidebar gets pl-[72px] offset, bottom bar is a glass-bubble
(z-105), MessageInput floats as absolute glass pill on desktop (z-110).
MemberSidebar/ActivityPanel hidden on mobile via hidden md:block.

Z-index stack: MobileNav backdrop z-35, sidebar z-40, glass strip z-100,
bottom bar z-105, input bubble z-110, hamburger z-120, profile popout
z-145, device panels z-150, modals z-200.
This commit is contained in:
Jannis Braun
2026-03-01 22:46:27 +01:00
parent e219229b63
commit 79252fe54a
15 changed files with 412 additions and 230 deletions
@@ -15,7 +15,7 @@ function getMemberGroup(member: MemberWithUser, ownerId: string | undefined) {
return {
key: '__owner__',
label: 'OWNER',
color: ownerRole?.color ?? '#f23f43',
color: ownerRole?.color ?? 'var(--accent-rose)',
position: Infinity,
};
}
@@ -79,7 +79,7 @@ export function MemberSidebar() {
return { color: sorted[0]!.color };
}
if (ownerId && member.userId === ownerId) {
return { color: '#f23f43' };
return { color: 'var(--accent-rose)' };
}
return undefined;
};
@@ -100,7 +100,7 @@ export function MemberSidebar() {
<div
key={member.userId}
onClick={(e) => handleMemberClick(e, member.user)}
className="flex items-center gap-3 px-2 py-1.5 rounded-[4px] hover:bg-discord-modifier-hover cursor-pointer group transition-colors"
className="flex items-center gap-3 px-2 py-1.5 rounded-[4px] hover:bg-interactive-hover cursor-pointer group transition-colors"
>
<Avatar
src={member.user.avatar}
@@ -111,13 +111,13 @@ export function MemberSidebar() {
/>
<div className="flex-1 min-w-0">
<div
className={`text-[15px] font-medium truncate ${isOffline ? 'text-discord-text-muted' : (!colorStyle ? 'text-discord-text-primary' : '')}`}
className={`text-[15px] font-medium truncate ${isOffline ? 'text-txt-tertiary' : (!colorStyle ? 'text-txt-primary' : '')}`}
style={colorStyle}
>
{displayName}
</div>
{!isOffline && member.user.customStatus && (
<div className="text-[12px] text-discord-text-muted truncate">{member.user.customStatus}</div>
<div className="text-[12px] text-txt-tertiary truncate">{member.user.customStatus}</div>
)}
</div>
</div>
@@ -125,12 +125,12 @@ export function MemberSidebar() {
};
return (
<div className="w-60 bg-discord-bg-members flex-shrink-0 overflow-y-auto select-none no-scrollbar">
<div className="w-60 bg-surface-members flex-shrink-0 overflow-y-auto select-none no-scrollbar hidden md:block">
<div className="p-3">
{/* Role-based groups */}
{roleGroups.map(([key, group]) => (
<div key={key} className="mb-4">
<h3 className="text-[12px] font-bold text-discord-text-muted uppercase tracking-wider px-2 mb-1">
<h3 className="text-[12px] font-bold text-txt-tertiary uppercase tracking-wider px-2 mb-1">
{group.label} {group.members.length}
</h3>
{group.members.map((m) => renderMember(m))}
@@ -140,7 +140,7 @@ export function MemberSidebar() {
{/* Offline */}
{offlineMembers.length > 0 && (
<div>
<h3 className="text-[12px] font-bold text-discord-text-muted uppercase tracking-wider px-2 mb-1">
<h3 className="text-[12px] font-bold text-txt-tertiary uppercase tracking-wider px-2 mb-1">
OFFLINE {offlineMembers.length}
</h3>
{offlineMembers.map((m) => renderMember(m, true))}