chore: initial commit — existing single-user document scanner codebase
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div class="p-8 max-w-4xl mx-auto">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-900">
|
||||
{{ activeTopic ? activeTopic : 'All Topics' }}
|
||||
</h2>
|
||||
<p class="text-gray-500 text-sm mt-0.5">
|
||||
{{ activeTopic ? `Documents classified under "${activeTopic}"` : 'Manage topics and browse documents by topic' }}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
v-if="activeTopic"
|
||||
@click="$router.push('/topics')"
|
||||
class="text-sm text-indigo-600 hover:underline"
|
||||
>
|
||||
← All Topics
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- No filter: show topic manager + topic grid -->
|
||||
<template v-if="!activeTopic">
|
||||
<TopicManager />
|
||||
|
||||
<div class="mt-8">
|
||||
<h3 class="text-lg font-semibold text-gray-800 mb-4">Browse by Topic</h3>
|
||||
<div v-if="topicsStore.topics.length === 0" class="text-sm text-gray-400">No topics yet.</div>
|
||||
<div v-else class="grid grid-cols-2 sm:grid-cols-3 gap-3">
|
||||
<router-link
|
||||
v-for="topic in topicsStore.topics"
|
||||
:key="topic.id"
|
||||
:to="`/topics/${encodeURIComponent(topic.name)}`"
|
||||
class="bg-white border border-gray-200 rounded-xl p-4 hover:border-indigo-300 hover:shadow-sm transition-all"
|
||||
>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="w-3 h-3 rounded-full" :style="{ backgroundColor: topic.color }"></span>
|
||||
<span class="font-medium text-gray-800 text-sm">{{ topic.name }}</span>
|
||||
</div>
|
||||
<p class="text-2xl font-bold text-gray-900">{{ topic.doc_count }}</p>
|
||||
<p class="text-xs text-gray-400">document{{ topic.doc_count !== 1 ? 's' : '' }}</p>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Filtered by topic: document list -->
|
||||
<template v-else>
|
||||
<div v-if="docsStore.loading" class="text-sm text-gray-400">Loading…</div>
|
||||
<div v-else-if="docsStore.documents.length === 0" class="text-center py-12 text-gray-400">
|
||||
No documents under this topic yet.
|
||||
</div>
|
||||
<div v-else class="grid gap-3">
|
||||
<DocumentCard v-for="doc in docsStore.documents" :key="doc.id" :doc="doc" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, watch, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import TopicManager from '../components/topics/TopicManager.vue'
|
||||
import DocumentCard from '../components/documents/DocumentCard.vue'
|
||||
import { useTopicsStore } from '../stores/topics.js'
|
||||
import { useDocumentsStore } from '../stores/documents.js'
|
||||
|
||||
const route = useRoute()
|
||||
const topicsStore = useTopicsStore()
|
||||
const docsStore = useDocumentsStore()
|
||||
|
||||
const activeTopic = computed(() => route.params.name ? decodeURIComponent(route.params.name) : null)
|
||||
|
||||
function loadDocs() {
|
||||
if (activeTopic.value) {
|
||||
docsStore.fetchDocuments({ topic: activeTopic.value })
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(loadDocs)
|
||||
watch(activeTopic, loadDocs)
|
||||
</script>
|
||||
Reference in New Issue
Block a user