Files
meetnote/web/app/upload/page.tsx
2026-04-13 19:00:17 +08:00

147 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useState, useRef } from 'react'
import { UploadCloud, FileAudio, X } from 'lucide-react'
import Link from 'next/link'
import { AppShell } from '@/components/app-shell'
import { cn } from '@/lib/utils'
export default function UploadPage() {
const [file, setFile] = useState<File | null>(null)
const [title, setTitle] = useState('')
const [participants, setParticipants] = useState('')
const [dragOver, setDragOver] = useState(false)
const inputRef = useRef<HTMLInputElement>(null)
const pickFile = (f: File | null | undefined) => {
if (f) setFile(f)
}
const humanSize = (bytes: number) => {
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(0) + ' KB'
return (bytes / 1024 / 1024).toFixed(1) + ' MB'
}
return (
<AppShell>
<div className="mx-auto max-w-2xl px-5 py-8 md:px-10 md:py-10">
<header className="mb-8">
<h1 className="text-[26px] font-semibold tracking-tight"></h1>
<p className="mt-1 text-[14px] text-muted-foreground">
</p>
</header>
{/* Dropzone */}
{!file ? (
<div
onDragOver={(e) => {
e.preventDefault()
setDragOver(true)
}}
onDragLeave={() => setDragOver(false)}
onDrop={(e) => {
e.preventDefault()
setDragOver(false)
pickFile(e.dataTransfer.files?.[0])
}}
onClick={() => inputRef.current?.click()}
className={cn(
'flex flex-col items-center justify-center rounded-2xl border-2 border-dashed px-6 py-16 transition-all cursor-pointer',
dragOver
? 'border-primary bg-primary-subtle'
: 'border-border bg-surface-elevated hover:border-primary/50 hover:bg-primary-subtle/50',
)}
>
<div className="flex h-14 w-14 items-center justify-center rounded-2xl bg-primary-subtle text-primary">
<UploadCloud className="h-7 w-7" />
</div>
<h3 className="mt-5 text-[17px] font-semibold"></h3>
<p className="mt-1 text-[13px] text-muted-foreground"></p>
<p className="mt-4 text-[12px] text-muted-foreground">
m4a · mp3 · wav · mp4 · opus · 500 MB
</p>
<input
ref={inputRef}
type="file"
accept="audio/*,video/mp4"
className="hidden"
onChange={(e) => pickFile(e.target.files?.[0])}
/>
</div>
) : (
<div className="rounded-2xl border border-border bg-surface-elevated p-5">
<div className="flex items-start gap-4">
<div className="flex h-12 w-12 items-center justify-center rounded-xl bg-primary-subtle text-primary shrink-0">
<FileAudio className="h-6 w-6" />
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center justify-between gap-2">
<h3 className="text-[15px] font-semibold truncate">{file.name}</h3>
<button
onClick={() => setFile(null)}
className="rounded-lg p-1.5 text-muted-foreground hover:bg-surface-muted"
>
<X className="h-4 w-4" />
</button>
</div>
<p className="mt-1 text-[13px] text-muted-foreground">{humanSize(file.size)}</p>
</div>
</div>
</div>
)}
{/* Form */}
<div className="mt-6 space-y-5">
<div>
<label className="block text-[13px] font-medium mb-2"></label>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="例:与客户对齐定价"
className="w-full rounded-xl border border-input bg-surface-elevated px-4 py-3 text-[14px] placeholder:text-muted-foreground/60 focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20"
/>
</div>
<div>
<label className="block text-[13px] font-medium mb-2">
<span className="ml-2 text-[11px] font-normal text-muted-foreground">
</span>
</label>
<input
type="text"
value={participants}
onChange={(e) => setParticipants(e.target.value)}
placeholder="张三, 李四, 客户王总"
className="w-full rounded-xl border border-input bg-surface-elevated px-4 py-3 text-[14px] placeholder:text-muted-foreground/60 focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20"
/>
</div>
</div>
{/* Actions */}
<div className="mt-8 flex items-center justify-end gap-3">
<Link
href="/"
className="rounded-full px-5 py-2.5 text-[14px] font-medium text-muted-foreground hover:bg-surface-muted"
>
</Link>
<button
disabled={!file}
className="rounded-full bg-primary px-6 py-2.5 text-[14px] font-medium text-primary-foreground transition-colors hover:bg-primary-light disabled:opacity-40 disabled:cursor-not-allowed"
>
</button>
</div>
<p className="mt-8 text-center text-[12px] text-muted-foreground">
Groq Whisper · Claude / /
</p>
</div>
</AppShell>
)
}