mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-09-10 01:00:42 +02:00
wip
This commit is contained in:
@@ -1,21 +1,15 @@
|
|||||||
import {
|
import {
|
||||||
CheckCircle,
|
|
||||||
PartyPopper,
|
PartyPopper,
|
||||||
RefreshCcw,
|
|
||||||
RotateCcw,
|
RotateCcw,
|
||||||
XCircle,
|
XCircle,
|
||||||
SkipForward,
|
SkipForward,
|
||||||
CheckCircle2Icon,
|
CheckCircle2Icon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
CheckCircleIcon,
|
|
||||||
XCircleIcon,
|
|
||||||
SkipForwardIcon,
|
|
||||||
CheckIcon,
|
|
||||||
XIcon,
|
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import type { QuestionState } from './AIQuizContent';
|
import type { QuestionState } from './AIQuizContent';
|
||||||
import { getPercentage } from '../../lib/number';
|
import { getPercentage } from '../../lib/number';
|
||||||
import { cn } from '../../lib/classname';
|
import { cn } from '../../lib/classname';
|
||||||
|
import { QuizStateButton } from './AIQuizStripe';
|
||||||
|
|
||||||
type AIQuizResultsProps = {
|
type AIQuizResultsProps = {
|
||||||
questionStates: Record<number, QuestionState>;
|
questionStates: Record<number, QuestionState>;
|
||||||
@@ -61,27 +55,15 @@ export function AIQuizResults(props: AIQuizResultsProps) {
|
|||||||
|
|
||||||
<div className="mb-6 grid w-full grid-cols-5 gap-2">
|
<div className="mb-6 grid w-full grid-cols-5 gap-2">
|
||||||
{states.map((state, quizIndex) => {
|
{states.map((state, quizIndex) => {
|
||||||
const { status } = state;
|
|
||||||
|
|
||||||
const isCorrect = status === 'correct';
|
|
||||||
const isIncorrect = status === 'incorrect';
|
|
||||||
const isSkipped = status === 'skipped';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<QuizStateButton
|
||||||
key={quizIndex}
|
key={quizIndex}
|
||||||
onClick={() => onReview?.(quizIndex)}
|
state={state}
|
||||||
className={cn(
|
quizIndex={quizIndex}
|
||||||
'flex aspect-square flex-col items-center justify-center rounded-xl border border-gray-200 p-2 hover:opacity-80',
|
isActive={true}
|
||||||
isCorrect && 'bg-green-700 text-white',
|
onReview={onReview}
|
||||||
isIncorrect && 'bg-red-700 text-white',
|
className="p-2"
|
||||||
isSkipped && 'bg-gray-700 text-white',
|
/>
|
||||||
)}
|
|
||||||
>
|
|
||||||
{isCorrect && <CheckIcon className="h-6 w-6" />}
|
|
||||||
{isIncorrect && <XIcon className="h-6 w-6" />}
|
|
||||||
{isSkipped && <SkipForwardIcon className="h-6 w-6" />}
|
|
||||||
</button>
|
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
@@ -2,6 +2,7 @@ import { cn } from '../../lib/classname';
|
|||||||
import {
|
import {
|
||||||
ArrowRightIcon,
|
ArrowRightIcon,
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
|
CircleAlertIcon,
|
||||||
SkipForwardIcon,
|
SkipForwardIcon,
|
||||||
XIcon,
|
XIcon,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
@@ -14,48 +15,69 @@ type AIQuizStripeProps = {
|
|||||||
onComplete?: () => void;
|
onComplete?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type QuizStateButtonProps = {
|
||||||
|
state: QuestionState;
|
||||||
|
quizIndex: number;
|
||||||
|
isActive: boolean;
|
||||||
|
onReview?: (questionIndex: number) => void;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function QuizStateButton(props: QuizStateButtonProps) {
|
||||||
|
const { state, quizIndex, isActive, onReview, className } = props;
|
||||||
|
const { status } = state;
|
||||||
|
|
||||||
|
const isCorrect = status === 'correct';
|
||||||
|
const isIncorrect = status === 'incorrect';
|
||||||
|
const isSkipped = status === 'skipped';
|
||||||
|
const isCanBeImproved = status === 'can_be_improved';
|
||||||
|
|
||||||
|
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',
|
||||||
|
isCanBeImproved && 'border-yellow-700 bg-yellow-700 text-white',
|
||||||
|
!isActive && 'opacity-50',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{isCorrect && <CheckIcon className="h-6 w-6" />}
|
||||||
|
{isIncorrect && <XIcon className="h-6 w-6" />}
|
||||||
|
{isSkipped && <SkipForwardIcon className="h-6 w-6" />}
|
||||||
|
{isCanBeImproved && <CircleAlertIcon className="h-6 w-6" />}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function AIQuizStripe(props: AIQuizStripeProps) {
|
export function AIQuizStripe(props: AIQuizStripeProps) {
|
||||||
const { activeQuestionIndex, questionStates, onReview, onComplete } = props;
|
const { activeQuestionIndex, questionStates, onReview, onComplete } = props;
|
||||||
|
|
||||||
const states = Object.values(questionStates);
|
const states = Object.values(questionStates);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed right-0 bottom-0 w-[calc(100vw-255px)] border-t border-gray-200 bg-white p-3">
|
<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 items-center justify-between gap-2">
|
||||||
<div className="flex w-full gap-2">
|
<div className="flex w-full gap-2">
|
||||||
{states.map((state, quizIndex) => {
|
{states.map((state, quizIndex) => (
|
||||||
const { status } = state;
|
<QuizStateButton
|
||||||
|
key={quizIndex}
|
||||||
const isActive = quizIndex === activeQuestionIndex;
|
state={state}
|
||||||
const isCorrect = status === 'correct';
|
quizIndex={quizIndex}
|
||||||
const isIncorrect = status === 'incorrect';
|
isActive={quizIndex === activeQuestionIndex}
|
||||||
const isSkipped = status === 'skipped';
|
onReview={onReview}
|
||||||
|
/>
|
||||||
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>
|
</div>
|
||||||
|
|
||||||
<button
|
<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"
|
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}
|
onClick={onComplete}
|
||||||
>
|
>
|
||||||
Complete Quiz <ArrowRightIcon className="h-4 w-4" />
|
Show Results <ArrowRightIcon className="h-4 w-4" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user