chore: initial commit — existing single-user document scanner codebase
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
6fed5ba531
commit
7a34807fa0
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div
|
||||
class="relative border-2 border-dashed rounded-xl p-10 text-center transition-colors"
|
||||
:class="dragging
|
||||
? 'border-indigo-400 bg-indigo-50'
|
||||
: 'border-gray-300 bg-white hover:border-indigo-300 hover:bg-gray-50'"
|
||||
@dragover.prevent="dragging = true"
|
||||
@dragleave.prevent="dragging = false"
|
||||
@drop.prevent="onDrop"
|
||||
@click="triggerInput"
|
||||
>
|
||||
<input
|
||||
ref="inputRef"
|
||||
type="file"
|
||||
class="hidden"
|
||||
multiple
|
||||
accept=".pdf,.docx,.doc,.txt,.md,.png,.jpg,.jpeg,.tiff,.webp"
|
||||
@change="onFileChange"
|
||||
/>
|
||||
|
||||
<div class="flex flex-col items-center gap-3">
|
||||
<svg class="w-12 h-12 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
|
||||
</svg>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-gray-700">Drop files here or <span class="text-indigo-600 underline cursor-pointer">browse</span></p>
|
||||
<p class="text-xs text-gray-400 mt-1">PDF, DOCX, TXT, MD, PNG, JPG supported</p>
|
||||
</div>
|
||||
|
||||
<label class="flex items-center gap-2 mt-2 cursor-pointer" @click.stop>
|
||||
<input type="checkbox" v-model="autoClassify" class="rounded border-gray-300 text-indigo-600" />
|
||||
<span class="text-sm text-gray-600">Auto-classify with AI after upload</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const emit = defineEmits(['files-selected'])
|
||||
const dragging = ref(false)
|
||||
const inputRef = ref(null)
|
||||
const autoClassify = ref(true)
|
||||
|
||||
function triggerInput() {
|
||||
inputRef.value?.click()
|
||||
}
|
||||
|
||||
function onDrop(e) {
|
||||
dragging.value = false
|
||||
const files = Array.from(e.dataTransfer?.files || [])
|
||||
if (files.length) emit('files-selected', { files, autoClassify: autoClassify.value })
|
||||
}
|
||||
|
||||
function onFileChange(e) {
|
||||
const files = Array.from(e.target.files || [])
|
||||
if (files.length) emit('files-selected', { files, autoClassify: autoClassify.value })
|
||||
e.target.value = ''
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<div v-if="items.length" class="space-y-2 mt-4">
|
||||
<div
|
||||
v-for="item in items"
|
||||
:key="item.name"
|
||||
class="flex items-center gap-3 bg-white border border-gray-200 rounded-lg px-4 py-2.5"
|
||||
>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm font-medium text-gray-800 truncate">{{ item.name }}</p>
|
||||
<p v-if="item.error" class="text-xs text-red-500 mt-0.5">{{ item.error }}</p>
|
||||
<p v-else-if="item.done" class="text-xs text-green-600 mt-0.5">
|
||||
Done{{ item.topics?.length ? ` — classified as: ${item.topics.join(', ')}` : ' — no topics assigned' }}
|
||||
</p>
|
||||
<p v-else class="text-xs text-gray-400 mt-0.5">Uploading…</p>
|
||||
</div>
|
||||
<div class="shrink-0">
|
||||
<svg v-if="item.error" class="w-5 h-5 text-red-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
<svg v-else-if="item.done" class="w-5 h-5 text-green-500" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
<svg v-else class="w-5 h-5 text-indigo-400 animate-spin" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
items: { type: Array, default: () => [] },
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user