Lashtw commited on
Commit
2db8c1d
·
verified ·
1 Parent(s): 778bf7f

Upload 9 files

Browse files
Files changed (1) hide show
  1. src/views/StudentView.js +40 -21
src/views/StudentView.js CHANGED
@@ -192,14 +192,16 @@ export async function renderStudentView() {
192
  return `
193
  <div id="monster-container-fixed" class="fixed top-32 left-8 z-50 flex flex-col items-center group pointer-events-none sm:pointer-events-auto w-32 h-32">
194
  <!-- Walking Container -->
 
195
  <div class="pixel-art-container relative transform transition-transform duration-500 ease-out origin-center"
196
- style="transform: scale(${currentScale}); animation: walk-patrol 15s linear infinite;">
197
 
198
- <div class="pixel-monster w-28 h-28 drop-shadow-2xl filter" style="animation: breathe 3s infinite ease-in-out;">
 
199
  ${generateMonsterSVG(monster)}
200
  </div>
201
 
202
- <!-- Level Indicator -->
203
  <div class="absolute -bottom-2 -right-2 bg-gray-900/90 text-xs text-yellow-400 px-2 py-0.5 rounded-full border border-yellow-500/50 font-mono font-bold transform scale-75 origin-top-left whitespace-nowrap">
204
  Lv.${1 + totalCompleted}
205
  </div>
@@ -234,12 +236,19 @@ export async function renderStudentView() {
234
  0%, 100% { transform: translateY(0); filter: brightness(1); }
235
  50% { transform: translateY(-3px); filter: brightness(1.1); }
236
  }
237
- @keyframes walk-patrol {
238
- 0% { transform: translateX(0) scaleX(1) scale(${currentScale}); }
239
- 45% { transform: translateX(120px) scaleX(1) scale(${currentScale}); }
240
- 50% { transform: translateX(120px) scaleX(-1) scale(${currentScale}); }
241
- 95% { transform: translateX(0) scaleX(-1) scale(${currentScale}); }
242
- 100% { transform: translateX(0) scaleX(1) scale(${currentScale}); }
 
 
 
 
 
 
 
243
  }
244
  </style>
245
  `;
@@ -281,17 +290,20 @@ export async function renderStudentView() {
281
  return `
282
  <div class="min-h-screen p-4 pb-32 max-w-md mx-auto sm:max-w-4xl pt-24 sm:pt-4">
283
  <header class="flex justify-end items-center mb-6 sticky top-0 bg-slate-900/95 backdrop-blur z-20 py-4 px-2 -mx-2 border-b border-gray-800">
284
- <div class="flex flex-col items-end">
285
- <div class="flex items-center space-x-2">
286
- <div class="w-2 h-2 rounded-full bg-green-500 animate-pulse"></div>
287
- <span class="text-gray-400 text-sm truncate max-w-[150px]">${nickname}</span>
 
 
 
288
  </div>
289
- <div class="text-xs text-gray-500 mt-1">教室: <span class="font-mono text-cyan-400 font-bold">${roomCode}</span></div>
 
 
 
 
290
  </div>
291
- <!-- Logo removed/minimized since we have Monster -->
292
- <!-- <div>
293
- <h1 class="text-xl font-bold italic text-white tracking-widest">VIBECODING</h1>
294
- </div> -->
295
  </header>
296
 
297
  <div class="space-y-4">
@@ -344,12 +356,11 @@ export async function renderStudentView() {
344
  </div>
345
 
346
  <!-- Peer Learning FAB -->
347
- <button onclick="window.openPeerModal()" class="fixed bottom-8 left-1/2 -translate-x-1/2 bg-purple-600 hover:bg-purple-500 text-white rounded-full p-5 shadow-[0_0_20px_rgba(147,51,234,0.6)] transition-transform hover:scale-110 active:scale-90 z-40 flex items-center space-x-2"
348
  title="查看同學作業">
349
- <svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
350
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0z" />
351
  </svg>
352
- <span class="font-bold text-lg hidden sm:inline">查看同學提示詞</span>
353
  </button>
354
  </div>
355
  `;
@@ -489,6 +500,14 @@ function participantDataCheck(roomCode, userId) {
489
  return true;
490
  }
491
 
 
 
 
 
 
 
 
 
492
  // Peer Learning Modal Logic
493
  function renderPeerModal() {
494
  // We need to re-fetch challenges for the dropdown?
 
192
  return `
193
  <div id="monster-container-fixed" class="fixed top-32 left-8 z-50 flex flex-col items-center group pointer-events-none sm:pointer-events-auto w-32 h-32">
194
  <!-- Walking Container -->
195
+ <!-- Walking Container (Handles Movement Only) -->
196
  <div class="pixel-art-container relative transform transition-transform duration-500 ease-out origin-center"
197
+ style="transform: scale(${currentScale}); animation: patrol-move 15s linear infinite;">
198
 
199
+ <!-- Monster Sprite (Handles Flip & Breathe) -->
200
+ <div class="pixel-monster w-28 h-28 drop-shadow-2xl filter" style="animation: breathe 3s infinite ease-in-out, patrol-flip 15s linear infinite;">
201
  ${generateMonsterSVG(monster)}
202
  </div>
203
 
204
+ <!-- Level Indicator (No Flip) -->
205
  <div class="absolute -bottom-2 -right-2 bg-gray-900/90 text-xs text-yellow-400 px-2 py-0.5 rounded-full border border-yellow-500/50 font-mono font-bold transform scale-75 origin-top-left whitespace-nowrap">
206
  Lv.${1 + totalCompleted}
207
  </div>
 
236
  0%, 100% { transform: translateY(0); filter: brightness(1); }
237
  50% { transform: translateY(-3px); filter: brightness(1.1); }
238
  }
239
+ @keyframes patrol-move {
240
+ 0% { transform: translateX(0); }
241
+ 45% { transform: translateX(120px); }
242
+ 55% { transform: translateX(120px); }
243
+ 95% { transform: translateX(0); }
244
+ 100% { transform: translateX(0); }
245
+ }
246
+ @keyframes patrol-flip {
247
+ 0% { transform: scaleX(1); }
248
+ 49% { transform: scaleX(1); }
249
+ 50% { transform: scaleX(-1); }
250
+ 99% { transform: scaleX(-1); }
251
+ 100% { transform: scaleX(1); }
252
  }
253
  </style>
254
  `;
 
290
  return `
291
  <div class="min-h-screen p-4 pb-32 max-w-md mx-auto sm:max-w-4xl pt-24 sm:pt-4">
292
  <header class="flex justify-end items-center mb-6 sticky top-0 bg-slate-900/95 backdrop-blur z-20 py-4 px-2 -mx-2 border-b border-gray-800">
293
+ <div class="flex items-center space-x-4">
294
+ <div class="flex flex-col items-end">
295
+ <div class="flex items-center space-x-2">
296
+ <div class="w-2 h-2 rounded-full bg-green-500 animate-pulse"></div>
297
+ <span class="text-gray-400 text-sm truncate max-w-[150px]">${nickname}</span>
298
+ </div>
299
+ <div class="text-xs text-gray-500 mt-1">教室: <span class="font-mono text-cyan-400 font-bold">${roomCode}</span></div>
300
  </div>
301
+ <button onclick="window.logout()" class="text-gray-500 hover:text-red-400 transition-colors p-2" title="登出">
302
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
303
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
304
+ </svg>
305
+ </button>
306
  </div>
 
 
 
 
307
  </header>
308
 
309
  <div class="space-y-4">
 
356
  </div>
357
 
358
  <!-- Peer Learning FAB -->
359
+ <button onclick="window.openPeerModal()" class="fixed bottom-6 right-6 bg-purple-600 hover:bg-purple-500 text-white rounded-full p-4 shadow-xl shadow-purple-600/40 transition-transform hover:scale-110 active:scale-90 z-40"
360
  title="查看同學作業">
361
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
362
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0z" />
363
  </svg>
 
364
  </button>
365
  </div>
366
  `;
 
500
  return true;
501
  }
502
 
503
+ window.logout = () => {
504
+ if (!confirm("確定要登出嗎?")) return;
505
+ localStorage.removeItem('vibecoding_user_id');
506
+ localStorage.removeItem('vibecoding_room_code');
507
+ localStorage.removeItem('vibecoding_nickname');
508
+ window.location.reload();
509
+ };
510
+
511
  // Peer Learning Modal Logic
512
  function renderPeerModal() {
513
  // We need to re-fetch challenges for the dropdown?