Add web GUI: FastAPI API + Vue 3 frontend with dark theme

API (web/api.py):
  GET  /api/projects, /api/projects/{id}, /api/tasks/{id}
  GET  /api/decisions?project=X, /api/cost?days=7, /api/support/tickets
  POST /api/projects, /api/tasks, /api/decisions, /api/bootstrap
  CORS for localhost:5173, all queries via models.py

Frontend (web/frontend/):
  Vue 3 + TypeScript + Vite + Tailwind CSS v3
  Dashboard: project cards with task counters, cost, status badges
  ProjectView: tabs for Tasks/Decisions/Modules with filters
  Modals: Add Project, Add Task, Add Decision, Bootstrap
  Dark theme, monospace font, minimal clean design

Startup:
  API:  cd web && uvicorn api:app --reload --port 8420
  Web:  cd web/frontend && npm install && npm run dev

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
johnfrum1234 2026-03-15 13:50:15 +02:00
parent b95db7c7d6
commit 86e5b8febf
21 changed files with 3386 additions and 1 deletions

View file

@ -0,0 +1,19 @@
<script setup lang="ts">
defineProps<{ color?: string; text: string }>()
const colors: Record<string, string> = {
green: 'bg-green-900/50 text-green-400 border-green-800',
blue: 'bg-blue-900/50 text-blue-400 border-blue-800',
red: 'bg-red-900/50 text-red-400 border-red-800',
yellow: 'bg-yellow-900/50 text-yellow-400 border-yellow-800',
gray: 'bg-gray-800/50 text-gray-400 border-gray-700',
purple: 'bg-purple-900/50 text-purple-400 border-purple-800',
orange: 'bg-orange-900/50 text-orange-400 border-orange-800',
}
</script>
<template>
<span class="text-xs px-2 py-0.5 rounded border" :class="colors[color || 'gray']">
{{ text }}
</span>
</template>

View file

@ -0,0 +1,18 @@
<script setup lang="ts">
defineProps<{ title: string }>()
const emit = defineEmits<{ close: [] }>()
</script>
<template>
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/60" @click.self="emit('close')">
<div class="bg-gray-900 border border-gray-700 rounded-lg w-full max-w-lg mx-4 shadow-2xl">
<div class="flex items-center justify-between px-5 py-3 border-b border-gray-800">
<h3 class="text-sm font-semibold text-gray-200">{{ title }}</h3>
<button @click="emit('close')" class="text-gray-500 hover:text-gray-300 text-lg leading-none">&times;</button>
</div>
<div class="px-5 py-4">
<slot />
</div>
</div>
</div>
</template>