// 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; 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( 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;