diff --git a/Mindforge.Web/src/components/FlashcardReviewComponent.tsx b/Mindforge.Web/src/components/FlashcardReviewComponent.tsx index f4df952..a4da8a8 100644 --- a/Mindforge.Web/src/components/FlashcardReviewComponent.tsx +++ b/Mindforge.Web/src/components/FlashcardReviewComponent.tsx @@ -82,7 +82,6 @@ export function FlashcardReviewComponent() { library.id, { fileName: library.fileName, - subject: library.subject || 'Geral', difficultyLabel: difficultyLabel(library.difficulty), }, ]), diff --git a/Mindforge.Web/src/components/FlashcardStudySession.css b/Mindforge.Web/src/components/FlashcardStudySession.css index 15f2dc3..f567f54 100644 --- a/Mindforge.Web/src/components/FlashcardStudySession.css +++ b/Mindforge.Web/src/components/FlashcardStudySession.css @@ -203,8 +203,7 @@ text-transform: uppercase; } -.study-tag, -.study-status-badge { +.study-tag { display: inline-flex; align-items: center; gap: 8px; @@ -214,53 +213,13 @@ border: 1px solid rgba(82, 54, 17, .12); } -.study-status-badge { - font-size: 11px; - line-height: 1; -} - -.study-status-icon { - width: 16px; - height: 16px; - border-radius: 999px; - display: inline-flex; - align-items: center; - justify-content: center; - background: rgba(82, 54, 17, .10); - font-size: 11px; -} - -.study-status-badge.rag-red { - color: var(--red-deep); - background: rgba(183, 91, 77, 0.12); - border-color: rgba(183, 91, 77, 0.22); -} - -.study-status-badge.rag-amber { - color: #74531c; - background: rgba(199, 149, 57, 0.14); - border-color: rgba(199, 149, 57, 0.24); -} - -.study-status-badge.rag-green { - color: var(--green-deep); - background: rgba(79, 143, 90, 0.12); - border-color: rgba(79, 143, 90, 0.22); -} - -.study-status-badge.rag-grey { - color: var(--muted); - background: rgba(123, 106, 80, 0.10); - border-color: rgba(123, 106, 80, 0.18); -} - .study-card-question, .study-card-answer { position: relative; z-index: 1; display: grid; align-content: center; - gap: 16px; + gap: 18px; min-height: 190px; color: var(--ink); font-family: "Segoe UI", Inter, Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif; @@ -271,14 +230,14 @@ line-height: 1.5; } -.study-back-question, -.study-back-answer { +.study-back-answer, +.study-back-question { display: grid; gap: 6px; } -.study-back-question span, -.study-back-answer span { +.study-back-answer span, +.study-back-question span { color: var(--blue-deep); font-size: 11px; font-weight: 950; @@ -286,30 +245,21 @@ text-transform: uppercase; } -.study-back-question p, -.study-back-answer p { +.study-back-answer p, +.study-back-question p { margin: 0; color: var(--ink); } -.study-back-question p { - color: #66543d; - font-size: clamp(15px, 1.7vw, 18px); - line-height: 1.45; -} - .study-back-answer p { font-size: clamp(20px, 2.65vw, 24px); line-height: 1.5; } -.study-card-details { - display: flex; - flex-wrap: wrap; - gap: 8px; - color: var(--muted); - font-size: 12px; - font-weight: 800; +.study-back-question p { + color: #66543d; + font-size: clamp(15px, 1.7vw, 18px); + line-height: 1.45; } .study-card-footer { @@ -324,19 +274,6 @@ font-weight: 800; } -.study-spacebar { - padding: 4px 9px; - border-radius: 8px; - color: #4f3a1d; - background: rgba(255,255,255,.58); - border: 1px solid rgba(82, 54, 17, .14); - box-shadow: inset 0 -2px 0 rgba(82, 54, 17, .08); - font-size: 11px; - font-weight: 950; - letter-spacing: .08em; - text-transform: uppercase; -} - .study-controls { position: relative; z-index: 1; @@ -519,7 +456,7 @@ .study-queue-item { display: grid; - grid-template-columns: 38px minmax(0, 1fr) auto; + grid-template-columns: 38px minmax(0, 1fr); gap: 10px; align-items: center; padding: 10px; @@ -536,11 +473,6 @@ font-size: 13px; } -.study-queue-item span { - color: var(--muted); - font-size: 11px; -} - .study-queue-number { width: 38px; height: 38px; diff --git a/Mindforge.Web/src/components/FlashcardStudySession.tsx b/Mindforge.Web/src/components/FlashcardStudySession.tsx index d03dcfb..0dfda1c 100644 --- a/Mindforge.Web/src/components/FlashcardStudySession.tsx +++ b/Mindforge.Web/src/components/FlashcardStudySession.tsx @@ -5,13 +5,7 @@ import './FlashcardStudySession.css'; export interface FlashcardStudySessionLibraryMeta { fileName?: string; - subject?: string; - subSubject?: string; difficultyLabel?: string; - statusLabel?: string; - statusIcon?: string; - statusClassName?: string; - footerDetails?: string[]; } interface FlashcardStudySessionProps { @@ -105,13 +99,13 @@ function resetTimeout(timeoutRef: { current: number | null }) { } function formatFooter(meta: FlashcardStudySessionLibraryMeta | undefined) { - const main = [meta?.fileName, meta?.subSubject].filter(Boolean).join(' - '); - return main || 'Arquivo'; + return meta?.fileName || 'Arquivo'; } export function FlashcardStudySession({ cards, libraryMetaById, onAnswer, onEnd }: FlashcardStudySessionProps) { const [currentIndex, setCurrentIndex] = useState(0); const [showAnswer, setShowAnswer] = useState(false); + const [showBackQuestion, setShowBackQuestion] = useState(false); const [submittingAnswer, setSubmittingAnswer] = useState(false); const [cardExiting, setCardExiting] = useState(false); const [stampState, setStampState] = useState<'correct' | 'wrong' | null>(null); @@ -134,6 +128,7 @@ export function FlashcardStudySession({ cards, libraryMetaById, onAnswer, onEnd useEffect(() => { setCurrentIndex(0); setShowAnswer(false); + setShowBackQuestion(false); setSubmittingAnswer(false); setCardExiting(false); setStampState(null); @@ -165,10 +160,10 @@ export function FlashcardStudySession({ cards, libraryMetaById, onAnswer, onEnd if (!showAnswer) { setShowAnswer(true); } - } else if (e.code === 'KeyC' && showAnswer && !submittingAnswer) { + } else if (e.code === 'KeyC' && showAnswer && !showBackQuestion && !submittingAnswer) { e.preventDefault(); void registerReviewAnswer(true); - } else if (e.code === 'KeyW' && showAnswer && !submittingAnswer) { + } else if (e.code === 'KeyW' && showAnswer && !showBackQuestion && !submittingAnswer) { e.preventDefault(); void registerReviewAnswer(false); } @@ -176,12 +171,13 @@ export function FlashcardStudySession({ cards, libraryMetaById, onAnswer, onEnd window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); - }, [cards.length, showAnswer, submittingAnswer, currentCard]); + }, [cards.length, currentCard, showAnswer, showBackQuestion, submittingAnswer]); const goToPrevious = () => { if (currentIndex === 0 || submittingAnswer) return; setCurrentIndex(currentIndex - 1); setShowAnswer(false); + setShowBackQuestion(false); setFlipped(false); setStampState(null); setCardExiting(false); @@ -196,6 +192,7 @@ export function FlashcardStudySession({ cards, libraryMetaById, onAnswer, onEnd setCurrentIndex(currentIndex + 1); setShowAnswer(false); + setShowBackQuestion(false); setFlipped(false); setStampState(null); setCardExiting(false); @@ -204,7 +201,7 @@ export function FlashcardStudySession({ cards, libraryMetaById, onAnswer, onEnd }; const registerReviewAnswer = async (correct: boolean) => { - if (!currentCard || !showAnswer || submittingAnswer) return; + if (!currentCard || !showAnswer || showBackQuestion || submittingAnswer) return; resetTimeout(stampTimerRef); resetTimeout(advanceTimerRef); @@ -277,22 +274,38 @@ export function FlashcardStudySession({ cards, libraryMetaById, onAnswer, onEnd
{ if (!showAnswer && !submittingAnswer) setShowAnswer(true); }} + onClick={() => { + if (submittingAnswer) return; + if (!showAnswer) { + setShowAnswer(true); + return; + } + + if (!showBackQuestion) { + setShowBackQuestion(true); + } + }} tabIndex={0} role="button" - aria-label={showAnswer ? 'Flashcard revelado' : 'Clique ou pressione Espaço para revelar'} + aria-label={ + !showAnswer + ? 'Clique ou pressione Espaço para revelar' + : showBackQuestion + ? 'Flashcard com pergunta e resposta visíveis' + : 'Clique para mostrar a pergunta junto da resposta' + } >
-
- {currentMeta?.subject || 'Geral'} - {currentMeta?.difficultyLabel || currentMeta?.statusLabel || 'Revisão'} -
+ {currentMeta?.difficultyLabel && ( +
+ {currentMeta.difficultyLabel} +
+ )}
{currentCard.front}
@@ -304,35 +317,22 @@ export function FlashcardStudySession({ cards, libraryMetaById, onAnswer, onEnd )}
Resposta - {currentMeta?.statusLabel ? ( - - {currentMeta.statusIcon && {currentMeta.statusIcon}} - {currentMeta.statusLabel} - - ) : ( - {currentMeta?.difficultyLabel || 'Revisão'} - )} + {currentMeta?.difficultyLabel && {currentMeta.difficultyLabel}}
-
- Pergunta -

{currentCard.front}

-
Resposta

{currentCard.back}

- {currentMeta?.footerDetails && currentMeta.footerDetails.length > 0 && ( -
- {currentMeta.footerDetails.map((detail) => ( - {detail} - ))} + {showBackQuestion && ( +
+ Pergunta +

{currentCard.front}

)}
@@ -342,14 +342,14 @@ export function FlashcardStudySession({ cards, libraryMetaById, onAnswer, onEnd @@ -386,16 +386,12 @@ export function FlashcardStudySession({ cards, libraryMetaById, onAnswer, onEnd

Fila

- {cards.slice(currentIndex, currentIndex + 5).map((card, index) => { - const meta = libraryMetaById.get(card.libraryId); - return ( -
- {currentIndex + index + 1} - {card.front.substring(0, 40)}{card.front.length > 40 ? '...' : ''} - {meta?.subject || ''} -
- ); - })} + {cards.slice(currentIndex, currentIndex + 5).map((card, index) => ( +
+ {currentIndex + index + 1} + {card.front.substring(0, 40)}{card.front.length > 40 ? '...' : ''} +
+ ))} {remainingCount > 5 && (
+{remainingCount - 5} restantes diff --git a/Mindforge.Web/src/components/SpacedReviewComponent.tsx b/Mindforge.Web/src/components/SpacedReviewComponent.tsx index 60494c0..802a7f6 100644 --- a/Mindforge.Web/src/components/SpacedReviewComponent.tsx +++ b/Mindforge.Web/src/components/SpacedReviewComponent.tsx @@ -226,24 +226,12 @@ export function SpacedReviewComponent() { const sessionLibraryMetaById = useMemo(() => { return new Map( - sessionLibraries.map((library) => { - const statusMeta = STATUS_META_BY_STATUS[library.ragStatus]; - return [ - library.libraryId, - { - fileName: library.fileName, - subject: library.subject || 'Geral', - subSubject: library.subSubject || 'Geral', - statusLabel: statusMeta.label, - statusIcon: statusMeta.icon, - statusClassName: statusMeta.className, - footerDetails: [ - `Desempenho do arquivo: ${formatPerformance(library.performanceRate)}`, - `Última revisão: ${formatLastReviewed(library.lastReviewedAt)}`, - ], - }, - ]; - }), + sessionLibraries.map((library) => [ + library.libraryId, + { + fileName: library.fileName, + }, + ]), ); }, [sessionLibraries]); diff --git a/project-context.md b/project-context.md index 866b6fe..14e221e 100644 --- a/project-context.md +++ b/project-context.md @@ -147,7 +147,7 @@ Formas de requisição principais: - **Background**: Gradiente radial quente (dourado/azul) sobre base `#fff8e6` com overlay de grid de papel 24px. - **Layout**: CSS Grid (`grid-template-columns: 288px minmax(0, 1fr)`). Sidebar sticky com textura diagonal. Topbar integrada ao fluxo (não fixa). - **Animações**: Apenas sob ação do usuário (flip 3D do flashcard, carimbo, saída do cartão, confete canvas). Sem animações infinitas ou spinners. -- **Flashcard**: Cartão 3D com efeito `rotateY(180deg)`, frente papel pautado com borda tracejada, verso azulado que mostra pergunta menor + resposta principal. Carimbo de feedback ("Correto"/"Incorreto") é renderizado no verso visível antes da saída do cartão. Confete canvas ao acertar. +- **Flashcard**: Cartão 3D com efeito `rotateY(180deg)`, frente papel pautado com borda tracejada e verso azulado focado na resposta. No verso, um clique extra revela a pergunta; enquanto essa pergunta auxiliar estiver visível, os botões "Correto" e "Incorreto" ficam bloqueados. O card não exibe status RAG nem metadados de assunto/subassunto/desempenho/última revisão. O carimbo de feedback ("Correto"/"Incorreto") é renderizado no verso visível antes da saída do cartão, e há confete canvas ao acertar. - **Responsivo**: Breakpoints em 1120px (sidebar colapsada) e 760px (layout single-column). ### Variáveis CSS (definidas em `index.css`)