feat: implement three-mode UI system (Easy / Pro / Chat)
Add switchable UI modes with conditional rendering: - Easy mode: goal-based interface with 7 guided workflows - Pro mode: current technical interface preserved with Quick Start Goals - Chat mode: AIUI placeholder for future integration New components: ModeSwitcher, EasyHome, GoalDetail wizard, Chat placeholder New stores: uiMode (mode persistence), goals (progress tracking) New data: goal definitions catalog, helpTree goals section Modified: Dashboard (reactive nav), Home (mode dispatcher), Settings (mode picker), Router (goal/chat routes), Spotlight (goal search integration) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
486fc39249
commit
7b044d22ef
@@ -82,7 +82,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-nav flex-1 min-h-0 space-y-2 p-6 pt-4">
|
||||
<div class="px-6 pt-4 pb-2 shrink-0">
|
||||
<ModeSwitcher />
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-nav flex-1 min-h-0 space-y-2 p-6 pt-2">
|
||||
<RouterLink
|
||||
v-for="(item, idx) in desktopNavItems"
|
||||
:key="item.path"
|
||||
@@ -315,8 +319,12 @@ import { useLoginTransitionStore } from '../stores/loginTransition'
|
||||
import AnimatedLogo from '@/components/AnimatedLogo.vue'
|
||||
import OnlineStatusPill from '@/components/OnlineStatusPill.vue'
|
||||
import ControllerIndicator from '@/components/ControllerIndicator.vue'
|
||||
import ModeSwitcher from '@/components/ModeSwitcher.vue'
|
||||
import { useUIModeStore } from '@/stores/uiMode'
|
||||
import { playDashboardLoadOomph } from '@/composables/useLoginSounds'
|
||||
|
||||
const uiMode = useUIModeStore()
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const store = useAppStore()
|
||||
@@ -517,76 +525,70 @@ const isOffline = computed(() => store.isOffline)
|
||||
const isRestarting = computed(() => store.isRestarting)
|
||||
const isShuttingDown = computed(() => store.isShuttingDown)
|
||||
|
||||
// Desktop navigation items
|
||||
const desktopNavItems = [
|
||||
{
|
||||
path: '/dashboard',
|
||||
label: 'Home',
|
||||
icon: 'home',
|
||||
},
|
||||
{
|
||||
path: '/dashboard/apps',
|
||||
label: 'My Apps',
|
||||
icon: 'apps',
|
||||
},
|
||||
{
|
||||
path: '/dashboard/marketplace',
|
||||
label: 'App Store',
|
||||
icon: 'marketplace',
|
||||
},
|
||||
{
|
||||
path: '/dashboard/cloud',
|
||||
label: 'Cloud',
|
||||
icon: 'cloud',
|
||||
},
|
||||
{
|
||||
path: '/dashboard/server',
|
||||
label: 'Network',
|
||||
icon: 'server',
|
||||
},
|
||||
{
|
||||
path: '/dashboard/web5',
|
||||
label: 'Web5',
|
||||
icon: 'web5',
|
||||
},
|
||||
{
|
||||
path: '/dashboard/settings',
|
||||
label: 'Settings',
|
||||
icon: 'settings',
|
||||
},
|
||||
// Navigation items — reactive based on UI mode
|
||||
interface NavItem {
|
||||
path: string
|
||||
label: string
|
||||
icon: string
|
||||
isCombined?: boolean
|
||||
}
|
||||
|
||||
const gamerDesktopNav: NavItem[] = [
|
||||
{ path: '/dashboard', label: 'Home', icon: 'home' },
|
||||
{ path: '/dashboard/apps', label: 'My Apps', icon: 'apps' },
|
||||
{ path: '/dashboard/marketplace', label: 'App Store', icon: 'marketplace' },
|
||||
{ path: '/dashboard/cloud', label: 'Cloud', icon: 'cloud' },
|
||||
{ path: '/dashboard/server', label: 'Network', icon: 'server' },
|
||||
{ path: '/dashboard/web5', label: 'Web5', icon: 'web5' },
|
||||
{ path: '/dashboard/settings', label: 'Settings', icon: 'settings' },
|
||||
]
|
||||
|
||||
// Mobile navigation items (Apps and App Store combined)
|
||||
const mobileNavItems = [
|
||||
{
|
||||
path: '/dashboard',
|
||||
label: 'Home',
|
||||
icon: 'home',
|
||||
},
|
||||
{
|
||||
path: '/dashboard/apps',
|
||||
label: 'Apps',
|
||||
icon: 'apps',
|
||||
isCombined: true, // This combines apps and marketplace
|
||||
},
|
||||
{
|
||||
path: '/dashboard/cloud',
|
||||
label: 'Network',
|
||||
icon: 'server',
|
||||
isCombined: true, // This combines server and cloud
|
||||
},
|
||||
{
|
||||
path: '/dashboard/web5',
|
||||
label: 'Web5',
|
||||
icon: 'web5',
|
||||
},
|
||||
{
|
||||
path: '/dashboard/settings',
|
||||
label: 'Settings',
|
||||
icon: 'settings',
|
||||
},
|
||||
const easyDesktopNav: NavItem[] = [
|
||||
{ path: '/dashboard', label: 'Home', icon: 'home' },
|
||||
{ path: '/dashboard/apps', label: 'My Services', icon: 'apps' },
|
||||
{ path: '/dashboard/settings', label: 'Settings', icon: 'settings' },
|
||||
]
|
||||
|
||||
const chatDesktopNav: NavItem[] = [
|
||||
{ path: '/dashboard', label: 'Home', icon: 'home' },
|
||||
{ path: '/dashboard/chat', label: 'Chat', icon: 'chat' },
|
||||
{ path: '/dashboard/apps', label: 'My Apps', icon: 'apps' },
|
||||
{ path: '/dashboard/settings', label: 'Settings', icon: 'settings' },
|
||||
]
|
||||
|
||||
const desktopNavItems = computed(() => {
|
||||
if (uiMode.isEasy) return easyDesktopNav
|
||||
if (uiMode.isChat) return chatDesktopNav
|
||||
return gamerDesktopNav
|
||||
})
|
||||
|
||||
const gamerMobileNav: NavItem[] = [
|
||||
{ path: '/dashboard', label: 'Home', icon: 'home' },
|
||||
{ path: '/dashboard/apps', label: 'Apps', icon: 'apps', isCombined: true },
|
||||
{ path: '/dashboard/cloud', label: 'Network', icon: 'server', isCombined: true },
|
||||
{ path: '/dashboard/web5', label: 'Web5', icon: 'web5' },
|
||||
{ path: '/dashboard/settings', label: 'Settings', icon: 'settings' },
|
||||
]
|
||||
|
||||
const easyMobileNav: NavItem[] = [
|
||||
{ path: '/dashboard', label: 'Home', icon: 'home' },
|
||||
{ path: '/dashboard/apps', label: 'Services', icon: 'apps' },
|
||||
{ path: '/dashboard/settings', label: 'Settings', icon: 'settings' },
|
||||
]
|
||||
|
||||
const chatMobileNav: NavItem[] = [
|
||||
{ path: '/dashboard', label: 'Home', icon: 'home' },
|
||||
{ path: '/dashboard/chat', label: 'Chat', icon: 'chat' },
|
||||
{ path: '/dashboard/apps', label: 'Apps', icon: 'apps' },
|
||||
{ path: '/dashboard/settings', label: 'Settings', icon: 'settings' },
|
||||
]
|
||||
|
||||
const mobileNavItems = computed(() => {
|
||||
if (uiMode.isEasy) return easyMobileNav
|
||||
if (uiMode.isChat) return chatMobileNav
|
||||
return gamerMobileNav
|
||||
})
|
||||
|
||||
function getIconPath(iconName: string): string[] {
|
||||
const icons: Record<string, string[]> = {
|
||||
home: ['M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6'],
|
||||
@@ -595,6 +597,7 @@ function getIconPath(iconName: string): string[] {
|
||||
cloud: ['M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z'],
|
||||
server: ['M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01'],
|
||||
web5: ['M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9'],
|
||||
chat: ['M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z'],
|
||||
settings: [
|
||||
'M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z',
|
||||
'M15 12a3 3 0 11-6 0 3 3 0 016 0z',
|
||||
|
||||
Reference in New Issue
Block a user