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:
Dorian
2026-03-04 07:09:31 +00:00
co-authored by Claude Opus 4.6
parent 486fc39249
commit 7b044d22ef
17 changed files with 1108 additions and 103 deletions
+78
View File
@@ -0,0 +1,78 @@
<template>
<div
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5 mb-8 transition-opacity duration-300"
:class="{ 'opacity-0 pointer-events-none': !show }"
>
<RouterLink
v-for="(goal, idx) in goals"
:key="goal.id"
:to="`/dashboard/goals/${goal.id}`"
class="goal-card glass-card p-6 block"
:class="{ 'home-card-animate': animate }"
:style="{ '--card-stagger': idx }"
>
<div class="flex items-start justify-between mb-4">
<div class="w-10 h-10 rounded-xl bg-white/10 flex items-center justify-center shrink-0">
<span class="text-xl">{{ goalIcon(goal.icon) }}</span>
</div>
<span class="goal-status-badge" :class="statusBadgeClass(goal.id)">
<span v-if="goalStatuses[goal.id] === 'completed'" class="w-1.5 h-1.5 rounded-full bg-green-400"></span>
<span v-else-if="goalStatuses[goal.id] === 'in-progress'" class="w-1.5 h-1.5 rounded-full bg-orange-400"></span>
{{ statusLabel(goal.id) }}
</span>
</div>
<h3 class="text-lg font-semibold text-white mb-1">{{ goal.title }}</h3>
<p class="text-sm text-white/55 mb-4 leading-relaxed">{{ goal.subtitle }}</p>
<div class="flex items-center justify-between">
<span class="text-xs text-white/40">{{ goal.estimatedTime }}</span>
<span class="text-xs text-white/50 flex items-center gap-1">
{{ goal.difficulty === 'beginner' ? 'Beginner' : 'Intermediate' }}
</span>
</div>
</RouterLink>
</div>
</template>
<script setup lang="ts">
import { RouterLink } from 'vue-router'
import { GOALS } from '@/data/goals'
import { useGoalStore } from '@/stores/goals'
defineProps<{
show: boolean
animate: boolean
}>()
const goalStore = useGoalStore()
const goals = GOALS
const goalStatuses = goalStore.goalStatuses
function goalIcon(icon: string): string {
const icons: Record<string, string> = {
shop: '🏪',
payments: '⚡',
photos: '📸',
files: '📁',
lightning: '⚡',
identity: '🔑',
backup: '💾',
}
return icons[icon] || '📦'
}
function statusLabel(goalId: string): string {
const status = goalStatuses[goalId]
if (status === 'completed') return 'Done'
if (status === 'in-progress') return 'In Progress'
return 'Start'
}
function statusBadgeClass(goalId: string): string {
const status = goalStatuses[goalId]
if (status === 'completed') return 'goal-status-badge-completed'
if (status === 'in-progress') return 'goal-status-badge-in-progress'
return 'goal-status-badge-not-started'
}
</script>
+26
View File
@@ -0,0 +1,26 @@
<template>
<div class="mode-switcher">
<button
v-for="m in modes"
:key="m.id"
@click="uiMode.setMode(m.id)"
class="mode-switcher-btn"
:class="{ 'mode-switcher-btn-active': uiMode.mode === m.id }"
>
{{ m.label }}
</button>
</div>
</template>
<script setup lang="ts">
import { useUIModeStore } from '@/stores/uiMode'
import type { UIMode } from '@/types/api'
const uiMode = useUIModeStore()
const modes: { id: UIMode; label: string }[] = [
{ id: 'easy', label: 'Easy' },
{ id: 'gamer', label: 'Pro' },
{ id: 'chat', label: 'Chat' },
]
</script>
+1 -1
View File
@@ -237,7 +237,7 @@ function selectHelpItem(section: { id: string }, item: { id: string; label: stri
}
}
function selectRecent(item: { id: string; label: string; path?: string; type: 'navigate' | 'learn' | 'action' }) {
function selectRecent(item: { id: string; label: string; path?: string; type: 'navigate' | 'learn' | 'action' | 'goal' }) {
spotlightStore.close()
if (item.path === '__cli__') {
cliStore.open()