更新内容

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