Move tabs

This commit is contained in:
Joey Yakimowich-Payne 2026-01-19 14:04:10 -07:00
commit 3122748bae
No known key found for this signature in database
GPG key ID: DDF6AF5B21B407D4
3 changed files with 118 additions and 68 deletions

View file

@ -1,6 +1,6 @@
import React, { useState, useEffect, useCallback } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { ArrowLeft, Save, Plus, Play, AlertTriangle } from 'lucide-react';
import { ArrowLeft, Save, Plus, Play, AlertTriangle, List, Settings } from 'lucide-react';
import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors, DragEndEvent } from '@dnd-kit/core';
import { arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy } from '@dnd-kit/sortable';
import { Quiz, Question, GameConfig, DEFAULT_GAME_CONFIG } from '../types';
@ -40,6 +40,7 @@ export const QuizEditor: React.FC<QuizEditorProps> = ({
initialQuiz.config || defaultConfig || DEFAULT_GAME_CONFIG
);
const [hasAppliedDefaultConfig, setHasAppliedDefaultConfig] = useState(!!initialQuiz.config);
const [activeTab, setActiveTab] = useState<'questions' | 'settings'>('questions');
useEffect(() => {
if (!hasAppliedDefaultConfig && defaultConfig && defaultConfig !== DEFAULT_GAME_CONFIG) {
@ -215,60 +216,96 @@ export const QuizEditor: React.FC<QuizEditorProps> = ({
<div className="absolute right-20 bottom-[-50px] w-24 h-24 bg-white/10 rounded-full"></div>
</div>
<div className="p-6 space-y-4 flex-1 min-h-0 overflow-y-auto">
<div className="flex items-center justify-between">
<h2 className="text-lg font-bold text-gray-700">Questions</h2>
<button
onClick={handleAddQuestion}
className="flex items-center gap-2 px-4 py-2 bg-theme-primary text-white rounded-xl font-bold hover:bg-theme-primary/90 transition shadow-md"
>
<Plus size={18} /> Add Question
</button>
</div>
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
<div className="flex bg-white border-b border-gray-100">
<button
onClick={() => setActiveTab('questions')}
className={`flex-1 py-3 font-bold text-center border-b-2 transition-all ${
activeTab === 'questions'
? 'border-theme-primary text-theme-primary bg-theme-primary/5'
: 'border-transparent text-gray-400 hover:text-gray-600 hover:bg-gray-50'
}`}
>
<SortableContext
items={quiz.questions.map(q => q.id)}
strategy={verticalListSortingStrategy}
>
<div className="space-y-3">
<AnimatePresence>
{quiz.questions.map((question, index) => (
<SortableQuestionCard
key={question.id}
question={question}
index={index}
isExpanded={expandedId === question.id}
onToggleExpand={() => setExpandedId(expandedId === question.id ? null : question.id)}
onEdit={() => setEditingQuestion(question)}
onDelete={() => quiz.questions.length > 1 ? setShowDeleteConfirm(question.id) : null}
/>
))}
</AnimatePresence>
</div>
</SortableContext>
</DndContext>
<div className="flex items-center justify-center gap-2">
<List size={18} />
<span>Questions</span>
</div>
</button>
<button
onClick={() => setActiveTab('settings')}
className={`flex-1 py-3 font-bold text-center border-b-2 transition-all ${
activeTab === 'settings'
? 'border-theme-primary text-theme-primary bg-theme-primary/5'
: 'border-transparent text-gray-400 hover:text-gray-600 hover:bg-gray-50'
}`}
>
<div className="flex items-center justify-center gap-2">
<Settings size={18} />
<span>Settings</span>
</div>
</button>
</div>
{quiz.questions.length === 0 && (
<div className="text-center py-12 text-gray-400">
<p className="font-bold text-lg">No questions yet</p>
<p className="text-sm">Click "Add Question" to get started</p>
<div className="p-6 space-y-4 flex-1 min-h-0 overflow-y-auto">
{activeTab === 'questions' ? (
<>
<div className="flex items-center justify-between">
<h2 className="text-lg font-bold text-gray-700">Questions</h2>
<button
onClick={handleAddQuestion}
className="flex items-center gap-2 px-4 py-2 bg-theme-primary text-white rounded-xl font-bold hover:bg-theme-primary/90 transition shadow-md"
>
<Plus size={18} /> Add Question
</button>
</div>
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
>
<SortableContext
items={quiz.questions.map(q => q.id)}
strategy={verticalListSortingStrategy}
>
<div className="space-y-3">
<AnimatePresence>
{quiz.questions.map((question, index) => (
<SortableQuestionCard
key={question.id}
question={question}
index={index}
isExpanded={expandedId === question.id}
onToggleExpand={() => setExpandedId(expandedId === question.id ? null : question.id)}
onEdit={() => setEditingQuestion(question)}
onDelete={() => quiz.questions.length > 1 ? setShowDeleteConfirm(question.id) : null}
/>
))}
</AnimatePresence>
</div>
</SortableContext>
</DndContext>
{quiz.questions.length === 0 && (
<div className="text-center py-12 text-gray-400">
<p className="font-bold text-lg">No questions yet</p>
<p className="text-sm">Click "Add Question" to get started</p>
</div>
)}
</>
) : (
<div className="space-y-6">
<h2 className="text-lg font-bold text-gray-700">Game Settings</h2>
<GameConfigPanel
config={config}
onChange={handleConfigChange}
questionCount={quiz.questions.length}
compact={false}
/>
</div>
)}
</div>
<div className="p-6 bg-gray-50 border-t-2 border-gray-100 space-y-4">
<GameConfigPanel
config={config}
onChange={handleConfigChange}
questionCount={quiz.questions.length}
compact
/>
<button
onClick={handleStartGame}
disabled={!canStartGame}