mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-08-31 21:11:44 +02:00
wip
This commit is contained in:
@@ -6,6 +6,8 @@ import { QuizTopNavigation } from './QuizTopNavigation';
|
||||
import { getPercentage } from '../../lib/number';
|
||||
import { AIQuizResults } from './AIQuizResults';
|
||||
import { flushSync } from 'react-dom';
|
||||
import { AIQuizStripe } from './AIQuizStripe';
|
||||
import { cn } from '../../lib/classname';
|
||||
|
||||
export type QuestionState = {
|
||||
isSubmitted: boolean;
|
||||
@@ -146,7 +148,12 @@ export function AIQuizContent(props: AIQuizContentProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-lg py-10">
|
||||
<div
|
||||
className={cn(
|
||||
'mx-auto w-full max-w-lg py-10',
|
||||
quizStatus === 'reviewing' && 'pb-24',
|
||||
)}
|
||||
>
|
||||
{shouldShowQuestions && (
|
||||
<QuizTopNavigation
|
||||
activeQuestionIndex={activeQuestionIndex}
|
||||
@@ -203,6 +210,20 @@ export function AIQuizContent(props: AIQuizContentProps) {
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{quizStatus === 'reviewing' && (
|
||||
<AIQuizStripe
|
||||
activeQuestionIndex={activeQuestionIndex}
|
||||
questionStates={questionStates}
|
||||
onReview={(questionIndex) => {
|
||||
setActiveQuestionIndex(questionIndex);
|
||||
setQuizStatus('reviewing');
|
||||
}}
|
||||
onComplete={() => {
|
||||
setQuizStatus('submitted');
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
63
src/components/AIQuiz/AIQuizStripe.tsx
Normal file
63
src/components/AIQuiz/AIQuizStripe.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { cn } from '../../lib/classname';
|
||||
import {
|
||||
ArrowRightIcon,
|
||||
CheckIcon,
|
||||
SkipForwardIcon,
|
||||
XIcon,
|
||||
} from 'lucide-react';
|
||||
import type { QuestionState } from './AIQuizContent';
|
||||
|
||||
type AIQuizStripeProps = {
|
||||
activeQuestionIndex: number;
|
||||
questionStates: Record<number, QuestionState>;
|
||||
onReview?: (questionIndex: number) => void;
|
||||
onComplete?: () => void;
|
||||
};
|
||||
|
||||
export function AIQuizStripe(props: AIQuizStripeProps) {
|
||||
const { activeQuestionIndex, questionStates, onReview, onComplete } = props;
|
||||
|
||||
const states = Object.values(questionStates);
|
||||
|
||||
return (
|
||||
<div className="fixed right-0 bottom-0 w-[calc(100vw-255px)] border-t border-gray-200 bg-white p-3">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="flex w-full gap-2">
|
||||
{states.map((state, quizIndex) => {
|
||||
const { status } = state;
|
||||
|
||||
const isActive = quizIndex === activeQuestionIndex;
|
||||
const isCorrect = status === 'correct';
|
||||
const isIncorrect = status === 'incorrect';
|
||||
const isSkipped = status === 'skipped';
|
||||
|
||||
return (
|
||||
<button
|
||||
key={quizIndex}
|
||||
onClick={() => onReview?.(quizIndex)}
|
||||
className={cn(
|
||||
'flex aspect-square flex-col items-center justify-center rounded-xl border p-1 hover:opacity-80',
|
||||
isCorrect && 'border-green-700 bg-green-700 text-white',
|
||||
isIncorrect && 'border-red-700 bg-red-700 text-white',
|
||||
isSkipped && 'border-gray-700 bg-gray-700 text-white',
|
||||
!isActive && 'opacity-50',
|
||||
)}
|
||||
>
|
||||
{isCorrect && <CheckIcon className="h-6 w-6" />}
|
||||
{isIncorrect && <XIcon className="h-6 w-6" />}
|
||||
{isSkipped && <SkipForwardIcon className="h-6 w-6" />}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<button
|
||||
className="flex shrink-0 items-center gap-2 rounded-xl bg-black px-4 py-2 text-white hover:bg-gray-900 disabled:opacity-70"
|
||||
onClick={onComplete}
|
||||
>
|
||||
Complete Quiz <ArrowRightIcon className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user