kin: KIN-138-frontend_dev

This commit is contained in:
Gros Frumos 2026-03-21 08:52:40 +02:00
parent e1fe41c428
commit dadd97a5c5
3 changed files with 80 additions and 15 deletions

View file

@ -11,6 +11,16 @@ const projects = ref<Project[]>([])
const costs = ref<CostEntry[]>([])
const loading = ref(true)
const error = ref('')
const projectSearch = ref('')
const showNewMenu = ref(false)
const filteredProjects = computed(() => {
const q = projectSearch.value.trim().toLowerCase()
if (!q) return projects.value
return projects.value.filter(p =>
p.id.toLowerCase().includes(q) || p.name.toLowerCase().includes(q)
)
})
// Add project modal
const showAdd = ref(false)
@ -194,27 +204,39 @@ async function createNewProject() {
<h1 class="text-xl font-bold text-gray-100">{{ t('dashboard.title') }}</h1>
<p class="text-sm text-gray-500" v-if="totalCost > 0">{{ t('dashboard.cost_this_week') }}: ${{ totalCost.toFixed(2) }}</p>
</div>
<div class="flex gap-2">
<button @click="showBootstrap = true"
class="px-3 py-1.5 text-xs bg-purple-900/50 text-purple-400 border border-purple-800 rounded hover:bg-purple-900">
{{ t('dashboard.bootstrap') }}
</button>
<button @click="showNewProject = true"
class="px-3 py-1.5 text-xs bg-green-900/50 text-green-400 border border-green-800 rounded hover:bg-green-900">
{{ t('dashboard.new_project') }}
</button>
<button @click="showAdd = true"
class="px-3 py-1.5 text-xs bg-gray-800 text-gray-300 border border-gray-700 rounded hover:bg-gray-700">
{{ t('dashboard.blank') }}
<div class="relative">
<button @click="showNewMenu = !showNewMenu"
class="px-3 py-1.5 text-xs bg-gray-800 text-gray-300 border border-gray-700 rounded hover:bg-gray-700 flex items-center gap-1">
+ {{ t('dashboard.new_project') }}
</button>
<div v-if="showNewMenu" class="absolute right-0 top-full mt-1 bg-gray-900 border border-gray-700 rounded shadow-lg z-10 min-w-[170px]">
<button @click="showNewProject = true; showNewMenu = false"
class="w-full text-left px-3 py-2 text-xs text-green-400 hover:bg-gray-800">
🔬 {{ t('dashboard.new_project') }}
</button>
<button @click="showBootstrap = true; showNewMenu = false"
class="w-full text-left px-3 py-2 text-xs text-purple-400 hover:bg-gray-800">
🚀 {{ t('dashboard.bootstrap') }}
</button>
<button @click="showAdd = true; showNewMenu = false"
class="w-full text-left px-3 py-2 text-xs text-gray-400 hover:bg-gray-800">
📋 {{ t('dashboard.blank') }}
</button>
</div>
</div>
</div>
<div v-if="!loading && !error" class="mb-3">
<input v-model="projectSearch"
:placeholder="t('dashboard.search_placeholder', 'Search projects...')"
class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-1.5 text-sm text-gray-300 placeholder-gray-600 focus:border-gray-500 outline-none" />
</div>
<p v-if="loading" class="text-gray-500 text-sm">{{ t('dashboard.loading') }}</p>
<p v-else-if="error" class="text-red-400 text-sm">{{ error }}</p>
<div v-else class="grid gap-3">
<div v-for="p in projects" :key="p.id">
<div v-for="p in filteredProjects" :key="p.id">
<!-- Inline delete confirmation -->
<div v-if="confirmDeleteId === p.id"
class="border border-red-800 rounded-lg p-4 bg-red-950/20">
@ -272,6 +294,13 @@ async function createNewProject() {
{{ p.total_tasks - p.done_tasks - p.active_tasks - p.blocked_tasks - (p.review_tasks || 0) }} pending
</span>
</div>
<div v-if="p.total_tasks > 0" class="mt-2 flex items-center gap-2">
<div class="flex-1 h-1 bg-gray-800 rounded-full overflow-hidden">
<div class="h-full bg-green-700 rounded-full transition-all"
:style="{ width: `${Math.round((p.done_tasks || 0) / p.total_tasks * 100)}%` }"></div>
</div>
<span class="text-[10px] text-gray-600 shrink-0">{{ Math.round((p.done_tasks || 0) / p.total_tasks * 100) }}%</span>
</div>
</router-link>
</div>
</div>