Workspace and account menu
The Agency name at the top of the sidebar. It opens one menu: who you are signed in as, the Agencies you can switch to, settings, bug reports and sign out.
Playground
Press the Agency name, then change the controls. The code under the preview lists only the props you changed.
import { WorkspaceMenu } from '@/ui/workspace-menu';<WorkspaceMenu email="priya@northbridge.co" settingsHref="#settings" />Owner in two Agencies
Always the first row of the sidebar: the Ascern mark, the Agency name at 600 and an up-down caret. The 260px menu opens below it. The email is a label, not an item. Agencies list only when you belong to more than one; the current one carries a check, and the others keep its 16px slot so names line up. Your role sits right of each name.
import { toast } from '@/ui/toast';
import { WorkspaceMenu } from '@/ui/workspace-menu';
// An Owner in two Agencies. The current one carries the check; switching is a link.
export default function WorkspaceMenuDefault() {
return (
<div className="w-60">
<WorkspaceMenu
email="priya@northbridge.co"
currentId="northbridge"
agencies={[
{ id: 'northbridge', name: 'Northbridge Talent', role: 'Owner', href: '#northbridge' },
{ id: 'halcyon', name: 'Halcyon Search', role: 'Recruiter', href: '#halcyon' },
]}
settingsHref="#settings"
accountHref="#account"
onReportBug={() => toast.add({ title: 'The bug report form opens here' })}
onSignOut={() => toast.add({ title: 'Signed out' })}
/>
</div>
);
}Recruiter in one Agency, and when things go wrong
No Agency list. Agency settings stays in the menu, disabled, with the reason, so the menu never changes shape between people. Long names and emails cut off with an ellipsis. Here Sign out and Report a bug fail, and the error toast says what to do next.
import { toast } from '@/ui/toast';
import { WorkspaceMenu } from '@/ui/workspace-menu';
// A Recruiter in one Agency: no Agency list, and Agency settings stays in place, disabled, with the reason. Sign out
// fails here, and the error toast says what to do next.
export default function WorkspaceMenuRecruiter() {
return (
<div className="w-60">
<WorkspaceMenu
email="tom.lindqvist-montgomery@northbridge-talent-partners.co"
currentId="northbridge"
agencies={[{ id: 'northbridge', name: 'Northbridge Talent Partners International', role: 'Recruiter', href: '#northbridge' }]}
accountHref="#account"
onReportBug={() => toast.add({ type: 'error', title: 'Bug reports aren’t set up here.', description: 'Email support@ascern.io instead.' })}
onSignOut={() => toast.add({ type: 'error', title: 'Couldn’t sign out.', description: 'Check your connection and try again.' })}
/>
</div>
);
}Account row
The foot of the sidebar shows who is signed in: the 24px avatar and your name. It is a label, not a button. On the folded rail only the avatar shows.
import { AccountRow } from '@/ui/workspace-menu';
// The foot of the sidebar: who is signed in. On the folded rail only the avatar shows.
export default function WorkspaceMenuAccountRow() {
return (
<div className="flex items-center gap-300">
<div className="w-60">
<AccountRow name="Priya Shah" />
</div>
<AccountRow name="Priya Shah" folded />
</div>
);
}Motion
The menu uses the Popup motion. Press Replay to close and open it again.
import { useState } from 'react';
import { Button } from '@/ui/button';
import { WorkspaceMenu } from '@/ui/workspace-menu';
// Replay closes the menu, then opens it again, so the 120ms exit and the 160ms entry run back to back.
export default function WorkspaceMenuMotion() {
const [open, setOpen] = useState(false);
const replay = () => {
setOpen(false);
setTimeout(() => setOpen(true), 400);
};
return (
<div className="flex items-start gap-150">
<div className="w-60">
<WorkspaceMenu
email="priya@northbridge.co"
currentId="northbridge"
agencies={[{ id: 'northbridge', name: 'Northbridge Talent', role: 'Owner', href: '#northbridge' }]}
settingsHref="#settings"
accountHref="#account"
onReportBug={() => {}}
onSignOut={() => {}}
open={open}
onOpenChange={setOpen}
modal={false}
/>
</div>
<Button variant="ghost" onClick={replay}>
Replay
</Button>
</div>
);
}