Fix UI jank a bit
This commit is contained in:
parent
73c7d3efed
commit
3d6081823c
18 changed files with 193 additions and 87 deletions
|
|
@ -40,6 +40,8 @@ export const Landing: React.FC<LandingProps> = ({ onGenerate, onCreateManual, on
|
|||
const [editingDefaultConfig, setEditingDefaultConfig] = useState<GameConfig | null>(null);
|
||||
const [preferencesOpen, setPreferencesOpen] = useState(false);
|
||||
const [accountSettingsOpen, setAccountSettingsOpen] = useState(false);
|
||||
const [gameInfo, setGameInfo] = useState<{ randomNamesEnabled: boolean; quizTitle: string } | null>(null);
|
||||
const [checkingPin, setCheckingPin] = useState(false);
|
||||
|
||||
const hasImageFile = selectedFiles.some(f => f.type.startsWith('image/'));
|
||||
const hasDocumentFile = selectedFiles.some(f => !f.type.startsWith('image/') && !['application/pdf', 'text/plain', 'text/markdown', 'text/csv', 'text/html'].includes(f.type));
|
||||
|
|
@ -67,6 +69,30 @@ export const Landing: React.FC<LandingProps> = ({ onGenerate, onCreateManual, on
|
|||
}
|
||||
}, [libraryOpen, auth.isAuthenticated, fetchQuizzes]);
|
||||
|
||||
useEffect(() => {
|
||||
const checkGamePin = async () => {
|
||||
if (pin.trim().length === 6) {
|
||||
setCheckingPin(true);
|
||||
try {
|
||||
const backendUrl = import.meta.env.VITE_BACKEND_URL || 'http://localhost:3001';
|
||||
const response = await fetch(`${backendUrl}/api/games/${pin.trim()}`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setGameInfo({ randomNamesEnabled: data.randomNamesEnabled, quizTitle: data.quizTitle });
|
||||
} else {
|
||||
setGameInfo(null);
|
||||
}
|
||||
} catch {
|
||||
setGameInfo(null);
|
||||
}
|
||||
setCheckingPin(false);
|
||||
} else {
|
||||
setGameInfo(null);
|
||||
}
|
||||
};
|
||||
checkGamePin();
|
||||
}, [pin]);
|
||||
|
||||
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.files && e.target.files.length > 0) {
|
||||
const newFiles = Array.from(e.target.files);
|
||||
|
|
@ -128,7 +154,9 @@ export const Landing: React.FC<LandingProps> = ({ onGenerate, onCreateManual, on
|
|||
|
||||
const handleJoinSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (pin.trim() && name.trim()) onJoin(pin, name);
|
||||
if (pin.trim() && (gameInfo?.randomNamesEnabled || name.trim())) {
|
||||
onJoin(pin, name.trim() || 'Player');
|
||||
}
|
||||
};
|
||||
|
||||
const handleLoadQuiz = async (id: string) => {
|
||||
|
|
@ -145,7 +173,7 @@ export const Landing: React.FC<LandingProps> = ({ onGenerate, onCreateManual, on
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen p-4 text-center relative">
|
||||
<div className="flex flex-col items-center justify-center h-screen p-4 text-center relative overflow-hidden">
|
||||
<div className="absolute top-4 right-4 flex items-center gap-2">
|
||||
{auth.isAuthenticated && (
|
||||
<>
|
||||
|
|
@ -174,17 +202,17 @@ export const Landing: React.FC<LandingProps> = ({ onGenerate, onCreateManual, on
|
|||
initial={{ scale: 0.8, opacity: 0, rotate: -2 }}
|
||||
animate={{ scale: 1, opacity: 1, rotate: 0 }}
|
||||
transition={{ type: "spring", bounce: 0.5 }}
|
||||
className="bg-white text-gray-900 p-8 rounded-[2rem] shadow-[0_10px_0_rgba(0,0,0,0.1)] max-w-md w-full border-4 border-white/50"
|
||||
className="bg-white text-gray-900 p-6 md:p-8 rounded-[2rem] shadow-[0_10px_0_rgba(0,0,0,0.1)] max-w-md w-full border-4 border-white/50 max-h-[calc(100vh-2rem)] overflow-y-auto"
|
||||
>
|
||||
<div className="flex justify-center mb-6">
|
||||
<div className="bg-theme-primary p-4 rounded-3xl rotate-3 shadow-lg">
|
||||
<BrainCircuit size={48} className="text-white" />
|
||||
<div className="flex justify-center mb-4 md:mb-6">
|
||||
<div className="bg-theme-primary p-3 md:p-4 rounded-2xl md:rounded-3xl rotate-3 shadow-lg">
|
||||
<BrainCircuit size={36} className="text-white md:w-12 md:h-12" />
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="text-5xl font-black mb-2 text-theme-primary tracking-tight">Kaboot</h1>
|
||||
<p className="text-gray-500 font-bold mb-6">The AI Quiz Party</p>
|
||||
<h1 className="text-4xl md:text-5xl font-black mb-1 md:mb-2 text-theme-primary tracking-tight">Kaboot</h1>
|
||||
<p className="text-gray-500 font-bold mb-4 md:mb-6">The AI Quiz Party</p>
|
||||
|
||||
<div className="flex bg-gray-100 p-2 rounded-2xl mb-8">
|
||||
<div className="flex bg-gray-100 p-2 rounded-2xl mb-6 md:mb-8">
|
||||
<button
|
||||
onClick={() => setMode('HOST')}
|
||||
className={`flex-1 py-3 rounded-xl font-black text-lg transition-all duration-200 ${mode === 'HOST' ? 'bg-white shadow-md text-theme-primary scale-105' : 'text-gray-400 hover:text-gray-600'}`}
|
||||
|
|
@ -432,19 +460,27 @@ export const Landing: React.FC<LandingProps> = ({ onGenerate, onCreateManual, on
|
|||
onChange={(e) => setPin(e.target.value)}
|
||||
className="w-full p-4 text-xl font-bold border-2 border-gray-200 rounded-2xl focus:border-theme-primary focus:ring-4 focus:ring-theme-primary/20 outline-none text-center"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Nickname"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
className="w-full p-4 text-xl font-bold border-2 border-gray-200 rounded-2xl focus:border-theme-primary focus:ring-4 focus:ring-theme-primary/20 outline-none text-center"
|
||||
/>
|
||||
{gameInfo?.randomNamesEnabled ? (
|
||||
<div className="p-4 bg-theme-primary/10 rounded-2xl border-2 border-theme-primary/20">
|
||||
<p className="text-theme-primary font-bold text-center">
|
||||
You'll get a random name!
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Nickname"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
className="w-full p-4 text-xl font-bold border-2 border-gray-200 rounded-2xl focus:border-theme-primary focus:ring-4 focus:ring-theme-primary/20 outline-none text-center"
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!pin.trim() || !name.trim()}
|
||||
className="w-full bg-[#333] text-white py-4 rounded-2xl text-xl font-black shadow-[0_6px_0_#000] active:shadow-none active:translate-y-[6px] transition-all hover:bg-black flex items-center justify-center gap-3"
|
||||
disabled={!pin.trim() || (!gameInfo?.randomNamesEnabled && !name.trim()) || checkingPin}
|
||||
className="w-full bg-[#333] text-white py-4 rounded-2xl text-xl font-black shadow-[0_6px_0_#000] active:shadow-none active:translate-y-[6px] transition-all hover:bg-black flex items-center justify-center gap-3 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
<Play fill="currentColor" /> Join Game
|
||||
{checkingPin ? <Loader2 className="animate-spin" /> : <Play fill="currentColor" />} Join Game
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue