更新内容

This commit is contained in:
TU
2026-07-06 21:07:21 +08:00
parent 71bb89342d
commit bf127782f4
+61 -65
View File
@@ -4,7 +4,7 @@
*/ */
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { BookOpen, ChevronDown, Layers3 } from 'lucide-react'; import { ArrowLeft, BookOpen, Layers3 } from 'lucide-react';
import { apiUrl } from '../api'; import { apiUrl } from '../api';
interface VocabEntry { interface VocabEntry {
@@ -38,7 +38,7 @@ const colorClassFor = (color: string) => {
export const VocabCards: React.FC = () => { export const VocabCards: React.FC = () => {
const [cards, setCards] = useState<VocabCard[]>([]); const [cards, setCards] = useState<VocabCard[]>([]);
const [expandedTerm, setExpandedTerm] = useState<string | null>(null); const [selectedCard, setSelectedCard] = useState<VocabCard | null>(null);
const [status, setStatus] = useState<'loading' | 'ready' | 'error'>('loading'); const [status, setStatus] = useState<'loading' | 'ready' | 'error'>('loading');
useEffect(() => { useEffect(() => {
@@ -68,20 +68,33 @@ export const VocabCards: React.FC = () => {
return ( return (
<div className="flex-1 overflow-y-auto bg-[#FAF9F6] px-2 py-3 lg:px-6 lg:pb-6"> <div className="flex-1 overflow-y-auto bg-[#FAF9F6] px-2 py-3 lg:px-6 lg:pb-6">
<div className="mx-auto max-w-4xl"> <div className="mx-auto max-w-5xl">
<div className="mb-3 flex items-center justify-between gap-3 rounded-xl border border-[#E8E4DE] bg-[#FDFCFB] px-4 py-3 shadow-sm"> <div className="mb-3 flex items-center justify-between gap-3 rounded-xl border border-[#E8E4DE] bg-[#FDFCFB] px-4 py-3 shadow-sm">
<div> <div>
<div className="flex items-center gap-2 font-serif text-lg font-bold text-[#2D2926]"> <div className="flex items-center gap-2 font-serif text-lg font-bold text-[#2D2926]">
<Layers3 className="h-5 w-5 text-[#8B7E74]" /> <Layers3 className="h-5 w-5 text-[#8B7E74]" />
{selectedCard ? selectedCard.text : '单词卡片'}
</div> </div>
<div className="mt-1 text-xs text-[#A69F92]"> {!selectedCard && (
<div className="mt-1 text-xs text-[#A69F92]">
</div>
)}
</div>
{selectedCard ? (
<button
type="button"
onClick={() => setSelectedCard(null)}
className="flex items-center gap-1 rounded-full border border-[#E8E4DE] bg-white px-3 py-1.5 text-xs font-semibold text-[#8B7E74] hover:bg-[#FAF9F6]"
>
<ArrowLeft className="h-3.5 w-3.5" />
</button>
) : (
<div className="rounded-full bg-[#8B7E74]/10 px-3 py-1 text-xs font-semibold text-[#8B7E74]">
{cards.length}
</div> </div>
</div> )}
<div className="rounded-full bg-[#8B7E74]/10 px-3 py-1 text-xs font-semibold text-[#8B7E74]">
{cards.length}
</div>
</div> </div>
{status === 'loading' && ( {status === 'loading' && (
@@ -102,65 +115,48 @@ export const VocabCards: React.FC = () => {
</div> </div>
)} )}
<div className="space-y-2"> {status === 'ready' && selectedCard && (
{cards.map((card) => { <div className="space-y-3">
const isExpanded = expandedTerm === card.normalizedText; <div className={`rounded-xl border p-3 text-sm leading-relaxed ${colorClassFor(selectedCard.latestColor)}`}>
return ( {selectedCard.latestComment || '无释义内容'}
<article </div>
key={card.normalizedText}
className="rounded-xl border border-[#E8E4DE] bg-[#FDFCFB] p-3 shadow-sm" <div className="space-y-2">
> {selectedCard.entries.map((entry, index) => (
<button <div
type="button" key={`${entry.fileName}-${entry.lineNumber}-${index}`}
onClick={() => setExpandedTerm(isExpanded ? null : card.normalizedText)} className="rounded-xl border border-[#E8E4DE]/70 bg-white p-3 shadow-sm"
className="flex w-full items-start justify-between gap-3 text-left"
> >
<div className="min-w-0"> <div className="mb-1 flex items-center gap-1.5 text-xs font-semibold text-[#8B7E74]">
<div className="font-serif text-xl font-bold text-[#2D2926]"> <BookOpen className="h-3.5 w-3.5" />
{card.text} {entry.documentTitle} · {entry.lineNumber}
</div> </div>
<div className="mt-1 flex flex-wrap items-center gap-1.5 text-[11px] text-[#A69F92]"> <div className="text-sm leading-relaxed text-[#2D2926]">
<span>{card.noteCount} </span> {entry.lineText}
<span>·</span> </div>
<span className="truncate">{card.documentTitles.join(' / ')}</span> <div className={`mt-2 rounded-lg border px-2 py-1.5 text-sm ${colorClassFor(entry.color)}`}>
</div> {entry.comment}
</div> </div>
<ChevronDown
className={`mt-1 h-4 w-4 shrink-0 text-[#8B7E74] transition ${
isExpanded ? 'rotate-180' : ''
}`}
/>
</button>
<div className={`mt-2 rounded-lg border p-2 text-sm leading-relaxed ${colorClassFor(card.latestColor)}`}>
{card.latestComment || '无释义内容'}
</div> </div>
))}
</div>
</div>
)}
{isExpanded && ( {status === 'ready' && !selectedCard && (
<div className="mt-3 space-y-2 border-t border-[#E8E4DE]/60 pt-3"> <div className="grid grid-cols-3 gap-1.5 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6 xl:grid-cols-7">
{card.entries.map((entry, index) => ( {cards.map((card) => (
<div <button
key={`${entry.fileName}-${entry.lineNumber}-${index}`} key={card.normalizedText}
className="rounded-lg border border-[#E8E4DE]/70 bg-white p-2.5" type="button"
> onClick={() => setSelectedCard(card)}
<div className="mb-1 flex items-center gap-1.5 text-[11px] font-semibold text-[#8B7E74]"> className="min-h-14 rounded-xl border border-[#E8E4DE] bg-[#FDFCFB] px-2 py-2 text-center font-serif text-base font-bold leading-snug text-[#2D2926] shadow-sm transition hover:border-[#8B7E74]/50 hover:bg-white active:bg-[#E8E4DE]/30 sm:text-lg"
<BookOpen className="h-3.5 w-3.5" /> >
{entry.documentTitle} · {entry.lineNumber} {card.text}
</div> </button>
<div className="text-xs leading-relaxed text-[#A69F92]"> ))}
{entry.lineText} </div>
</div> )}
<div className={`mt-2 rounded border px-2 py-1.5 text-sm ${colorClassFor(entry.color)}`}>
{entry.comment}
</div>
</div>
))}
</div>
)}
</article>
);
})}
</div>
</div> </div>
</div> </div>
); );