723 lines
18 KiB
TypeScript
723 lines
18 KiB
TypeScript
// Path: Frontend/src/components/shell/data/shell.data.ts
|
|
|
|
import type { Component } from "solid-js";
|
|
import {
|
|
Bell,
|
|
CircleHelp,
|
|
FileText,
|
|
Folder,
|
|
Home,
|
|
Keyboard,
|
|
LayoutGrid,
|
|
LogOut,
|
|
Repeat,
|
|
Search,
|
|
Settings,
|
|
Shield,
|
|
User,
|
|
} from "../../../lib/icons";
|
|
|
|
type ShellIconProps = {
|
|
class?: string;
|
|
size?: number;
|
|
strokeWidth?: number;
|
|
};
|
|
|
|
export type ShellIcon = Component<ShellIconProps>;
|
|
|
|
export type RailItem = {
|
|
id: string;
|
|
label: string;
|
|
abbreviation: string;
|
|
kind: "personal" | "organization";
|
|
active?: boolean;
|
|
};
|
|
|
|
export type ServerDockAction = {
|
|
id: string;
|
|
label: string;
|
|
icon: ShellIcon;
|
|
};
|
|
|
|
export type ActiveServer = {
|
|
id: string;
|
|
name: string;
|
|
abbreviation: string;
|
|
kind: "personal" | "organization";
|
|
connectedLabel?: string;
|
|
subtitle?: string;
|
|
dockActions: readonly ServerDockAction[];
|
|
};
|
|
|
|
export type ActiveProject = {
|
|
id: string;
|
|
name: string;
|
|
};
|
|
|
|
export type ActiveDepartment = {
|
|
id: string;
|
|
name: string;
|
|
teamName: string;
|
|
};
|
|
|
|
export type DepartmentItem = {
|
|
id: string;
|
|
name: string;
|
|
teams: readonly string[];
|
|
active?: boolean;
|
|
};
|
|
|
|
export type ProjectItem = {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
groupLabel?: string;
|
|
parentLabel?: string;
|
|
meta?: string;
|
|
active?: boolean;
|
|
};
|
|
|
|
export type ProjectMenuTarget =
|
|
| {
|
|
id: string;
|
|
label: string;
|
|
kind: "surface";
|
|
}
|
|
| {
|
|
id: string;
|
|
label: string;
|
|
kind: "folder";
|
|
}
|
|
| {
|
|
id: string;
|
|
label: string;
|
|
kind: "project";
|
|
};
|
|
|
|
export type ProjectContextMenuAction = {
|
|
id: string;
|
|
label: string;
|
|
tone?: "default" | "danger";
|
|
shortcut?: WorkspaceContextMenuShortcut;
|
|
children?: readonly ProjectContextMenuAction[];
|
|
};
|
|
|
|
export type ProjectContextMenuSection = {
|
|
id: string;
|
|
label?: string;
|
|
items: readonly ProjectContextMenuAction[];
|
|
};
|
|
|
|
export type SidebarItem = {
|
|
id: string;
|
|
label: string;
|
|
icon: ShellIcon;
|
|
active?: boolean;
|
|
meta?: string;
|
|
};
|
|
|
|
export type WorkspaceStaticKind = "workspace" | "home" | "settings";
|
|
|
|
// Keep this open-ended so future server-driven or plugin-provided item types do
|
|
// not require a frontend source edit before they can be represented safely.
|
|
export type WorkspaceItemTypeId = string;
|
|
|
|
export type WorkspaceStaticItem = SidebarItem & {
|
|
contextKind: WorkspaceStaticKind;
|
|
};
|
|
|
|
export type WorkspaceFolderNode = {
|
|
id: string;
|
|
label: string;
|
|
kind: "folder";
|
|
icon: ShellIcon;
|
|
active?: boolean;
|
|
meta?: string;
|
|
children?: readonly WorkspaceTreeNode[];
|
|
};
|
|
|
|
export type WorkspaceItemNode = {
|
|
id: string;
|
|
label: string;
|
|
kind: "item";
|
|
itemType: WorkspaceItemTypeId;
|
|
active?: boolean;
|
|
meta?: string;
|
|
children?: undefined;
|
|
};
|
|
|
|
export type WorkspaceTreeNode = WorkspaceFolderNode | WorkspaceItemNode;
|
|
|
|
export type WorkspaceItemTypeDefinition = {
|
|
id: WorkspaceItemTypeId;
|
|
label: string;
|
|
shortLabel: string;
|
|
icon: ShellIcon;
|
|
noun: string;
|
|
actionPrefix: string;
|
|
defaultCreateLabel: string;
|
|
includeInWorkspaceCreate?: boolean;
|
|
description?: string;
|
|
};
|
|
|
|
export type SidebarHeaderAction = {
|
|
id: string;
|
|
label: string;
|
|
icon: ShellIcon;
|
|
};
|
|
|
|
export type TopBarAction = {
|
|
id: string;
|
|
label: string;
|
|
icon: ShellIcon;
|
|
};
|
|
|
|
export type MobileBottomNavItem = {
|
|
id: string;
|
|
label: string;
|
|
icon: ShellIcon;
|
|
active?: boolean;
|
|
};
|
|
|
|
export type WorkspaceContextMenuTarget =
|
|
| {
|
|
id: string;
|
|
label: string;
|
|
kind: WorkspaceStaticKind;
|
|
}
|
|
| {
|
|
id: string;
|
|
label: string;
|
|
kind: "folder";
|
|
}
|
|
| {
|
|
id: string;
|
|
label: string;
|
|
kind: "item";
|
|
itemType: WorkspaceItemTypeId;
|
|
};
|
|
|
|
export type WorkspaceContextMenuAction = {
|
|
id: string;
|
|
label: string;
|
|
tone?: "default" | "danger";
|
|
shortcut?: WorkspaceContextMenuShortcut;
|
|
children?: readonly WorkspaceContextMenuAction[];
|
|
};
|
|
|
|
export type WorkspaceContextMenuShortcutModifier = "meta" | "alt" | "shift";
|
|
|
|
export type WorkspaceContextMenuShortcutKey = "b" | "c" | "d" | "delete" | "enter" | "f" | "m" | "r";
|
|
|
|
export type WorkspaceContextMenuShortcut = {
|
|
modifiers?: readonly WorkspaceContextMenuShortcutModifier[];
|
|
key: WorkspaceContextMenuShortcutKey;
|
|
};
|
|
|
|
export type WorkspaceContextMenuSection = {
|
|
id: string;
|
|
label?: string;
|
|
items: readonly WorkspaceContextMenuAction[];
|
|
};
|
|
|
|
export const firstPartyWorkspaceItemTypes: readonly WorkspaceItemTypeDefinition[] = [
|
|
{
|
|
id: "core.doc",
|
|
label: "Doc",
|
|
shortLabel: "Doc",
|
|
icon: FileText,
|
|
noun: "doc",
|
|
actionPrefix: "doc",
|
|
defaultCreateLabel: "New doc",
|
|
includeInWorkspaceCreate: true,
|
|
description: "Rich text documents and notes.",
|
|
},
|
|
{
|
|
id: "core.board.kanban",
|
|
label: "Kanban board",
|
|
shortLabel: "Board",
|
|
icon: LayoutGrid,
|
|
noun: "board",
|
|
actionPrefix: "board",
|
|
defaultCreateLabel: "New board",
|
|
includeInWorkspaceCreate: true,
|
|
description: "Default board-style workspace item.",
|
|
},
|
|
{
|
|
id: "core.board.list",
|
|
label: "List board",
|
|
shortLabel: "Board",
|
|
icon: LayoutGrid,
|
|
noun: "board",
|
|
actionPrefix: "list-board",
|
|
defaultCreateLabel: "New list board",
|
|
description: "Alternate first-party board view prepared for the future registry.",
|
|
},
|
|
] as const;
|
|
|
|
const workspaceItemTypeMap = new Map<WorkspaceItemTypeId, WorkspaceItemTypeDefinition>(
|
|
firstPartyWorkspaceItemTypes.map((definition) => [definition.id, definition]),
|
|
);
|
|
|
|
const createUnknownWorkspaceItemTypeDefinition = (
|
|
itemType: WorkspaceItemTypeId,
|
|
): WorkspaceItemTypeDefinition => ({
|
|
id: itemType,
|
|
label: "Item",
|
|
shortLabel: "Item",
|
|
icon: FileText,
|
|
noun: "item",
|
|
actionPrefix: "item",
|
|
defaultCreateLabel: "New item",
|
|
description: "Fallback definition for unknown or future workspace item types.",
|
|
});
|
|
|
|
export const getWorkspaceItemTypeDefinition = (itemType: WorkspaceItemTypeId): WorkspaceItemTypeDefinition => {
|
|
return workspaceItemTypeMap.get(itemType) ?? createUnknownWorkspaceItemTypeDefinition(itemType);
|
|
};
|
|
|
|
export const getWorkspaceNodeIcon = (node: WorkspaceTreeNode): ShellIcon =>
|
|
node.kind === "folder" ? node.icon : getWorkspaceItemTypeDefinition(node.itemType).icon;
|
|
|
|
const getWorkspaceCreateActions = (): readonly WorkspaceContextMenuAction[] => [
|
|
{ id: "new-folder", label: "New folder", shortcut: { modifiers: ["alt"], key: "f" } },
|
|
...firstPartyWorkspaceItemTypes
|
|
.filter((definition) => definition.includeInWorkspaceCreate)
|
|
.map((definition) => ({
|
|
id: `create-${definition.actionPrefix}`,
|
|
label: definition.defaultCreateLabel,
|
|
shortcut:
|
|
definition.id === "core.board.kanban"
|
|
? ({ modifiers: ["alt"], key: "b" } as const)
|
|
: definition.id === "core.doc"
|
|
? ({ modifiers: ["alt"], key: "d" } as const)
|
|
: undefined,
|
|
})),
|
|
];
|
|
|
|
export const getWorkspaceContextMenuEyebrow = (target: WorkspaceContextMenuTarget): string => {
|
|
switch (target.kind) {
|
|
case "workspace":
|
|
case "home":
|
|
return "Workspace";
|
|
case "settings":
|
|
return "Configuration";
|
|
case "folder":
|
|
return "Folder";
|
|
case "item":
|
|
return getWorkspaceItemTypeDefinition(target.itemType).shortLabel;
|
|
}
|
|
};
|
|
|
|
export const createWorkspaceSurfaceTarget = (workspace: ActiveProject): WorkspaceContextMenuTarget => ({
|
|
id: `workspace-${workspace.id}`,
|
|
label: workspace.name,
|
|
kind: "workspace",
|
|
});
|
|
|
|
export const createWorkspaceStaticTarget = (item: WorkspaceStaticItem): WorkspaceContextMenuTarget => ({
|
|
id: item.id,
|
|
label: item.label,
|
|
kind: item.contextKind,
|
|
});
|
|
|
|
export const createWorkspaceTreeTarget = (node: WorkspaceTreeNode): WorkspaceContextMenuTarget => ({
|
|
id: node.id,
|
|
label: node.label,
|
|
...(node.kind === "folder"
|
|
? { kind: "folder" as const }
|
|
: {
|
|
kind: "item" as const,
|
|
itemType: node.itemType,
|
|
}),
|
|
});
|
|
|
|
export type NotificationItem = {
|
|
id: string;
|
|
title: string;
|
|
contextLabel: string;
|
|
timeLabel: string;
|
|
unread?: boolean;
|
|
};
|
|
|
|
export type ProfileMenuAction = {
|
|
id: string;
|
|
label: string;
|
|
icon: ShellIcon;
|
|
tone?: "default" | "danger";
|
|
};
|
|
|
|
export type ProfileMenuSection = {
|
|
id: string;
|
|
items: readonly ProfileMenuAction[];
|
|
};
|
|
|
|
export type ActiveUserProfile = {
|
|
name: string;
|
|
email: string;
|
|
roleLabel: string;
|
|
contextLabel: string;
|
|
};
|
|
|
|
export const personalDockActions: readonly ServerDockAction[] = [
|
|
{ id: "account", label: "Account", icon: User },
|
|
{ id: "settings", label: "Settings", icon: Settings },
|
|
] as const;
|
|
|
|
export const organizationAdminDockActions: readonly ServerDockAction[] = [
|
|
{ id: "members", label: "Members", icon: User },
|
|
{ id: "server", label: "Server", icon: Settings },
|
|
] as const;
|
|
|
|
// Server shell scaffold data
|
|
export const railItems: readonly RailItem[] = [
|
|
{ id: "personal-server", label: "Personal Server Name", abbreviation: "P", kind: "personal" },
|
|
{ id: "organization-server", label: "Organization Name", abbreviation: "O", kind: "organization", active: true },
|
|
{ id: "design-review", label: "Design Review", abbreviation: "D", kind: "organization" },
|
|
] as const;
|
|
|
|
export const activeServer: ActiveServer = {
|
|
id: "organization-server",
|
|
name: "Organization Name",
|
|
abbreviation: "O",
|
|
kind: "organization",
|
|
connectedLabel: "12 connected",
|
|
dockActions: organizationAdminDockActions,
|
|
};
|
|
|
|
// Workspace framing scaffold data
|
|
export const activeProject: ActiveProject = {
|
|
id: "general",
|
|
name: "General",
|
|
};
|
|
|
|
export const activeDepartment: ActiveDepartment = {
|
|
id: "product",
|
|
name: "Product",
|
|
teamName: "Design Systems",
|
|
};
|
|
|
|
export const projectItems: readonly ProjectItem[] = [
|
|
{
|
|
id: "general",
|
|
name: "General",
|
|
description: "Default shared project",
|
|
groupLabel: "Shared space",
|
|
parentLabel: "Workspace home",
|
|
meta: "1 workspace",
|
|
active: true,
|
|
},
|
|
{
|
|
id: "operations",
|
|
name: "Operations",
|
|
description: "Cross-team planning and delivery",
|
|
groupLabel: "Team folders",
|
|
parentLabel: "Shared Services",
|
|
meta: "2 workspaces",
|
|
},
|
|
{
|
|
id: "hiring",
|
|
name: "Hiring",
|
|
description: "Candidate pipeline and interview loops",
|
|
groupLabel: "Team folders",
|
|
parentLabel: "People Ops",
|
|
meta: "1 workspace",
|
|
},
|
|
] as const;
|
|
|
|
export const departmentItems: readonly DepartmentItem[] = [
|
|
{ id: "product", name: "Product", teams: ["Design Systems", "Research Ops"], active: true },
|
|
{ id: "engineering", name: "Engineering", teams: ["Platform", "Realtime Collaboration"] },
|
|
{ id: "operations", name: "Operations", teams: ["Shared Services", "People Ops"] },
|
|
] as const;
|
|
|
|
// Sidebar and topbar scaffold data
|
|
// These static entries stay pinned in both desktop and mobile workspace navigation.
|
|
export const workspaceStaticItems: readonly WorkspaceStaticItem[] = [
|
|
{ id: "home", label: "Home", icon: Home, active: true, contextKind: "home" },
|
|
{ id: "workspace-settings", label: "Settings", icon: Settings, contextKind: "settings" },
|
|
] as const;
|
|
|
|
// Freeform workspace tree scaffold: folders are structural, while non-folder
|
|
// nodes already flow through the future-safe itemType registry seam.
|
|
export const workspaceTree: readonly WorkspaceTreeNode[] = [
|
|
{
|
|
id: "product-workspace",
|
|
label: "Product",
|
|
kind: "folder",
|
|
icon: Folder,
|
|
children: [
|
|
{ id: "roadmap-board", label: "Roadmap", kind: "item", itemType: "core.board.kanban", active: true },
|
|
{ id: "launch-brief", label: "Launch Brief", kind: "item", itemType: "core.doc" },
|
|
{
|
|
id: "research-folder",
|
|
label: "Research",
|
|
kind: "folder",
|
|
icon: Folder,
|
|
children: [
|
|
{ id: "interviews-doc", label: "Interviews", kind: "item", itemType: "core.doc" },
|
|
{ id: "signals-board", label: "Signals", kind: "item", itemType: "core.board.kanban", meta: "2" },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: "design-folder",
|
|
label: "Design",
|
|
kind: "folder",
|
|
icon: Folder,
|
|
children: [
|
|
{ id: "system-doc", label: "Design System", kind: "item", itemType: "core.doc" },
|
|
{ id: "review-board", label: "Review Queue", kind: "item", itemType: "core.board.kanban" },
|
|
],
|
|
},
|
|
{ id: "general-notes", label: "General Notes", kind: "item", itemType: "core.doc" },
|
|
] as const;
|
|
|
|
export const workspaceSidebarHeaderActions: readonly SidebarHeaderAction[] = [
|
|
{ id: "search-workspace", label: "Search workspace", icon: Search },
|
|
] as const;
|
|
|
|
export const mobileBottomNavItems: readonly MobileBottomNavItem[] = [
|
|
{ id: "home", label: "Home", icon: Home, active: true },
|
|
{ id: "search", label: "Search", icon: Search },
|
|
{ id: "browse", label: "Browse", icon: Folder },
|
|
] as const;
|
|
|
|
// Initial context-menu IA scaffold. Behavior wiring can evolve later, but the
|
|
// target kinds and action grouping should stay shared across workspace surfaces.
|
|
export const getWorkspaceContextMenuSections = (
|
|
target: WorkspaceContextMenuTarget,
|
|
): readonly WorkspaceContextMenuSection[] => {
|
|
const createActions = getWorkspaceCreateActions();
|
|
|
|
const createSubmenuAction = {
|
|
id: "create",
|
|
label: "Create",
|
|
children: createActions,
|
|
} as const;
|
|
|
|
switch (target.kind) {
|
|
case "workspace":
|
|
return [
|
|
{
|
|
id: "create",
|
|
label: undefined,
|
|
items: [createSubmenuAction],
|
|
},
|
|
{
|
|
id: "workspace",
|
|
label: undefined,
|
|
items: [
|
|
{ id: "rename-workspace", label: "Rename workspace", shortcut: { key: "enter" } },
|
|
{ id: "copy-workspace-link", label: "Copy link", shortcut: { modifiers: ["meta"], key: "c" } },
|
|
],
|
|
},
|
|
] as const;
|
|
case "home":
|
|
return [
|
|
{
|
|
id: "create",
|
|
label: undefined,
|
|
items: [createSubmenuAction],
|
|
},
|
|
{
|
|
id: "workspace",
|
|
label: undefined,
|
|
items: [{ id: "open-home", label: "Open home", shortcut: { key: "enter" } }],
|
|
},
|
|
] as const;
|
|
case "settings":
|
|
return [
|
|
{
|
|
id: "settings",
|
|
label: undefined,
|
|
items: [
|
|
{ id: "open-settings", label: "Open settings", shortcut: { key: "enter" } },
|
|
{ id: "copy-settings-link", label: "Copy link", shortcut: { modifiers: ["meta"], key: "c" } },
|
|
],
|
|
},
|
|
] as const;
|
|
case "folder":
|
|
return [
|
|
{
|
|
id: "open",
|
|
items: [
|
|
{ id: "open-folder", label: "Open folder", shortcut: { key: "enter" } },
|
|
{ id: "rename-folder", label: "Rename", shortcut: { modifiers: ["meta"], key: "r" } },
|
|
],
|
|
},
|
|
{
|
|
id: "create",
|
|
label: undefined,
|
|
items: [createSubmenuAction],
|
|
},
|
|
{
|
|
id: "organize",
|
|
label: undefined,
|
|
items: [
|
|
{ id: "duplicate-folder", label: "Duplicate", shortcut: { modifiers: ["meta"], key: "d" } },
|
|
{ id: "move-folder", label: "Move", shortcut: { modifiers: ["meta"], key: "m" } },
|
|
{ id: "delete-folder", label: "Delete", shortcut: { modifiers: ["meta"], key: "delete" }, tone: "danger" },
|
|
],
|
|
},
|
|
] as const;
|
|
case "item": {
|
|
const definition = getWorkspaceItemTypeDefinition(target.itemType);
|
|
const actionPrefix = definition.actionPrefix;
|
|
const nounLabel = definition.noun;
|
|
|
|
return [
|
|
{
|
|
id: `${actionPrefix}-primary`,
|
|
items: [
|
|
{ id: `open-${actionPrefix}`, label: `Open ${nounLabel}`, shortcut: { key: "enter" } },
|
|
{ id: `rename-${actionPrefix}`, label: "Rename", shortcut: { modifiers: ["meta"], key: "r" } },
|
|
],
|
|
},
|
|
{
|
|
id: "organize",
|
|
label: undefined,
|
|
items: [
|
|
{ id: `duplicate-${actionPrefix}`, label: "Duplicate", shortcut: { modifiers: ["meta"], key: "d" } },
|
|
{ id: `move-${actionPrefix}`, label: "Move", shortcut: { modifiers: ["meta"], key: "m" } },
|
|
{ id: `delete-${actionPrefix}`, label: "Delete", shortcut: { modifiers: ["meta"], key: "delete" }, tone: "danger" },
|
|
],
|
|
},
|
|
] as const;
|
|
}
|
|
}
|
|
};
|
|
|
|
const getProjectCreateActions = (): readonly ProjectContextMenuAction[] =>
|
|
[
|
|
{ id: "new-project", label: "New project" },
|
|
{ id: "new-folder", label: "New folder" },
|
|
] as const;
|
|
|
|
export const createProjectSurfaceTarget = (label = "Projects"): ProjectMenuTarget => ({
|
|
id: "project-surface",
|
|
label,
|
|
kind: "surface",
|
|
});
|
|
|
|
export const createProjectFolderTarget = (id: string, label: string): ProjectMenuTarget => ({
|
|
id,
|
|
label,
|
|
kind: "folder",
|
|
});
|
|
|
|
export const createProjectTarget = (project: ProjectItem): ProjectMenuTarget => ({
|
|
id: project.id,
|
|
label: project.name,
|
|
kind: "project",
|
|
});
|
|
|
|
export const getProjectContextMenuEyebrow = (target: ProjectMenuTarget): string => {
|
|
switch (target.kind) {
|
|
case "surface":
|
|
return "Projects";
|
|
case "folder":
|
|
return "Folder";
|
|
case "project":
|
|
return "Project";
|
|
}
|
|
};
|
|
|
|
export const getProjectContextMenuSections = (target: ProjectMenuTarget): readonly ProjectContextMenuSection[] => {
|
|
const createActions = getProjectCreateActions();
|
|
|
|
switch (target.kind) {
|
|
case "surface":
|
|
return [
|
|
{
|
|
id: "create",
|
|
items: createActions,
|
|
},
|
|
] as const;
|
|
case "folder":
|
|
return [
|
|
{
|
|
id: "create",
|
|
items: createActions,
|
|
},
|
|
] as const;
|
|
case "project":
|
|
return [
|
|
{
|
|
id: "create",
|
|
items: createActions,
|
|
},
|
|
] as const;
|
|
}
|
|
};
|
|
|
|
export const topBarActions: readonly TopBarAction[] = [
|
|
{ id: "search", label: "Search", icon: Search },
|
|
] as const;
|
|
|
|
export const notificationItems: readonly NotificationItem[] = [
|
|
{
|
|
id: "comment-design-systems",
|
|
title: "New comment on Design Systems",
|
|
contextLabel: "Product • Review thread updated",
|
|
timeLabel: "2m ago",
|
|
unread: true,
|
|
},
|
|
{
|
|
id: "sprint-platform",
|
|
title: "Sprint updated in Platform",
|
|
contextLabel: "Engineering • Scope changed",
|
|
timeLabel: "15m ago",
|
|
unread: true,
|
|
},
|
|
{
|
|
id: "member-joined",
|
|
title: "New member joined Operations",
|
|
contextLabel: "Organization Name • Access granted",
|
|
timeLabel: "1h ago",
|
|
},
|
|
{
|
|
id: "daily-summary",
|
|
title: "Daily summary is ready",
|
|
contextLabel: "General • 8 updates across boards",
|
|
timeLabel: "Today, 8:00 AM",
|
|
},
|
|
] as const;
|
|
|
|
export const unreadNotificationCount = notificationItems.filter((item) => item.unread).length;
|
|
|
|
export const activeUserProfile: ActiveUserProfile = {
|
|
name: "Demo Account",
|
|
email: "demo@moku.work",
|
|
roleLabel: "Founder · Product",
|
|
contextLabel: "Organization Name • Design Systems",
|
|
};
|
|
|
|
export const profileMenuSections: readonly ProfileMenuSection[] = [
|
|
{
|
|
id: "account",
|
|
items: [
|
|
{ id: "profile", label: "Profile", icon: User },
|
|
{ id: "account-settings", label: "Account Settings", icon: Settings },
|
|
{ id: "notifications", label: "Notifications", icon: Bell },
|
|
{ id: "security", label: "Security", icon: Shield },
|
|
],
|
|
},
|
|
{
|
|
id: "preferences",
|
|
items: [
|
|
{ id: "keyboard-shortcuts", label: "Keyboard Shortcuts", icon: Keyboard },
|
|
{ id: "theme-preferences", label: "Theme Preferences", icon: Settings },
|
|
{ id: "help-support", label: "Help & Support", icon: CircleHelp },
|
|
],
|
|
},
|
|
{
|
|
id: "session",
|
|
items: [
|
|
{ id: "switch-account", label: "Switch Account", icon: Repeat },
|
|
{ id: "sign-out", label: "Sign Out", icon: LogOut, tone: "danger" },
|
|
],
|
|
},
|
|
] as const;
|