@@ -80,7 +80,6 @@ export default function GroupChatGameFlow() {
8080 selectOption,
8181 handleOptionHover,
8282 stageTimeLimitMs,
83- totalStages,
8483 groupName,
8584 groupMemberCount,
8685 } = useGroupChatGame ( { onComplete : handleComplete } ) ;
@@ -89,51 +88,29 @@ export default function GroupChatGameFlow() {
8988 chatEndRef . current ?. scrollIntoView ( { behavior : 'smooth' } ) ;
9089 } , [ chatMessages , isTypingIndicatorVisible , gamePhase ] ) ;
9190
92- if ( gamePhase === 'completed' ) {
93- if ( submitStatus === 'loading' ) {
94- return (
95- < div className = "flex min-h-screen items-center justify-center bg-gray-100" >
96- < Spinner message = "送信中..." />
97- </ div >
98- ) ;
99- }
100- if ( submitStatus === 'error' ) {
101- return (
102- < div className = "flex min-h-screen flex-col items-center justify-center gap-4 bg-gray-100" >
103- < p className = "text-lg font-semibold text-red-600" >
104- 通信に失敗しました
105- </ p >
106- < button
107- onClick = { handleRetry }
108- className = "rounded-lg bg-blue-600 px-6 py-3 font-semibold text-white transition hover:bg-blue-700"
109- >
110- リトライ
111- </ button >
112- </ div >
113- ) ;
114- }
115- return (
116- < div className = "flex min-h-screen items-center justify-center bg-gray-100" >
117- < div className = "text-center" >
118- < p className = "text-lg font-bold" > 完了しました</ p >
119- < p className = "mt-2 text-sm text-gray-500" >
120- Loading画面へ移動します...
121- </ p >
122- </ div >
123- </ div >
124- ) ;
125- }
91+ const isOverlayActive = [ 'tutorial' , 'stage-cutin' , 'completed' ] . includes (
92+ gamePhase
93+ ) ;
12694
12795 const timerRatio = remainingTimeMs / stageTimeLimitMs ;
128- const timerColorClass =
129- timerRatio > 0.5
130- ? 'bg-green-500'
131- : timerRatio > 0.2
132- ? 'bg-amber-500'
133- : 'bg-red-500' ;
13496
13597 return (
136- < div className = "flex min-h-screen flex-col items-center justify-center bg-gray-100 p-4" >
98+ < div
99+ className = "fixed inset-0 flex flex-col items-center justify-center overflow-hidden p-4"
100+ style = { { backgroundColor : '#F0D44A' , height : '100dvh' } }
101+ >
102+ { /* 背景のドット模様(CSSで描画) - オーバーレイ非表示時のみ */ }
103+ { ! isOverlayActive && (
104+ < div
105+ className = "absolute inset-0 z-0 opacity-40"
106+ style = { {
107+ backgroundImage :
108+ 'radial-gradient(circle, rgba(255,255,255,0.8) 1.0px, transparent 4px)' ,
109+ backgroundSize : '16px 16px, cover' ,
110+ } }
111+ />
112+ ) }
113+
137114 { /* --- チュートリアルオーバーレイ --- */ }
138115 { gamePhase === 'tutorial' && (
139116 < div
@@ -143,16 +120,16 @@ export default function GroupChatGameFlow() {
143120 onKeyDown = { ( e ) => {
144121 if ( e . key === 'Enter' || e . key === ' ' ) startGame ( ) ;
145122 } }
146- className = "fixed inset-0 z-50 flex cursor-pointer flex-col items-center justify-center bg-black/30 "
123+ className = "fixed inset-0 z-50 flex cursor-pointer flex-col items-center justify-center bg-black/60 "
147124 >
148- < div className = "animate-[fadeInUp_0.4s_ease-out] px-6 text-center" >
149- < p className = "text-lg font-black tracking-widest text-white drop-shadow-lg " >
150- 指示‼️
125+ < div className = "z-10 animate-[fadeInUp_0.4s_ease-out] px-6 text-center" >
126+ < p className = "text-3xl font-black tracking-widest text-white drop-shadow-md " >
127+ 適切に応答せよ!
151128 </ p >
152- < p className = "mt-6 whitespace-pre-line text-xl font-bold leading-relaxed text-white drop-shadow-lg " >
129+ < p className = "mt-6 whitespace-pre-line text-lg font-bold leading-relaxed text-white drop-shadow-md " >
153130 { TUTORIAL_TEXT }
154131 </ p >
155- < p className = "mt-8 animate-pulse text-sm text-white/70 " >
132+ < p className = "mt-8 animate-pulse text-sm font-bold text-white/80 " >
156133 タップして開始
157134 </ p >
158135 </ div >
@@ -161,7 +138,7 @@ export default function GroupChatGameFlow() {
161138
162139 { /* --- カットイン演出 --- */ }
163140 { gamePhase === 'stage-cutin' && currentStage && (
164- < div className = "fixed inset-0 z-40 flex items-center justify-center bg-black/60" >
141+ < div className = "fixed inset-0 z-40 flex flex-col items-center justify-center bg-black/60" >
165142 < div className = "animate-[fadeInUp_0.3s_ease-out] text-center" >
166143 < p className = "text-4xl font-black text-white drop-shadow-lg" >
167144 場面{ currentStageIndex + 1 }
@@ -176,74 +153,102 @@ export default function GroupChatGameFlow() {
176153 </ div >
177154 ) }
178155
156+ { /* --- 終了(完了)オーバーレイ --- */ }
157+ { gamePhase === 'completed' && (
158+ < div className = "fixed inset-0 z-50 flex flex-col items-center justify-center bg-black/60" >
159+ < div className = "z-10 animate-[fadeInUp_0.4s_ease-out] px-6 text-center" >
160+ { submitStatus === 'error' ? (
161+ < >
162+ < p className = "text-4xl font-black tracking-widest text-[#e03131] drop-shadow-md bg-white px-6 py-2 rounded-xl border-[4px] border-black" >
163+ 通信エラー!
164+ </ p >
165+ < button
166+ onClick = { handleRetry }
167+ className = "mt-6 flex items-center justify-center rounded-xl border-[4px] border-black bg-white px-8 py-3 text-xl font-black text-black shadow-[4px_4px_0_0_#000] transition-transform hover:-translate-y-1 hover:shadow-[6px_6px_0_0_#000] mx-auto"
168+ >
169+ リトライする
170+ </ button >
171+ </ >
172+ ) : (
173+ < >
174+ < p className = "text-6xl font-black tracking-widest text-white drop-shadow-lg" >
175+ 終了!
176+ </ p >
177+ { submitStatus === 'loading' && (
178+ < div className = "mt-8 flex justify-center text-white" >
179+ < Spinner message = "送信中..." />
180+ </ div >
181+ ) }
182+ { submitStatus === 'success' && (
183+ < p className = "mt-6 text-lg font-bold text-white/80" >
184+ Loading画面へ移動します...
185+ </ p >
186+ ) }
187+ </ >
188+ ) }
189+ </ div >
190+ </ div >
191+ ) }
192+
179193 { /* --- スマホフレーム --- */ }
180194 < div
181- className = "flex w-full max-w-sm flex-col overflow-hidden rounded-2xl border-2 border-gray-800 bg-white shadow-2xl "
195+ className = "relative z-10 flex w-full max-w-sm flex-col overflow-hidden rounded-[24px] border-[6px] border-black bg-white shadow-[8px_8px_0px_0px_rgba(0,0,0,0.3)] transition-all "
182196 style = { { height : 'min(90vh, 700px)' } }
183197 >
184198 { /* ヘッダー: LINE風 */ }
185- < header className = "flex items-center justify-between bg-blue-500 px-4 py-3 text-white" >
199+ < header className = "flex items-center justify-between border-b-[6px] border-black bg-[#2d5be3] px-4 py-3 text-white" >
186200 < div className = "flex items-center gap-2" >
187- < span className = "inline-block h-2 w-2 rounded-full bg-green-300 " />
188- < h1 className = "text-sm font-bold " >
201+ < span className = "inline-block h-3 w-3 rounded-full border-[2px] border-black bg-[#57d071] " />
202+ < h1 className = "text-lg font-black tracking-widest " >
189203 { groupName } ({ groupMemberCount } )
190204 </ h1 >
191205 </ div >
192- { currentStage && (
193- < span className = "rounded-full bg-white/20 px-2 py-0.5 text-[10px] font-medium" >
194- { currentStageIndex + 1 } /{ totalStages }
195- </ span >
196- ) }
206+ < button
207+ onClick = { ( ) => window . location . reload ( ) }
208+ className = "flex items-center justify-center rounded-full border-[3px] border-black bg-[#e03131] px-4 py-1 text-xs font-black shadow-[2px_2px_0_0_#000] transition-all hover:translate-y-0.5 hover:shadow-[0_0_0_0_#000]"
209+ >
210+ RESET
211+ </ button >
197212 </ header >
198213
199214 { /* チャットエリア */ }
200- < div className = "flex-1 overflow-y-auto bg-sky-100 px-3 py-3" >
201- < div className = "space-y-3" >
202- { /* DAYラベル */ }
203- { currentStage && (
204- < >
205- < p className = "text-center text-[10px] text-gray-400" > TODAY</ p >
206- < p className = "text-center" >
207- < span className = "inline-block rounded-full bg-gray-300/60 px-3 py-0.5 text-[10px] text-gray-500" >
208- — { currentStage . dayLabel } —
209- </ span >
210- </ p >
211- </ >
212- ) }
213-
215+ < div className = "flex-1 overflow-y-auto bg-[#dae5f3] px-3 py-4" >
216+ < div className = "space-y-4" >
214217 { chatMessages . map ( ( msg , i ) =>
215- msg . type === 'bot' ? (
216- < div
217- key = { `s${ currentStageIndex } -${ i } -${ msg . botId } ` }
218- className = "flex items-start gap-2"
219- >
218+ msg . type === 'separator' ? (
219+ < div key = { `msg-${ i } ` } className = "my-2 flex justify-center" >
220+ < span className = "rounded-full border-[2px] border-gray-300 bg-white/50 px-4 py-1 text-[10px] font-bold text-gray-500" >
221+ { msg . label }
222+ </ span >
223+ </ div >
224+ ) : msg . type === 'bot' ? (
225+ < div key = { `msg-${ i } ` } className = "flex items-start gap-2" >
220226 { ( ( ) => {
221227 const bot = getBotByBotId ( msg . botId ) ;
222228 return (
223- < div className = "flex flex-col items-center gap-0.5 " >
229+ < div className = "mt-1 flex flex-col items-center gap-1 " >
224230 < div
225- className = { `flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-xs font-bold ${
231+ className = { `flex h-10 w-10 shrink-0 items-center justify-center rounded-full border-[3px] border-black text-sm font-black shadow-[2px_2px_0_0_#000] ${
226232 bot ?. color ?? 'bg-gray-400 text-white'
227233 } `}
228234 >
229235 { bot ?. avatarLabel ?? '?' }
230236 </ div >
231- < span className = "text-[9px] text-gray-500" >
232- { bot ?. name }
233- </ span >
234237 </ div >
235238 ) ;
236239 } ) ( ) }
237- < div className = "max-w-[70%] rounded-lg rounded-tl-none bg-white px-3 py-2 text-sm shadow-sm" >
238- { msg . text }
240+ < div className = "flex flex-col" >
241+ < span className = "mb-1 ml-1 text-[10px] font-bold text-gray-600" >
242+ { getBotByBotId ( msg . botId ) ?. name }
243+ </ span >
244+ < div className = "max-w-[80%] rounded-2xl rounded-tl-none border-[3px] border-black bg-white px-4 py-3 text-sm font-bold text-black shadow-[2px_2px_0_0_#000]" >
245+ { msg . text }
246+ </ div >
239247 </ div >
240248 </ div >
241249 ) : (
242- < div
243- key = { `s${ currentStageIndex } -${ i } -user` }
244- className = "flex justify-end"
245- >
246- < div className = "max-w-[70%] rounded-lg rounded-tr-none bg-green-400 px-3 py-2 text-sm text-white shadow-sm" >
250+ < div key = { `msg-${ i } ` } className = "flex justify-end" >
251+ < div className = "max-w-[80%] rounded-2xl rounded-tr-none border-[3px] border-black bg-[#57d071] px-4 py-3 text-sm font-bold text-white shadow-[2px_2px_0_0_#000]" >
247252 { msg . text }
248253 </ div >
249254 </ div >
@@ -252,19 +257,19 @@ export default function GroupChatGameFlow() {
252257
253258 { /* 入力中インジケータ */ }
254259 { isTypingIndicatorVisible && typingBotName && (
255- < div className = "flex items-center justify-center gap-2 rounded-full bg-white/80 px-4 py-1.5 shadow-sm mx-auto w-fit " >
256- < span className = "inline-flex gap-0.5 " >
257- < span className = "h-1.5 w-1.5 animate-bounce rounded-full bg-gray-500 " />
260+ < div className = "mx-auto flex w-fit items-center justify-center gap-2 rounded-full border-[3px] border-black bg-white px-4 py-2 shadow-[2px_2px_0_0_#000] " >
261+ < span className = "inline-flex gap-1 " >
262+ < span className = "h-1.5 w-1.5 animate-bounce rounded-full bg-black " />
258263 < span
259- className = "h-1.5 w-1.5 animate-bounce rounded-full bg-gray-500 "
264+ className = "h-1.5 w-1.5 animate-bounce rounded-full bg-black "
260265 style = { { animationDelay : '0.15s' } }
261266 />
262267 < span
263- className = "h-1.5 w-1.5 animate-bounce rounded-full bg-gray-500 "
268+ className = "h-1.5 w-1.5 animate-bounce rounded-full bg-black "
264269 style = { { animationDelay : '0.3s' } }
265270 />
266271 </ span >
267- < span className = "text-sm font-medium text-gray-600 " >
272+ < span className = "text-sm font-bold text-black " >
268273 { typingBotName } が返信中
269274 </ span >
270275 </ div >
@@ -274,53 +279,57 @@ export default function GroupChatGameFlow() {
274279 </ div >
275280
276281 { /* 下部: タイマー + 選択肢 */ }
277- < div className = "border-t border-gray-800 bg-amber-50 " >
282+ < div className = "border-t-[6px] border-black bg-[#f1cf44] pb-6 " >
278283 { gamePhase === 'waiting-input' && currentStage && (
279- < div className = "px-3 pb-3 pt-2" >
284+ < >
280285 { /* タイマーゲージ */ }
281- < div className = "mb -2 h-1.5 overflow-hidden rounded- full bg-gray-200 " >
286+ < div className = "h -2 w- full bg-black " >
282287 < div
283- className = { ` h-full transition-all duration-100 ${ timerColorClass } ` }
288+ className = " h-full bg-[#e03131] transition-all duration-100"
284289 style = { { width : `${ timerRatio * 100 } %` } }
285290 />
286291 </ div >
287292 { /* 選択肢 */ }
288- { currentStage . options . some ( ( o ) => o . label ) ? (
289- < div className = "flex flex-col gap-1.5" >
290- { currentStage . options . map ( ( opt , idx ) => (
291- < button
292- key = { idx }
293- type = "button"
294- onMouseEnter = { ( ) => handleOptionHover ( idx + 1 ) }
295- onFocus = { ( ) => handleOptionHover ( idx + 1 ) }
296- onClick = { ( ) => selectOption ( idx + 1 ) }
297- className = "flex items-center gap-2 rounded-lg border border-gray-300 bg-white px-3 py-2.5 text-left text-sm transition-colors hover:bg-gray-50 active:bg-gray-100"
298- >
299- < span className = "text-base" > { opt . emoji } </ span >
300- < span > { opt . label } </ span >
301- </ button >
302- ) ) }
303- </ div >
304- ) : (
305- < div className = "grid grid-cols-4 gap-2" >
306- { currentStage . options . map ( ( opt , idx ) => (
307- < button
308- key = { idx }
309- type = "button"
310- onMouseEnter = { ( ) => handleOptionHover ( idx + 1 ) }
311- onFocus = { ( ) => handleOptionHover ( idx + 1 ) }
312- onClick = { ( ) => selectOption ( idx + 1 ) }
313- className = "flex items-center justify-center rounded-lg border border-gray-300 bg-white py-3 text-3xl transition-colors hover:bg-gray-50 active:bg-gray-100"
314- >
315- { opt . emoji }
316- </ button >
317- ) ) }
318- </ div >
319- ) }
320- </ div >
293+ < div className = "px-5 pt-5 pb-2" >
294+ { currentStage . options . some ( ( o ) => o . label ) ? (
295+ < div className = "flex flex-col gap-3" >
296+ { currentStage . options . map ( ( opt , idx ) => (
297+ < button
298+ key = { idx }
299+ type = "button"
300+ onMouseEnter = { ( ) => handleOptionHover ( idx + 1 ) }
301+ onFocus = { ( ) => handleOptionHover ( idx + 1 ) }
302+ onClick = { ( ) => selectOption ( idx + 1 ) }
303+ className = "flex items-center gap-3 rounded-xl border-[3px] border-black bg-white px-5 py-3.5 text-left font-bold transition-transform hover:-translate-y-1 hover:shadow-[4px_4px_0_0_#000]"
304+ >
305+ < span className = "text-lg" > { opt . emoji } </ span >
306+ < span className = "text-[13px] text-black" >
307+ { opt . label }
308+ </ span >
309+ </ button >
310+ ) ) }
311+ </ div >
312+ ) : (
313+ < div className = "grid grid-cols-4 gap-3" >
314+ { currentStage . options . map ( ( opt , idx ) => (
315+ < button
316+ key = { idx }
317+ type = "button"
318+ onMouseEnter = { ( ) => handleOptionHover ( idx + 1 ) }
319+ onFocus = { ( ) => handleOptionHover ( idx + 1 ) }
320+ onClick = { ( ) => selectOption ( idx + 1 ) }
321+ className = "flex items-center justify-center rounded-xl border-[3px] border-black bg-white py-4 text-3xl font-bold transition-transform hover:-translate-y-1 hover:shadow-[4px_4px_0_0_#000]"
322+ >
323+ { opt . emoji }
324+ </ button >
325+ ) ) }
326+ </ div >
327+ ) }
328+ </ div >
329+ </ >
321330 ) }
322331 { ( gamePhase === 'chat-playing' || gamePhase === 'stage-cutin' ) && (
323- < p className = "py-3 text-center text-xs text-gray-400 " >
332+ < p className = "py-6 text-center text-sm font-bold text-black/60 " >
324333 メッセージを表示しています...
325334 </ p >
326335 ) }
0 commit comments