Skip to content

workos-auth/ui-shell: Add account dropdown to auth corner#52

Open
x0ba wants to merge 1 commit into
workos-auth/corefrom
workos-auth/ui-shell
Open

workos-auth/ui-shell: Add account dropdown to auth corner#52
x0ba wants to merge 1 commit into
workos-auth/corefrom
workos-auth/ui-shell

Conversation

@x0ba
Copy link
Copy Markdown
Owner

@x0ba x0ba commented May 29, 2026

Stack Context

This 3-PR stack migrates FlightLog from Clerk to WorkOS AuthKit while preserving cookie sessions for the dashboard and Bearer tokens for the SDK/API.

Stack: workos-auth/core (#51) → workos-auth/ui-shellworkos-auth/docs-tests

Why?

PR 1 ships a functional but minimal auth corner. This PR polishes the app shell account UI with a compact avatar dropdown that matches the rest of the shadcn-based dashboard.

What?

  • Add shadcn dropdown-menu components
  • Replace minimal email/sign-out block with avatar initials trigger
  • Dropdown shows email and the same POST sign-out form

Test plan

  • bun run check
  • bun run lint (src/)
  • bunx vitest run src/lib/server/auth.test.ts src/lib/auth-redirect.test.ts
  • Manual: signed-in sidebar shows avatar menu with email and working sign out

Introduce shadcn dropdown-menu and replace the minimal email/sign-out block
with a compact avatar trigger menu in the app shell sidebar.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
flightlog Error Error May 29, 2026 8:25pm

Copy link
Copy Markdown
Owner Author

x0ba commented May 29, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@x0ba x0ba changed the title Add account dropdown to auth corner with avatar initials and sign-out. workos-auth/ui-shell: Add account dropdown to auth corner May 29, 2026
@x0ba x0ba marked this pull request as ready for review May 29, 2026 20:27
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 29, 2026

Greptile Summary

This PR polishes the auth corner introduced in PR #51 by replacing the flat email/sign-out block with a compact avatar-initials trigger that opens a shadcn DropdownMenu, and adds the full set of bits-ui–backed dropdown-menu primitive wrappers to match the existing shadcn component library.

  • auth-corner.svelte derives two-letter initials from the email local part (or last two chars of userId as fallback), renders an 8×8 rounded avatar button, and places email display and a sign-out form inside the resulting dropdown.
  • Seventeen new ui/dropdown-menu/*.svelte files plus a barrel index.ts add the complete shadcn dropdown-menu component set, enabling reuse elsewhere in the dashboard.

Confidence Score: 3/5

Safe to merge for mouse/pointer users; keyboard-only users cannot sign out through the dropdown.

The sign-out form nested inside DropdownMenuItem works for mouse clicks because the button fills the entire item area, but bits-ui dispatches keyboard activation (Enter/Space) as a synthetic click on the item div rather than on child elements, so the button[type="submit"] inside the form is never triggered. Separately, focus:bg-transparent on that same item removes the only focus indicator keyboard users would have. The rest of the PR — the new shadcn dropdown-menu primitives and the initials derivation — is straightforward and clean.

src/lib/components/auth-corner.svelte — specifically the DropdownMenuItem wrapping the sign-out form at lines 38–47.

Important Files Changed

Filename Overview
src/lib/components/auth-corner.svelte Replaces flat email/sign-out block with an avatar initials trigger and dropdown menu; the sign-out form nested inside DropdownMenuItem won't respond to keyboard activation (Enter key), and focus:bg-transparent removes focus visual feedback for keyboard users.
src/lib/components/ui/dropdown-menu/index.ts Barrel export exposing all dropdown-menu components under both short (e.g. Item) and prefixed (e.g. DropdownMenuItem) names — standard shadcn pattern, no issues.
src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte Wraps bits-ui Content in a portal, forwards all props. Default w-(--bits-dropdown-menu-anchor-width) matches trigger width, so callers with small triggers (like the 32px avatar) should always pass an explicit width class — auth-corner.svelte already does this with w-56.
src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte Standard shadcn DropdownMenuItem wrapper; styles and prop forwarding are correct.

Sequence Diagram

sequenceDiagram
    participant U as User
    participant AC as AuthCorner
    participant DM as DropdownMenu (bits-ui)
    participant F as Sign-out Form
    participant S as /sign-out endpoint

    U->>AC: View sidebar (userId present)
    AC->>AC: Derive initials from email/userId
    AC-->>U: Render avatar trigger button

    U->>DM: Click avatar button
    DM-->>U: Open dropdown (email label + Sign out item)

    note over U,DM: Mouse path (works)
    U->>F: Click button directly (mouse)
    F->>S: POST /sign-out
    S-->>U: Redirect / session cleared

    note over U,DM: Keyboard path (broken)
    U->>DM: Navigate to Sign out item (arrow keys)
    U->>DM: Press Enter
    DM->>DM: Dispatches click() on item div
    DM--xF: click does NOT propagate to child button
    note over F: Form never submitted
Loading

Fix All in Cursor Fix All in Codex

Reviews (1): Last reviewed commit: "Add account dropdown to auth corner with..." | Re-trigger Greptile

Comment on lines +38 to +47
<DropdownMenuItem class="p-0 focus:bg-transparent">
<form method="POST" action={resolve('/sign-out')} class="w-full">
<button
type="submit"
class="w-full rounded-md px-2 py-1.5 text-left text-xs hover:bg-accent hover:text-accent-foreground"
>
Sign out
</button>
</form>
</DropdownMenuItem>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Keyboard sign-out unreachable

DropdownMenuPrimitive.Item (rendered as a div[role="menuitem"]) handles keyboard activation (Enter/Space) by dispatching a synthetic click on itself — not on its child elements. Because the button[type="submit"] is a child, that synthetic click never reaches it, so the form is never submitted via keyboard. Mouse users work correctly because they click the button itself (which fills the item area via w-full), but keyboard-only users cannot sign out from this menu.

A common fix is to use the item's onSelect handler to programmatically submit the form, or to forward the activation directly to a button using the asChild prop if bits-ui supports it for Item.

Fix in Cursor Fix in Codex

<DropdownMenuLabel class="truncate font-normal">{email}</DropdownMenuLabel>
<DropdownMenuSeparator />
{/if}
<DropdownMenuItem class="p-0 focus:bg-transparent">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Focus indicator suppressed on sign-out item

focus:bg-transparent overrides the focus:bg-accent style provided by DropdownMenuPrimitive.Item, leaving the focused state visually indistinguishable from the unfocused state. Keyboard users navigating with arrow keys get no visual cue that "Sign out" is focused, which violates WCAG 2.4.7 (Focus Visible). The hover:bg-accent styles on the inner button are mouse-only and don't help here.

Fix in Cursor Fix in Codex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant