update
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import { fetchGuides, fetchTopics, createTopic as apiCreateTopic, deleteTopic as apiDeleteTopic, createGuide as apiCreate, deleteGuide, cancelGuide as apiCancel, fetchBausteineStatus, fetchActiveBausteine, createBausteine as apiCreateBausteine, cancelBausteine as apiCancelBausteine, deleteBausteine as apiDeleteBausteine, fetchProjects, deleteProject as apiDeleteProject, fetchProviders } from './api.js'
|
||||
import { fetchGuides, fetchTopics, createTopic as apiCreateTopic, deleteTopic as apiDeleteTopic, createGuide as apiCreate, deleteGuide, cancelGuide as apiCancel, fetchBausteineStatus, fetchActiveBausteine, createBausteine as apiCreateBausteine, cancelBausteine as apiCancelBausteine, deleteBausteine as apiDeleteBausteine, fetchProjects, deleteProject as apiDeleteProject, fetchProviders, fetchStats } from './api.js'
|
||||
import TopicSidebar from './components/TopicSidebar.vue'
|
||||
import TopicDetail from './components/TopicDetail.vue'
|
||||
|
||||
@@ -21,6 +21,15 @@ const bausteine = ref({ ...EMPTY_BAUSTEINE })
|
||||
const activeBausteine = ref([])
|
||||
const provider = ref(localStorage.getItem('provider') || 'claude')
|
||||
const providers = ref([])
|
||||
const stats = ref(null)
|
||||
|
||||
async function loadStats() {
|
||||
try {
|
||||
stats.value = await fetchStats()
|
||||
} catch (e) {
|
||||
console.error('Fehler beim Laden der Statistik:', e)
|
||||
}
|
||||
}
|
||||
|
||||
function setProvider(id) {
|
||||
provider.value = id
|
||||
@@ -112,6 +121,7 @@ async function loadTopics() {
|
||||
async function loadGuides() {
|
||||
try {
|
||||
guides.value = await fetchGuides()
|
||||
loadStats()
|
||||
} catch (e) {
|
||||
console.error('Fehler beim Laden:', e)
|
||||
}
|
||||
@@ -288,6 +298,7 @@ onUnmounted(() => {
|
||||
:topics="topics"
|
||||
:projects="projectNames"
|
||||
:selectedTopic="selectedTopic"
|
||||
:stats="stats"
|
||||
:doneByFormat="doneByFormat"
|
||||
:latestByFormat="latestByFormat"
|
||||
:allGuides="guides"
|
||||
@@ -318,6 +329,7 @@ onUnmounted(() => {
|
||||
:previewGuide="previewGuide"
|
||||
:dark="darkMode"
|
||||
:provider="provider"
|
||||
@progressChanged="loadStats"
|
||||
/>
|
||||
<div v-else class="empty-main">
|
||||
<p>Thema in der Sidebar anlegen oder auswählen.</p>
|
||||
|
||||
@@ -41,6 +41,11 @@ export async function deleteBausteine(topic) {
|
||||
await fetch(`${BASE}/bausteine?topic=${encodeURIComponent(topic)}`, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
export async function fetchStats() {
|
||||
const res = await fetch(`${BASE}/stats`)
|
||||
return res.json()
|
||||
}
|
||||
|
||||
export async function fetchProviders() {
|
||||
const res = await fetch(`${BASE}/providers`)
|
||||
return res.json()
|
||||
|
||||
@@ -28,6 +28,8 @@ const props = defineProps({
|
||||
provider: { type: String, default: 'claude' },
|
||||
})
|
||||
|
||||
const emit = defineEmits(['progressChanged'])
|
||||
|
||||
const isOnePager = computed(() => props.previewGuide?.format === 'OnePager')
|
||||
|
||||
// --- Inhalt laden ---
|
||||
@@ -73,6 +75,7 @@ async function toggleChapter(title) {
|
||||
try {
|
||||
const res = await setProgress(props.previewGuide.id, title, newState)
|
||||
doneChapters.value = new Set(res.chapters || [])
|
||||
emit('progressChanged')
|
||||
} catch {
|
||||
const rollback = new Set(doneChapters.value)
|
||||
if (newState) rollback.delete(title)
|
||||
|
||||
@@ -5,6 +5,7 @@ const props = defineProps({
|
||||
topics: { type: Array, required: true },
|
||||
projects: { type: Array, default: () => [] },
|
||||
selectedTopic: { type: String, default: null },
|
||||
stats: { type: Object, default: null },
|
||||
doneByFormat: { type: Object, default: () => ({}) },
|
||||
latestByFormat: { type: Object, default: () => ({}) },
|
||||
allGuides: { type: Array, default: () => [] },
|
||||
@@ -25,6 +26,19 @@ function providerAvailable(id) {
|
||||
|
||||
const PROVIDER_LABELS = { claude: 'Claude', minimax: 'MiniMax', lokal: 'Lokal' }
|
||||
|
||||
// Tracker oben in der Navigation: Themen gesamt, pro Format erstellt/absolviert
|
||||
const trackerItems = computed(() => {
|
||||
if (!props.stats) return []
|
||||
const f = props.stats.formate || {}
|
||||
const fmt = (k) => `${f[k]?.absolviert ?? 0}/${f[k]?.erstellt ?? 0}`
|
||||
return [
|
||||
{ label: 'Themen', value: String(props.stats.themen ?? 0), title: 'Themen inkl. Projekte' },
|
||||
{ label: 'MiniGuides', value: fmt('MiniGuide'), title: 'absolviert/erstellt' },
|
||||
{ label: 'Guides', value: fmt('Guide'), title: 'absolviert/erstellt' },
|
||||
{ label: 'FullGuides', value: fmt('FullGuide'), title: 'absolviert/erstellt' },
|
||||
]
|
||||
})
|
||||
|
||||
const formats = [
|
||||
{ key: 'OnePager', label: 'OnePager' },
|
||||
{ key: 'MiniGuide', label: 'MiniGuide' },
|
||||
@@ -167,6 +181,12 @@ function confirmDeleteProject(name) {
|
||||
|
||||
<template>
|
||||
<aside class="sidebar" @mouseleave="emit('sidebarLeave')">
|
||||
<div class="stats-bar" v-if="trackerItems.length">
|
||||
<div class="stat" v-for="item in trackerItems" :key="item.label" :title="item.title">
|
||||
<span class="stat-value">{{ item.value }}</span>
|
||||
<span class="stat-label">{{ item.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="new-topic">
|
||||
<button
|
||||
class="pin-btn"
|
||||
@@ -407,6 +427,40 @@ function confirmDeleteProject(name) {
|
||||
border-color: var(--accent-border);
|
||||
}
|
||||
|
||||
.stats-bar {
|
||||
display: flex;
|
||||
padding: 0.5rem 0.75rem;
|
||||
gap: 4px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.stat {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 1px;
|
||||
padding: 4px 2px;
|
||||
background: var(--panel-soft);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.58rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
color: var(--text-faint);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.provider-toggle {
|
||||
display: flex;
|
||||
gap: 0;
|
||||
|
||||
Reference in New Issue
Block a user