6.2 KiB
DASH-001: Tabbed Navigation System
Overview
Replace the current single-view dashboard with a proper tabbed interface. This is the foundation task that enables all other dashboard improvements.
Context
The current Noodl editor dashboard (projectsview.ts) uses a basic pane-switching mechanism with jQuery. A new launcher is being developed in packages/noodl-core-ui/src/preview/launcher/ using React, which already has a sidebar-based navigation but needs proper tab support for the main content area.
This task focuses on the new React-based launcher only. The old jQuery launcher will be deprecated.
Current State
Existing New Launcher Structure
packages/noodl-core-ui/src/preview/launcher/
├── Launcher/
│ ├── Launcher.tsx # Main component with PAGES array
│ ├── components/
│ │ ├── LauncherSidebar/ # Left navigation
│ │ ├── LauncherPage/ # Page wrapper
│ │ ├── LauncherProjectCard/
│ │ └── LauncherSearchBar/
│ └── views/
│ ├── Projects.tsx # Current projects view
│ └── LearningCenter.tsx # Empty learning view
└── template/
└── LauncherApp/ # App shell template
Current Page Definition
// In Launcher.tsx
export enum LauncherPageId {
LocalProjects,
LearningCenter
}
export const PAGES: LauncherPageMetaData[] = [
{ id: LauncherPageId.LocalProjects, displayName: 'Recent Projects', icon: IconName.CircleDot },
{ id: LauncherPageId.LearningCenter, displayName: 'Learn', icon: IconName.Rocket }
];
Requirements
Functional Requirements
-
Tab Bar Component
- Horizontal tab bar at the top of the main content area
- Visual indicator for active tab
- Smooth transition when switching tabs
- Keyboard navigation support (arrow keys, Enter)
-
Tab Configuration
- Projects tab (default, opens first)
- Learn tab (tutorials, guides)
- Templates tab (project starters)
- Extensible for future tabs (Marketplace, Settings)
-
State Persistence
- Remember last active tab across sessions
- Store in localStorage or electron-store
-
URL/Deep Linking (Optional)
- Support for
noodl://dashboard/projectsstyle deep links - Query params for tab state
- Support for
Non-Functional Requirements
- Tab switching should feel instant (<100ms)
- No layout shift when switching tabs
- Accessible (WCAG 2.1 AA compliant)
- Consistent with existing noodl-core-ui design system
Technical Approach
1. Create Tab Bar Component
Create a new component in noodl-core-ui that can be reused:
packages/noodl-core-ui/src/components/layout/TabBar/
├── TabBar.tsx
├── TabBar.module.scss
├── TabBar.stories.tsx
└── index.ts
2. Update Launcher Structure
// New page structure
export enum LauncherPageId {
Projects = 'projects',
Learn = 'learn',
Templates = 'templates'
}
export interface LauncherTab {
id: LauncherPageId;
label: string;
icon?: IconName;
component: React.ComponentType;
}
export const LAUNCHER_TABS: LauncherTab[] = [
{ id: LauncherPageId.Projects, label: 'Projects', icon: IconName.Folder, component: Projects },
{ id: LauncherPageId.Learn, label: 'Learn', icon: IconName.Book, component: LearningCenter },
{ id: LauncherPageId.Templates, label: 'Templates', icon: IconName.Components, component: Templates }
];
3. State Management
Use React context for tab state:
// LauncherContext.tsx
interface LauncherContextValue {
activeTab: LauncherPageId;
setActiveTab: (tab: LauncherPageId) => void;
}
4. Persistence Hook
// usePersistentTab.ts
function usePersistentTab(key: string, defaultTab: LauncherPageId) {
// Load from localStorage on mount
// Save to localStorage on change
}
Files to Create
packages/noodl-core-ui/src/components/layout/TabBar/TabBar.tsxpackages/noodl-core-ui/src/components/layout/TabBar/TabBar.module.scsspackages/noodl-core-ui/src/components/layout/TabBar/TabBar.stories.tsxpackages/noodl-core-ui/src/components/layout/TabBar/index.tspackages/noodl-core-ui/src/preview/launcher/Launcher/LauncherContext.tsxpackages/noodl-core-ui/src/preview/launcher/Launcher/hooks/usePersistentTab.tspackages/noodl-core-ui/src/preview/launcher/Launcher/views/Templates.tsx
Files to Modify
-
packages/noodl-core-ui/src/preview/launcher/Launcher/Launcher.tsx- Import and use TabBar
- Implement tab switching logic
- Wrap with LauncherContext
-
packages/noodl-core-ui/src/components/layout/index.ts- Export TabBar component
Implementation Steps
Phase 1: TabBar Component
- Create TabBar component with basic functionality
- Add styling consistent with noodl-core-ui
- Write Storybook stories for testing
- Add keyboard navigation
Phase 2: Launcher Integration
- Create LauncherContext
- Create usePersistentTab hook
- Integrate TabBar into Launcher.tsx
- Create empty Templates view
Phase 3: Polish
- Add tab transition animations
- Test accessibility
- Add deep link support (if time permits)
Testing Checklist
- Tabs render correctly
- Clicking tab switches content
- Active tab is visually indicated
- Keyboard navigation works (Tab, Arrow keys, Enter)
- Tab state persists after closing/reopening
- No layout shift on tab switch
- Works at different viewport sizes
- Screen reader announces tab changes
Design Reference
The tab bar should follow the existing Tabs component style in noodl-core-ui but be optimized for the launcher context (larger, more prominent).
See: packages/noodl-core-ui/src/components/layout/Tabs/
Dependencies
- None (this is a foundation task)
Blocked By
- None
Blocks
- DASH-002 (Project List Redesign)
- DASH-003 (Project Organization)
- DASH-004 (Tutorial Section Redesign)
Estimated Effort
- Component creation: 2-3 hours
- Launcher integration: 2-3 hours
- Polish and testing: 1-2 hours
- Total: 5-8 hours
Success Criteria
- User can switch between Projects, Learn, and Templates tabs
- Tab state persists across sessions
- Component is reusable for other contexts
- Passes accessibility audit
- Matches existing design system aesthetics