Skip to content

Commit 989e4a5

Browse files
feat: enhance modal components with improved styling, layout adjustments, and background scrolling prevention
1 parent 798c407 commit 989e4a5

6 files changed

Lines changed: 404 additions & 212 deletions

File tree

src/components/Analysis/CustomAnalysisModal.tsx

Lines changed: 103 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { useState } from 'react'
22
import { Chess } from 'chess.ts'
33
import toast from 'react-hot-toast'
44
import { ModalContainer } from '../Misc/ModalContainer'
5-
import { CloseIcon } from '../Icons/icons'
65

76
interface Props {
87
onSubmit: (type: 'pgn' | 'fen', data: string, name?: string) => void
@@ -45,109 +44,127 @@ export const CustomAnalysisModal: React.FC<Props> = ({ onSubmit, onClose }) => {
4544

4645
return (
4746
<ModalContainer dismiss={onClose}>
48-
<div className="flex w-[700px] max-w-[90vw] flex-col gap-4">
49-
<div className="relative flex items-center justify-center">
50-
<h2 className="text-2xl font-bold">Custom Analysis</h2>
47+
<div className="flex h-[550px] w-[600px] max-w-[90vw] flex-col overflow-hidden rounded-lg bg-background-1">
48+
{/* Header */}
49+
<div className="relative border-b border-white/10 p-4">
50+
<div className="text-center">
51+
<h2 className="text-xl font-bold text-primary">Custom Analysis</h2>
52+
<p className="text-xs text-secondary">
53+
Import a chess game from PGN notation or analyze a specific
54+
position using FEN notation
55+
</p>
56+
</div>
5157
<button
52-
className="absolute right-0 cursor-pointer border-none bg-none opacity-50 transition duration-200 hover:opacity-100"
58+
className="absolute right-4 top-4 text-secondary transition-colors hover:text-primary"
5359
title="Close"
5460
onClick={onClose}
5561
>
56-
{CloseIcon}
62+
<span className="material-symbols-outlined">close</span>
5763
</button>
5864
</div>
5965

60-
<p className="text-sm text-secondary">
61-
Import a chess game from PGN notation or analyze a specific position
62-
using FEN notation.
63-
</p>
66+
{/* Content */}
67+
<div className="flex-1 overflow-y-auto p-4">
68+
<div className="space-y-4">
69+
{/* Mode selector */}
70+
<div>
71+
<label
72+
htmlFor="import-type-selector"
73+
className="mb-1 block text-sm font-medium text-primary"
74+
>
75+
Import Type:
76+
</label>
77+
<div id="import-type-selector" className="flex gap-2">
78+
<button
79+
className={`flex-1 rounded px-4 py-2 text-sm font-medium transition-colors ${
80+
mode === 'pgn'
81+
? 'bg-human-4 text-white'
82+
: 'bg-background-2 text-primary hover:bg-background-3'
83+
}`}
84+
onClick={() => setMode('pgn')}
85+
>
86+
PGN Game
87+
</button>
88+
<button
89+
className={`flex-1 rounded px-4 py-2 text-sm font-medium transition-colors ${
90+
mode === 'fen'
91+
? 'bg-human-4 text-white'
92+
: 'bg-background-2 text-primary hover:bg-background-3'
93+
}`}
94+
onClick={() => setMode('fen')}
95+
>
96+
FEN Position
97+
</button>
98+
</div>
99+
</div>
64100

65-
{/* Mode selector */}
66-
<div className="flex gap-2">
67-
<button
68-
className={`rounded px-4 py-2 transition duration-200 ${
69-
mode === 'pgn'
70-
? 'bg-human-4 text-white'
71-
: 'bg-background-2 text-primary hover:bg-background-3'
72-
}`}
73-
onClick={() => setMode('pgn')}
74-
>
75-
Import PGN Game
76-
</button>
77-
<button
78-
className={`rounded px-4 py-2 transition duration-200 ${
79-
mode === 'fen'
80-
? 'bg-human-4 text-white'
81-
: 'bg-background-2 text-primary hover:bg-background-3'
82-
}`}
83-
onClick={() => setMode('fen')}
84-
>
85-
Analyze Position (FEN)
86-
</button>
87-
</div>
88-
89-
<div>
90-
<label
91-
htmlFor="analysis-name"
92-
className="mb-1 block text-sm font-medium"
93-
>
94-
Name (optional):
95-
</label>
96-
<input
97-
id="analysis-name"
98-
type="text"
99-
className="w-full rounded border border-background-3 bg-background-2 p-2 text-primary focus:border-human-4 focus:outline-none"
100-
placeholder="Enter a name for this analysis"
101-
value={name}
102-
onChange={(e) => setName(e.target.value)}
103-
/>
104-
</div>
101+
<div>
102+
<label
103+
htmlFor="analysis-name"
104+
className="mb-1 block text-sm font-medium text-primary"
105+
>
106+
Name (optional):
107+
</label>
108+
<input
109+
id="analysis-name"
110+
type="text"
111+
className="w-full rounded border border-background-3 bg-background-2 px-3 py-2 text-sm text-primary placeholder-secondary focus:border-human-4 focus:outline-none focus:ring-1 focus:ring-human-4"
112+
placeholder="Enter a name for this analysis"
113+
value={name}
114+
onChange={(e) => setName(e.target.value)}
115+
/>
116+
</div>
105117

106-
<div>
107-
<label
108-
htmlFor="analysis-data"
109-
className="mb-1 block text-sm font-medium"
110-
>
111-
{mode === 'pgn' ? 'PGN Data:' : 'FEN Position:'}
112-
</label>
113-
<textarea
114-
id="analysis-data"
115-
className="h-32 w-full rounded border border-background-3 bg-background-2 p-2 font-mono text-sm text-primary focus:border-human-4 focus:outline-none"
116-
placeholder={mode === 'pgn' ? examplePGN : exampleFEN}
117-
value={input}
118-
onChange={(e) => setInput(e.target.value)}
119-
/>
120-
<p className="mt-1 text-xs text-secondary">
121-
{mode === 'pgn'
122-
? 'Paste your PGN game notation here. Headers and variations are supported.'
123-
: 'Enter a valid FEN position string. This will set up the board for analysis.'}
124-
</p>
125-
</div>
118+
<div>
119+
<label
120+
htmlFor="analysis-data"
121+
className="mb-1 block text-sm font-medium text-primary"
122+
>
123+
{mode === 'pgn' ? 'PGN Data:' : 'FEN Position:'}
124+
</label>
125+
<textarea
126+
id="analysis-data"
127+
className="h-32 w-full rounded border border-background-3 bg-background-2 px-3 py-2 font-mono text-sm text-primary placeholder-secondary focus:border-human-4 focus:outline-none focus:ring-1 focus:ring-human-4"
128+
placeholder={mode === 'pgn' ? examplePGN : exampleFEN}
129+
value={input}
130+
onChange={(e) => setInput(e.target.value)}
131+
/>
132+
<p className="mt-1 text-xs text-secondary">
133+
{mode === 'pgn'
134+
? 'Paste your PGN game notation here. Headers and variations are supported.'
135+
: 'Enter a valid FEN position string. This will set up the board for analysis.'}
136+
</p>
137+
</div>
126138

127-
<div className="flex gap-2">
128-
<button
129-
className="rounded bg-background-2 px-3 py-1 text-xs text-secondary hover:bg-background-3"
130-
onClick={() => setInput(mode === 'pgn' ? examplePGN : exampleFEN)}
131-
>
132-
Use Example
133-
</button>
134-
<button
135-
className="rounded bg-background-2 px-3 py-1 text-xs text-secondary hover:bg-background-3"
136-
onClick={() => setInput('')}
137-
>
138-
Clear
139-
</button>
139+
<div className="flex gap-2">
140+
<button
141+
className="rounded bg-background-2 px-3 py-1 text-xs text-primary transition-colors hover:bg-background-3"
142+
onClick={() =>
143+
setInput(mode === 'pgn' ? examplePGN : exampleFEN)
144+
}
145+
>
146+
Use Example
147+
</button>
148+
<button
149+
className="rounded bg-background-2 px-3 py-1 text-xs text-primary transition-colors hover:bg-background-3"
150+
onClick={() => setInput('')}
151+
>
152+
Clear
153+
</button>
154+
</div>
155+
</div>
140156
</div>
141157

142-
<div className="flex justify-end gap-2">
158+
{/* Actions */}
159+
<div className="flex gap-3 border-t border-white/10 p-4">
143160
<button
144-
className="rounded bg-background-2 px-4 py-2 text-primary transition duration-200 hover:bg-background-3"
161+
className="flex-1 rounded bg-background-2 py-2 text-sm font-medium text-primary transition-colors hover:bg-background-3"
145162
onClick={onClose}
146163
>
147164
Cancel
148165
</button>
149166
<button
150-
className="hover:bg-human-5 rounded bg-human-4 px-4 py-2 text-white transition duration-200"
167+
className="flex-1 rounded bg-human-4 py-2 text-sm font-medium text-white transition-colors hover:bg-human-4/80"
151168
onClick={validateAndSubmit}
152169
>
153170
Analyze

src/components/Analysis/DownloadModelModal.tsx

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@ export const DownloadModelModal: React.FC<Props> = ({
1212
progress,
1313
download,
1414
}: Props) => {
15-
useEffect(() => {
16-
document.body.style.overflow = 'hidden'
17-
return () => {
18-
document.body.style.overflow = 'unset'
19-
}
20-
}, [])
21-
2215
return (
2316
<motion.div
2417
className="absolute left-0 top-0 z-20 flex h-screen w-screen flex-col items-center justify-center bg-black/90 px-4 md:px-0"

src/components/Misc/InstructionsModal.tsx

Lines changed: 121 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,65 @@ interface Props {
4444
instructionsType: InstructionsType
4545
}
4646

47+
const getFeatureIcon = (instructionsType: InstructionsType): string => {
48+
switch (instructionsType) {
49+
case 'againstMaia':
50+
return 'smart_toy'
51+
case 'handAndBrain':
52+
return 'diversity_3'
53+
case 'analysis':
54+
return 'analytics'
55+
case 'train':
56+
return 'fitness_center'
57+
case 'turing':
58+
return 'psychology'
59+
default:
60+
return 'help'
61+
}
62+
}
63+
64+
const getKeyFeatures = (instructionsType: InstructionsType): string[] => {
65+
switch (instructionsType) {
66+
case 'againstMaia':
67+
return [
68+
'Choose Maia opponent strength (1100-1900)',
69+
'Customizable time controls',
70+
'Start from custom positions',
71+
'Get rated based on your performance',
72+
]
73+
case 'handAndBrain':
74+
return [
75+
'Play as either Hand or Brain',
76+
'Team up with Maia as your partner',
77+
'Face off against Maia opponent teams',
78+
'Separate ratings for Hand and Brain play',
79+
]
80+
case 'analysis':
81+
return [
82+
'Analyze your Lichess games',
83+
'Compare Maia vs Stockfish analysis',
84+
'Visualize moves on the movemap',
85+
'Continue positions against Maia',
86+
]
87+
case 'train':
88+
return [
89+
'Solve Maia-inspired tactics puzzles',
90+
'Unlock moveaps after solving',
91+
'Track your tactics rating',
92+
'Learn human-like move patterns',
93+
]
94+
case 'turing':
95+
return [
96+
'Distinguish human from bot play',
97+
'Browse complete games',
98+
'Submit reasoning for your guesses',
99+
'Compete on the leaderboard',
100+
]
101+
default:
102+
return []
103+
}
104+
}
105+
47106
export const InstructionsModal: React.FC<Props> = ({
48107
instructionsType,
49108
}: Props) => {
@@ -58,31 +117,78 @@ export const InstructionsModal: React.FC<Props> = ({
58117
setOpenedModals({ ...openedModals, [instructionsType]: true })
59118
}
60119

120+
const features = getKeyFeatures(instructionsType)
121+
61122
return (
62123
<AnimatePresence>
63124
<ModalContainer dismiss={dismiss} className="z-50">
64-
<div className="relative flex flex-col gap-4">
125+
<div className="relative flex h-[550px] w-[600px] max-w-[90vw] flex-col overflow-hidden rounded-lg bg-background-1">
65126
<button
66127
title="Close"
67128
onClick={dismiss}
68-
className="absolute -right-4 -top-2 cursor-pointer border-none bg-none opacity-50 outline-none transition duration-300 hover:opacity-100"
129+
className="absolute right-4 top-4 z-10 text-secondary transition-colors hover:text-primary"
69130
>
70-
{CloseIcon}
131+
<span className="material-symbols-outlined">close</span>
71132
</button>
72-
<h2 className="text-center text-2xl font-bold">
73-
{titles[instructionsType]}
74-
</h2>
75-
<div className="max-w-[600px]">
76-
<Markdown>{content[instructionsType]}</Markdown>
77-
<div className="flex items-center justify-end">
78-
<button
79-
onClick={dismiss}
80-
className="flex items-center justify-center rounded-sm bg-human-3 px-4 py-2 transition duration-200 hover:bg-human-4"
81-
>
82-
Continue
83-
</button>
133+
134+
{/* Header */}
135+
<div className="border-b border-white/10 p-4">
136+
<div className="flex items-center gap-3">
137+
<span className="material-symbols-outlined text-2xl text-human-4">
138+
{getFeatureIcon(instructionsType)}
139+
</span>
140+
<div>
141+
<h2 className="text-xl font-bold text-primary">
142+
{titles[instructionsType]}
143+
</h2>
144+
<p className="text-xs text-secondary">
145+
Learn how to use this feature effectively
146+
</p>
147+
</div>
84148
</div>
85149
</div>
150+
151+
{/* Key Features */}
152+
<div className="border-b border-white/10 p-4">
153+
<h3 className="mb-2 text-sm font-medium text-primary">
154+
Key Features
155+
</h3>
156+
<div className="grid grid-cols-1 gap-2">
157+
{features.map((feature, index) => (
158+
<div key={index} className="flex items-center gap-2 text-sm">
159+
<span
160+
className="material-symbols-outlined text-human-4"
161+
style={{ fontSize: '16px' }}
162+
>
163+
check_circle
164+
</span>
165+
<span className="text-primary">{feature}</span>
166+
</div>
167+
))}
168+
</div>
169+
</div>
170+
171+
{/* Description */}
172+
<div className="flex-1 overflow-y-auto p-4">
173+
<h3 className="mb-2 text-sm font-medium text-primary">
174+
How it Works
175+
</h3>
176+
<div className="prose prose-sm max-w-none">
177+
<div className="text-sm leading-relaxed text-secondary">
178+
<Markdown>{content[instructionsType]}</Markdown>
179+
</div>
180+
</div>
181+
</div>
182+
183+
{/* Action */}
184+
<div className="border-t border-white/10 p-4">
185+
<button
186+
onClick={dismiss}
187+
className="w-full rounded bg-human-4 py-2 text-sm font-medium text-white transition-colors hover:bg-human-4/80"
188+
>
189+
Get Started
190+
</button>
191+
</div>
86192
</div>
87193
</ModalContainer>
88194
</AnimatePresence>

0 commit comments

Comments
 (0)