refactor(projects): SegmentedControl, EmptyState, typed icons
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
13c262184a
commit
fd49ad9865
1 changed files with 21 additions and 33 deletions
|
|
@ -1,13 +1,16 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { ref, computed, onMounted, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { dashboardApi } from '@/api/endpoints/dashboard'
|
||||
import Card from '@/components/ui/Card.vue'
|
||||
import CardContent from '@/components/ui/CardContent.vue'
|
||||
import Progress from '@/components/ui/Progress.vue'
|
||||
import Spinner from '@/components/ui/Spinner.vue'
|
||||
import SegmentedControl from '@/components/ui/SegmentedControl.vue'
|
||||
import EmptyState from '@/components/ui/EmptyState.vue'
|
||||
import { formatDuration, formatDate } from '@/lib/utils'
|
||||
import type { ProjectSummary } from '@/types'
|
||||
import { LayoutGrid, List, FolderOpen, Code2, Zap } from 'lucide-vue-next'
|
||||
|
||||
const router = useRouter()
|
||||
const projects = ref<ProjectSummary[]>([])
|
||||
|
|
@ -16,10 +19,12 @@ const loading = ref(false)
|
|||
const savedView = localStorage.getItem('projects.view')
|
||||
const viewMode = ref<'grid' | 'list'>(savedView === 'list' ? 'list' : 'grid')
|
||||
|
||||
function setView(v: 'grid' | 'list') {
|
||||
viewMode.value = v
|
||||
localStorage.setItem('projects.view', v)
|
||||
}
|
||||
watch(viewMode, (v) => localStorage.setItem('projects.view', v))
|
||||
|
||||
const viewOptions = [
|
||||
{ value: 'grid', label: 'Grid', icon: LayoutGrid },
|
||||
{ value: 'list', label: 'List', icon: List },
|
||||
]
|
||||
|
||||
onMounted(async () => {
|
||||
loading.value = true
|
||||
|
|
@ -46,40 +51,23 @@ const progressColor = (pct: number | null) => {
|
|||
<h2 class="text-lg font-semibold text-foreground flex-1">Projects</h2>
|
||||
|
||||
<!-- View toggle -->
|
||||
<div class="flex items-center rounded-lg border border-border overflow-hidden bg-muted/30">
|
||||
<button
|
||||
:class="[
|
||||
'px-2.5 py-1.5 transition-colors',
|
||||
viewMode === 'grid' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:text-foreground hover:bg-muted/50',
|
||||
]"
|
||||
title="Grid view"
|
||||
@click="setView('grid')"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
:class="[
|
||||
'px-2.5 py-1.5 transition-colors',
|
||||
viewMode === 'list' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:text-foreground hover:bg-muted/50',
|
||||
]"
|
||||
title="List view"
|
||||
@click="setView('list')"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<SegmentedControl
|
||||
v-model="viewMode"
|
||||
:options="viewOptions"
|
||||
aria-label="View mode"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="loading" class="flex items-center justify-center h-40">
|
||||
<Spinner size="lg" class="text-primary" />
|
||||
</div>
|
||||
|
||||
<div v-else-if="projects.length === 0" class="text-center text-muted-foreground py-12">
|
||||
No projects found
|
||||
<div v-else-if="projects.length === 0" class="py-12">
|
||||
<EmptyState
|
||||
title="No projects yet"
|
||||
description="Start a Claude Code session to see your projects here."
|
||||
:icons="[FolderOpen, Code2, Zap]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Grid view -->
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue