Settings as panels, the way the portal does it

Four tabs over three cards was navigation for its own sake, and the two shells
disagreed about what a settings screen looks like. It is one grid of cards now,
matching the portal: the account card carries changing a password and deleting
the account in its footer, appearance is a card with one row, and remote access
— an operator's concern, not a personal preference — is a card of its own for a
superuser.

SettingRow, alert-dialog and UserAvatar come across from the portal, so an
account renders the same face in both shells.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-27 16:04:42 +02:00
co-authored by Claude Opus 5
parent 6d09500a73
commit 5da5606f79
12 changed files with 717 additions and 367 deletions
@@ -0,0 +1,36 @@
import Avatar from "boring-avatars"
import useAuth from "@/hooks/useAuth"
// Shared avatar identity config, kept in step with the portal's copy
// (index/frontend/src/components/Common/UserAvatar.tsx) so one account renders
// the same face in both shells. The seed is the email, the only stable per-user
// id both sides hold. These are decorative identity colours, not design tokens.
export const AVATAR_VARIANT = "marble" as const
export const AVATAR_COLORS = [
"#EAAC0F",
"#e9e1cf",
"#18150f",
"#5d9a69",
"#9b8450",
]
/** Deterministic boring-avatars icon for the current user (seeded by email). */
export function UserAvatar({
size = 40,
className,
}: {
size?: number
className?: string
}) {
const { user } = useAuth()
return (
<Avatar
name={user?.email ?? "user"}
variant={AVATAR_VARIANT}
colors={AVATAR_COLORS}
size={size}
className={className}
/>
)
}