refactor(projects): SegmentedControl, EmptyState, typed icons

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Vadym Samoilenko 2026-05-13 11:12:53 +01:00
parent 13c262184a
commit fd49ad9865

View file

@ -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 -->