iamfebin commited on
Commit
080f0c0
·
1 Parent(s): 2538dbc

feat: implement Metro-style Windows Phone mobile responsive UI

Browse files
algospaced-ui/src/App.tsx CHANGED
@@ -31,6 +31,7 @@ export default function App() {
31
  mysql: { isOpen: false, isMinimized: false },
32
  });
33
  const [activeWindow, setActiveWindow] = useState<string>('queue');
 
34
 
35
  // Start Menu and System info
36
  const [isStartOpen, setIsStartOpen] = useState(false);
@@ -105,6 +106,17 @@ export default function App() {
105
  };
106
  }, []);
107
 
 
 
 
 
 
 
 
 
 
 
 
108
  useEffect(() => {
109
  if (user) {
110
  fetchStreak();
@@ -352,6 +364,7 @@ export default function App() {
352
  }
353
 
354
  const username = user.email ? user.email.split('@')[0] : 'Player_One';
 
355
 
356
  return (
357
  <div
@@ -367,111 +380,246 @@ export default function App() {
367
  />
368
 
369
  {/* Desktop Icons column */}
370
- <nav className="fixed left-0 top-12 h-[calc(100vh-80px)] w-[140px] flex flex-col items-center py-gutter-md space-y-6 z-10 overflow-y-auto custom-scrollbar select-none">
371
-
372
- {/* Daily Queue Shortcut */}
373
- <button
374
- onClick={() => toggleWindowMinimize('queue')}
375
- className="flex flex-col items-center justify-center text-ink-black gap-2.5 p-2 w-full group icon-hover-shift cursor-pointer outline-none"
376
- >
377
- <div className="w-16 h-16 bg-paper-white border-[3px] border-ink-black flex items-center justify-center gadget-shadow group-hover:bg-secondary-container transition-colors shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)]">
378
- <span className="material-symbols-outlined text-4xl" style={{ fontVariationSettings: "'FILL' 1" }}>
379
- view_list
 
 
 
 
 
380
  </span>
381
- </div>
382
- <span className="font-icon-label text-[9px] bg-ink-black text-white px-2 py-1 border-[3px] border-ink-black text-center leading-tight shadow-[2px_2px_0px_0px_#fde047] uppercase">
383
- DAILY<br/>QUEUE
384
- </span>
385
- </button>
386
-
387
- {/* Journey Path Shortcut */}
388
- <button
389
- onClick={() => toggleWindowMinimize('journey')}
390
- className="flex flex-col items-center justify-center text-ink-black gap-2.5 p-2 w-full group icon-hover-shift cursor-pointer outline-none"
391
- >
392
- <div className="w-16 h-16 bg-paper-white border-[3px] border-ink-black flex items-center justify-center gadget-shadow group-hover:bg-secondary-container transition-colors shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)]">
393
- <span className="material-symbols-outlined text-4xl" style={{ fontVariationSettings: "'FILL' 1" }}>
394
- route
395
  </span>
396
- </div>
397
- <span className="font-icon-label text-[9px] bg-ink-black text-white px-2 py-1 border-[3px] border-ink-black text-center leading-tight shadow-[2px_2px_0px_0px_#fde047] uppercase">
398
- JOURNEY<br/>PATH
399
- </span>
400
- </button>
401
-
402
- {/* Drive Sync Shortcut */}
403
- <button
404
- onClick={triggerSync}
405
- className="flex flex-col items-center justify-center text-ink-black gap-2.5 p-2 w-full group icon-hover-shift cursor-pointer outline-none"
406
- >
407
- <div className="w-16 h-16 bg-paper-white border-[3px] border-ink-black flex items-center justify-center gadget-shadow group-hover:bg-secondary-container transition-colors shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)]">
408
- <span className="material-symbols-outlined text-4xl" style={{ fontVariationSettings: "'FILL' 1" }}>
409
- cloud_sync
410
  </span>
411
- </div>
412
- <span className="font-icon-label text-[9px] bg-ink-black text-white px-2 py-1 border-[3px] border-ink-black text-center leading-tight shadow-[2px_2px_0px_0px_#fde047] uppercase">
413
- DRIVE<br/>SYNC
414
- </span>
415
- </button>
416
-
417
- {/* My Computer Shortcut */}
418
- <button
419
- onClick={() => toggleWindowMinimize('computer')}
420
- className="flex flex-col items-center justify-center text-ink-black gap-2.5 p-2 w-full group icon-hover-shift cursor-pointer outline-none"
421
- >
422
- <div className="w-16 h-16 bg-paper-white border-[3px] border-ink-black flex items-center justify-center gadget-shadow group-hover:bg-secondary-container transition-colors shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)] p-1 overflow-hidden">
423
- <img
424
- alt="My Computer"
425
- className="w-full h-full object-cover"
426
- src="https://lh3.googleusercontent.com/aida-public/AB6AXuD2tUGA2d7QiNyajDAWYK183zhNTgtAZpOXK3E9wRvHGs-t6ykWt9uPScYe_fziWzQI0pREcY_ThI341WvGMusyYmnAkagfuwx6wubIs1ES68DO8CCNAlcHcb2zOUU4MJeYuhWDy1uYRqyGYjIaDUqfgNWk2vm4WzwRqoorn2dxtZ6QdJhEKbXjG8fG9chkkvr68qJf0fLUL6bIqBXZg2FJ30S7zS3oZ4IZsug-wLyRYuJ4Gu_86snNUo1whNrBdZm5OMREfc9sLbwJ"
427
- />
428
- </div>
429
- <span className="font-icon-label text-[9px] bg-ink-black text-white px-2 py-1 border-[3px] border-ink-black text-center leading-tight shadow-[2px_2px_0px_0px_#fde047] uppercase">
430
- MY<br/>COMP
431
- </span>
432
- </button>
433
-
434
- {/* Terminal Shortcut */}
435
- <button
436
- onClick={() => toggleWindowMinimize('terminal')}
437
- className="flex flex-col items-center justify-center text-ink-black gap-2.5 p-2 w-full group icon-hover-shift cursor-pointer outline-none"
438
- >
439
- <div className="w-16 h-16 bg-paper-white border-[3px] border-ink-black flex items-center justify-center gadget-shadow group-hover:bg-secondary-container transition-colors shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)] p-1 overflow-hidden">
440
- <img
441
- alt="Terminal"
442
- className="w-full h-full object-cover"
443
- src="https://lh3.googleusercontent.com/aida-public/AB6AXuA2AvcQ2oKWP8AJ8yR5nF82LLDEH1FKySUK-npnqEjvJ6Cs9xp8joCwH7x43oTCAC5xhO2rQdYzka3B6u72FNbdxMnsv3WJLye3bKochu8AnnRlS3szfYSaj724sYsiZo4n8G-oWqvl7C0rOGaDaU2nRH1xXmW2PBi6L2NryTsUaTCVZQKTKBBNNEOig5kh7B52e-iIuj2PTzaSjF9ebp6gMuCnBtJT8Sxo5Qsmvfm-t2U5r_qQpRiYj--Ut41T7NTh-tHgs4S4kBvz"
444
- />
445
- </div>
446
- <span className="font-icon-label text-[9px] bg-ink-black text-white px-2 py-1 border-[3px] border-ink-black text-center leading-tight shadow-[2px_2px_0px_0px_#fde047] uppercase">
447
- TERMINAL
448
- </span>
449
- </button>
450
- </nav>
451
 
452
  {/* System Gadget Widget (Top Right) */}
453
- <div className="absolute top-desktop-margin right-desktop-margin w-64 bg-paper-white border-[3px] border-ink-black gadget-shadow z-20 overflow-hidden flex flex-col shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)] select-none">
454
- <div className="bg-[#0ea5e9] border-b-[3px] border-ink-black px-3 py-1 flex justify-between items-center text-white">
455
- <span className="font-window-title text-xs font-bold tracking-wide">Profile.sys</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
456
  </div>
457
- <div className="p-3 flex items-center gap-3 bg-[#fdf8e1]">
458
- <div className="w-12 h-12 border-[3px] border-ink-black overflow-hidden bg-primary-fixed-dim shadow-[2px_2px_0_0_#1E293B] shrink-0">
459
- <img
460
- className="w-full h-full object-cover"
461
- src="https://lh3.googleusercontent.com/aida-public/AB6AXuBl1MnAmh_W_EWibibrGw1F1YSenuKlaIn3JymUnBKn1nPLjAaOBjoLzdT5krzVDmihFhXOk-DEtNTdM2Js1_Ttr--5WZohhyqD1QfpS6j_yU1_-4wweOmgWq2HLUYNMf0mzQDNLNu5KbACEJKL5sm1YaTLPePlO687X3VHYsUhWTpUQeBwFjushaBpyW8tEa2dJj5ZSRWq0qa5GhtE0zAAW741e2SIRtFOp7CvBYEEetymSiucK513lli1TUwgWIgXvlfxZoGbH00q"
462
- />
 
 
 
463
  </div>
464
- <div className="overflow-hidden">
465
- <div className="font-headline-md text-sm font-bold text-ink-black truncate">{username}</div>
466
- <div className="flex items-center gap-1 text-red-500 mt-1 select-none font-bold">
467
- <span className="material-symbols-outlined text-sm" style={{ fontVariationSettings: "'FILL' 1" }}>
468
- local_fire_department
469
- </span>
470
- <span className="font-arcade text-[7px]">{streak?.current_streak ?? 0} DAY STREAK</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
471
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
472
  </div>
473
  </div>
474
- </div>
475
 
476
  {/* Floating Windows Shell Containers */}
477
 
@@ -488,6 +636,7 @@ export default function App() {
488
  setActiveWindow={setActiveWindow}
489
  defaultWidth="750px"
490
  defaultHeight="600px"
 
491
  >
492
  <ReviewQueue
493
  overrideProblemId={overrideProblemId}
@@ -508,6 +657,7 @@ export default function App() {
508
  setActiveWindow={setActiveWindow}
509
  defaultWidth="700px"
510
  defaultHeight="560px"
 
511
  >
512
  <JourneyPath
513
  onSelectProblemForReview={handleSelectProblemForReview}
@@ -528,6 +678,7 @@ export default function App() {
528
  defaultWidth="640px"
529
  defaultHeight="450px"
530
  titleBarColor="#1e293b"
 
531
  >
532
  <TerminalEmulator
533
  onOpenWindow={openWindow}
@@ -549,6 +700,7 @@ export default function App() {
549
  defaultWidth="480px"
550
  defaultHeight="320px"
551
  titleBarColor="#855400"
 
552
  >
553
  <div className="w-full h-full bg-[#fdf8e1] p-6 flex flex-col justify-between">
554
  <div className="space-y-4">
@@ -609,6 +761,7 @@ export default function App() {
609
  defaultWidth="640px"
610
  defaultHeight="480px"
611
  titleBarColor="#006686"
 
612
  >
613
  <FileExplorer onSetWallpaper={setWallpaperUrl} activeWallpaperUrl={wallpaperUrl} />
614
  </WindowShell>
@@ -627,6 +780,7 @@ export default function App() {
627
  defaultWidth="620px"
628
  defaultHeight="580px"
629
  titleBarColor="#9d4edd"
 
630
  >
631
  <PythonChallenge />
632
  </WindowShell>
@@ -645,6 +799,7 @@ export default function App() {
645
  defaultWidth="660px"
646
  defaultHeight="580px"
647
  titleBarColor="#0ea5e9"
 
648
  >
649
  <MySQLPlayground />
650
  </WindowShell>
@@ -730,12 +885,12 @@ export default function App() {
730
  e.stopPropagation();
731
  setIsStartOpen(!isStartOpen);
732
  }}
733
- className="h-full px-6 flex items-center gap-2 border-r-[4px] border-ink-black bg-[#39ff14] text-ink-black hover:bg-[#28e007] active:bg-[#1fb304] transition-colors shadow-[inset_-3px_-3px_0px_rgba(0,0,0,0.2),inset_3px_3px_0px_rgba(255,255,255,0.5)] font-bold cursor-pointer"
734
  >
735
  <span className="material-symbols-outlined text-2xl font-bold" style={{ fontVariationSettings: "'FILL' 1" }}>
736
  sports_esports
737
  </span>
738
- <span className="font-display-lg text-lg italic tracking-wide">Start</span>
739
  </button>
740
 
741
  {/* Windows tabs in taskbar */}
@@ -744,14 +899,14 @@ export default function App() {
744
  {windows.queue.isOpen && (
745
  <button
746
  onClick={() => toggleWindowMinimize('queue')}
747
- className={`h-full px-4 flex items-center gap-2 border-r-[4px] border-ink-black text-xs font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
748
  activeWindow === 'queue' && !windows.queue.isMinimized
749
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
750
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
751
  }`}
752
  >
753
  <span className="material-symbols-outlined text-sm font-bold">view_list</span>
754
- <span>Daily Queue</span>
755
  </button>
756
  )}
757
 
@@ -759,14 +914,14 @@ export default function App() {
759
  {windows.journey.isOpen && (
760
  <button
761
  onClick={() => toggleWindowMinimize('journey')}
762
- className={`h-full px-4 flex items-center gap-2 border-r-[4px] border-ink-black text-xs font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
763
  activeWindow === 'journey' && !windows.journey.isMinimized
764
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
765
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
766
  }`}
767
  >
768
  <span className="material-symbols-outlined text-sm font-bold">route</span>
769
- <span>Journey Path</span>
770
  </button>
771
  )}
772
 
@@ -774,14 +929,14 @@ export default function App() {
774
  {windows.terminal.isOpen && (
775
  <button
776
  onClick={() => toggleWindowMinimize('terminal')}
777
- className={`h-full px-4 flex items-center gap-2 border-r-[4px] border-ink-black text-xs font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
778
  activeWindow === 'terminal' && !windows.terminal.isMinimized
779
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
780
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
781
  }`}
782
  >
783
  <span className="material-symbols-outlined text-sm font-bold">terminal</span>
784
- <span>Terminal</span>
785
  </button>
786
  )}
787
 
@@ -789,14 +944,14 @@ export default function App() {
789
  {windows.sync.isOpen && (
790
  <button
791
  onClick={() => toggleWindowMinimize('sync')}
792
- className={`h-full px-4 flex items-center gap-2 border-r-[4px] border-ink-black text-xs font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
793
  activeWindow === 'sync' && !windows.sync.isMinimized
794
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
795
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
796
  }`}
797
  >
798
  <span className="material-symbols-outlined text-sm font-bold">cloud_sync</span>
799
- <span>Drive Sync</span>
800
  </button>
801
  )}
802
 
@@ -804,14 +959,14 @@ export default function App() {
804
  {windows.computer.isOpen && (
805
  <button
806
  onClick={() => toggleWindowMinimize('computer')}
807
- className={`h-full px-4 flex items-center gap-2 border-r-[4px] border-ink-black text-xs font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
808
  activeWindow === 'computer' && !windows.computer.isMinimized
809
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
810
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
811
  }`}
812
  >
813
  <span className="material-symbols-outlined text-sm font-bold">desktop_windows</span>
814
- <span>My Computer</span>
815
  </button>
816
  )}
817
 
@@ -819,14 +974,14 @@ export default function App() {
819
  {windows.python.isOpen && (
820
  <button
821
  onClick={() => toggleWindowMinimize('python')}
822
- className={`h-full px-4 flex items-center gap-2 border-r-[4px] border-ink-black text-xs font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
823
  activeWindow === 'python' && !windows.python.isMinimized
824
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
825
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
826
  }`}
827
  >
828
  <span className="material-symbols-outlined text-sm font-bold">sports_esports</span>
829
- <span>Python Challenge</span>
830
  </button>
831
  )}
832
 
@@ -834,14 +989,14 @@ export default function App() {
834
  {windows.mysql.isOpen && (
835
  <button
836
  onClick={() => toggleWindowMinimize('mysql')}
837
- className={`h-full px-4 flex items-center gap-2 border-r-[4px] border-ink-black text-xs font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
838
  activeWindow === 'mysql' && !windows.mysql.isMinimized
839
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
840
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
841
  }`}
842
  >
843
  <span className="material-symbols-outlined text-sm font-bold">database</span>
844
- <span>MySQL Playground</span>
845
  </button>
846
  )}
847
  </div>
 
31
  mysql: { isOpen: false, isMinimized: false },
32
  });
33
  const [activeWindow, setActiveWindow] = useState<string>('queue');
34
+ const [isMobile, setIsMobile] = useState(false);
35
 
36
  // Start Menu and System info
37
  const [isStartOpen, setIsStartOpen] = useState(false);
 
106
  };
107
  }, []);
108
 
109
+ useEffect(() => {
110
+ const checkMobile = () => {
111
+ setIsMobile(window.innerWidth < 768);
112
+ };
113
+ checkMobile();
114
+ window.addEventListener('resize', checkMobile);
115
+ return () => {
116
+ window.removeEventListener('resize', checkMobile);
117
+ };
118
+ }, []);
119
+
120
  useEffect(() => {
121
  if (user) {
122
  fetchStreak();
 
364
  }
365
 
366
  const username = user.email ? user.email.split('@')[0] : 'Player_One';
367
+ const isAnyWindowOpen = Object.values(windows).some(w => w.isOpen && !w.isMinimized);
368
 
369
  return (
370
  <div
 
380
  />
381
 
382
  {/* Desktop Icons column */}
383
+ {!isMobile && (
384
+ <nav className="fixed left-0 top-12 h-[calc(100vh-80px)] w-[140px] flex flex-col items-center py-gutter-md space-y-6 z-10 overflow-y-auto custom-scrollbar select-none">
385
+
386
+ {/* Daily Queue Shortcut */}
387
+ <button
388
+ onClick={() => toggleWindowMinimize('queue')}
389
+ className="flex flex-col items-center justify-center text-ink-black gap-2.5 p-2 w-full group icon-hover-shift cursor-pointer outline-none"
390
+ >
391
+ <div className="w-16 h-16 bg-paper-white border-[3px] border-ink-black flex items-center justify-center gadget-shadow group-hover:bg-secondary-container transition-colors shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)]">
392
+ <span className="material-symbols-outlined text-4xl" style={{ fontVariationSettings: "'FILL' 1" }}>
393
+ view_list
394
+ </span>
395
+ </div>
396
+ <span className="font-icon-label text-[9px] bg-ink-black text-white px-2 py-1 border-[3px] border-ink-black text-center leading-tight shadow-[2px_2px_0px_0px_#fde047] uppercase">
397
+ DAILY<br/>QUEUE
398
  </span>
399
+ </button>
400
+
401
+ {/* Journey Path Shortcut */}
402
+ <button
403
+ onClick={() => toggleWindowMinimize('journey')}
404
+ className="flex flex-col items-center justify-center text-ink-black gap-2.5 p-2 w-full group icon-hover-shift cursor-pointer outline-none"
405
+ >
406
+ <div className="w-16 h-16 bg-paper-white border-[3px] border-ink-black flex items-center justify-center gadget-shadow group-hover:bg-secondary-container transition-colors shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)]">
407
+ <span className="material-symbols-outlined text-4xl" style={{ fontVariationSettings: "'FILL' 1" }}>
408
+ route
409
+ </span>
410
+ </div>
411
+ <span className="font-icon-label text-[9px] bg-ink-black text-white px-2 py-1 border-[3px] border-ink-black text-center leading-tight shadow-[2px_2px_0px_0px_#fde047] uppercase">
412
+ JOURNEY<br/>PATH
413
  </span>
414
+ </button>
415
+
416
+ {/* Drive Sync Shortcut */}
417
+ <button
418
+ onClick={triggerSync}
419
+ className="flex flex-col items-center justify-center text-ink-black gap-2.5 p-2 w-full group icon-hover-shift cursor-pointer outline-none"
420
+ >
421
+ <div className="w-16 h-16 bg-paper-white border-[3px] border-ink-black flex items-center justify-center gadget-shadow group-hover:bg-secondary-container transition-colors shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)]">
422
+ <span className="material-symbols-outlined text-4xl" style={{ fontVariationSettings: "'FILL' 1" }}>
423
+ cloud_sync
424
+ </span>
425
+ </div>
426
+ <span className="font-icon-label text-[9px] bg-ink-black text-white px-2 py-1 border-[3px] border-ink-black text-center leading-tight shadow-[2px_2px_0px_0px_#fde047] uppercase">
427
+ DRIVE<br/>SYNC
428
  </span>
429
+ </button>
430
+
431
+ {/* My Computer Shortcut */}
432
+ <button
433
+ onClick={() => toggleWindowMinimize('computer')}
434
+ className="flex flex-col items-center justify-center text-ink-black gap-2.5 p-2 w-full group icon-hover-shift cursor-pointer outline-none"
435
+ >
436
+ <div className="w-16 h-16 bg-paper-white border-[3px] border-ink-black flex items-center justify-center gadget-shadow group-hover:bg-secondary-container transition-colors shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)] p-1 overflow-hidden">
437
+ <img
438
+ alt="My Computer"
439
+ className="w-full h-full object-cover"
440
+ src="https://lh3.googleusercontent.com/aida-public/AB6AXuD2tUGA2d7QiNyajDAWYK183zhNTgtAZpOXK3E9wRvHGs-t6ykWt9uPScYe_fziWzQI0pREcY_ThI341WvGMusyYmnAkagfuwx6wubIs1ES68DO8CCNAlcHcb2zOUU4MJeYuhWDy1uYRqyGYjIaDUqfgNWk2vm4WzwRqoorn2dxtZ6QdJhEKbXjG8fG9chkkvr68qJf0fLUL6bIqBXZg2FJ30S7zS3oZ4IZsug-wLyRYuJ4Gu_86snNUo1whNrBdZm5OMREfc9sLbwJ"
441
+ />
442
+ </div>
443
+ <span className="font-icon-label text-[9px] bg-ink-black text-white px-2 py-1 border-[3px] border-ink-black text-center leading-tight shadow-[2px_2px_0px_0px_#fde047] uppercase">
444
+ MY<br/>COMP
445
+ </span>
446
+ </button>
447
+
448
+ {/* Terminal Shortcut */}
449
+ <button
450
+ onClick={() => toggleWindowMinimize('terminal')}
451
+ className="flex flex-col items-center justify-center text-ink-black gap-2.5 p-2 w-full group icon-hover-shift cursor-pointer outline-none"
452
+ >
453
+ <div className="w-16 h-16 bg-paper-white border-[3px] border-ink-black flex items-center justify-center gadget-shadow group-hover:bg-secondary-container transition-colors shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)] p-1 overflow-hidden">
454
+ <img
455
+ alt="Terminal"
456
+ className="w-full h-full object-cover"
457
+ src="https://lh3.googleusercontent.com/aida-public/AB6AXuA2AvcQ2oKWP8AJ8yR5nF82LLDEH1FKySUK-npnqEjvJ6Cs9xp8joCwH7x43oTCAC5xhO2rQdYzka3B6u72FNbdxMnsv3WJLye3bKochu8AnnRlS3szfYSaj724sYsiZo4n8G-oWqvl7C0rOGaDaU2nRH1xXmW2PBi6L2NryTsUaTCVZQKTKBBNNEOig5kh7B52e-iIuj2PTzaSjF9ebp6gMuCnBtJT8Sxo5Qsmvfm-t2U5r_qQpRiYj--Ut41T7NTh-tHgs4S4kBvz"
458
+ />
459
+ </div>
460
+ <span className="font-icon-label text-[9px] bg-ink-black text-white px-2 py-1 border-[3px] border-ink-black text-center leading-tight shadow-[2px_2px_0px_0px_#fde047] uppercase">
461
+ TERMINAL
462
+ </span>
463
+ </button>
464
+ </nav>
465
+ )}
 
 
 
466
 
467
  {/* System Gadget Widget (Top Right) */}
468
+ {!isMobile && (
469
+ <div className="absolute top-desktop-margin right-desktop-margin w-64 bg-paper-white border-[3px] border-ink-black gadget-shadow z-20 overflow-hidden flex flex-col shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)] select-none">
470
+ <div className="bg-[#0ea5e9] border-b-[3px] border-ink-black px-3 py-1 flex justify-between items-center text-white">
471
+ <span className="font-window-title text-xs font-bold tracking-wide">Profile.sys</span>
472
+ </div>
473
+ <div className="p-3 flex items-center gap-3 bg-[#fdf8e1]">
474
+ <div className="w-12 h-12 border-[3px] border-ink-black overflow-hidden bg-primary-fixed-dim shadow-[2px_2px_0_0_#1E293B] shrink-0">
475
+ <img
476
+ className="w-full h-full object-cover"
477
+ src="https://lh3.googleusercontent.com/aida-public/AB6AXuBl1MnAmh_W_EWibibrGw1F1YSenuKlaIn3JymUnBKn1nPLjAaOBjoLzdT5krzVDmihFhXOk-DEtNTdM2Js1_Ttr--5WZohhyqD1QfpS6j_yU1_-4wweOmgWq2HLUYNMf0mzQDNLNu5KbACEJKL5sm1YaTLPePlO687X3VHYsUhWTpUQeBwFjushaBpyW8tEa2dJj5ZSRWq0qa5GhtE0zAAW741e2SIRtFOp7CvBYEEetymSiucK513lli1TUwgWIgXvlfxZoGbH00q"
478
+ />
479
+ </div>
480
+ <div className="overflow-hidden">
481
+ <div className="font-headline-md text-sm font-bold text-ink-black truncate">{username}</div>
482
+ <div className="flex items-center gap-1 text-red-500 mt-1 select-none font-bold">
483
+ <span className="material-symbols-outlined text-sm" style={{ fontVariationSettings: "'FILL' 1" }}>
484
+ local_fire_department
485
+ </span>
486
+ <span className="font-arcade text-[7px]">{streak?.current_streak ?? 0} DAY STREAK</span>
487
+ </div>
488
+ </div>
489
+ </div>
490
  </div>
491
+ )}
492
+
493
+ {/* Windows Phone Metro Start Screen (Mobile Home View) */}
494
+ {isMobile && !isAnyWindowOpen && (
495
+ <div className="w-full h-[calc(100vh-56px)] overflow-y-auto custom-scrollbar p-6 pb-24 flex flex-col gap-6 z-10 relative">
496
+ {/* Metro Header */}
497
+ <div className="flex flex-col select-none border-b-[3px] border-dashed border-ink-black pb-4">
498
+ <span className="text-[9px] font-arcade text-trash-gray font-bold uppercase tracking-wider">AlgoSpaced OS v1.0</span>
499
+ <h1 className="text-4xl font-extrabold font-headline-md text-ink-black uppercase tracking-tight mt-1">start</h1>
500
  </div>
501
+
502
+ {/* Tiles Grid */}
503
+ <div className="grid grid-cols-2 gap-4">
504
+ {/* Profile Tile (Wide - 2 cols) */}
505
+ <div className="col-span-2 bg-[#fdf8e1] border-[3px] border-ink-black p-4 flex items-center gap-4 gadget-shadow shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)]">
506
+ <div className="w-12 h-12 border-[3px] border-ink-black overflow-hidden bg-primary-fixed-dim shadow-[2px_2px_0_0_#1E293B] shrink-0">
507
+ <img
508
+ className="w-full h-full object-cover"
509
+ src="https://lh3.googleusercontent.com/aida-public/AB6AXuBl1MnAmh_W_EWibibrGw1F1YSenuKlaIn3JymUnBKn1nPLjAaOBjoLzdT5krzVDmihFhXOk-DEtNTdM2Js1_Ttr--5WZohhyqD1QfpS6j_yU1_-4wweOmgWq2HLUYNMf0mzQDNLNu5KbACEJKL5sm1YaTLPePlO687X3VHYsUhWTpUQeBwFjushaBpyW8tEa2dJj5ZSRWq0qa5GhtE0zAAW741e2SIRtFOp7CvBYEEetymSiucK513lli1TUwgWIgXvlfxZoGbH00q"
510
+ />
511
+ </div>
512
+ <div className="overflow-hidden">
513
+ <div className="font-headline-md text-sm font-bold text-ink-black truncate">{username}</div>
514
+ <div className="flex items-center gap-1 text-red-500 mt-1 select-none font-bold">
515
+ <span className="material-symbols-outlined text-sm" style={{ fontVariationSettings: "'FILL' 1" }}>
516
+ local_fire_department
517
+ </span>
518
+ <span className="font-arcade text-[7px]">{streak?.current_streak ?? 0} DAY STREAK</span>
519
+ </div>
520
+ </div>
521
  </div>
522
+
523
+ {/* Daily Queue Tile */}
524
+ <button
525
+ onClick={() => toggleWindowMinimize('queue')}
526
+ className="bg-grass-green text-ink-black border-[3px] border-ink-black p-4 flex flex-col justify-between aspect-square gadget-shadow active:translate-y-1 active:translate-x-1 active:shadow-none select-none text-left cursor-pointer transition-all"
527
+ >
528
+ <span className="material-symbols-outlined text-3xl align-top" style={{ fontVariationSettings: "'FILL' 1" }}>
529
+ view_list
530
+ </span>
531
+ <span className="font-arcade text-[8px] font-bold tracking-tight uppercase leading-tight">
532
+ DAILY<br/>QUEUE
533
+ </span>
534
+ </button>
535
+
536
+ {/* Journey Path Tile */}
537
+ <button
538
+ onClick={() => toggleWindowMinimize('journey')}
539
+ className="bg-[#0ea5e9] text-white border-[3px] border-ink-black p-4 flex flex-col justify-between aspect-square gadget-shadow active:translate-y-1 active:translate-x-1 active:shadow-none select-none text-left cursor-pointer transition-all"
540
+ >
541
+ <span className="material-symbols-outlined text-3xl align-top" style={{ fontVariationSettings: "'FILL' 1" }}>
542
+ route
543
+ </span>
544
+ <span className="font-arcade text-[8px] font-bold tracking-tight uppercase leading-tight">
545
+ JOURNEY<br/>PATH
546
+ </span>
547
+ </button>
548
+
549
+ {/* My Computer Tile */}
550
+ <button
551
+ onClick={() => toggleWindowMinimize('computer')}
552
+ className="bg-paper-white text-ink-black border-[3px] border-ink-black p-4 flex flex-col justify-between aspect-square gadget-shadow active:translate-y-1 active:translate-x-1 active:shadow-none select-none text-left cursor-pointer transition-all"
553
+ >
554
+ <img
555
+ alt="My Computer"
556
+ className="w-10 h-10 object-cover border-2 border-ink-black bg-white"
557
+ src="https://lh3.googleusercontent.com/aida-public/AB6AXuD2tUGA2d7QiNyajDAWYK183zhNTgtAZpOXK3E9wRvHGs-t6ykWt9uPScYe_fziWzQI0pREcY_ThI341WvGMusyYmnAkagfuwx6wubIs1ES68DO8CCNAlcHcb2zOUU4MJeYuhWDy1uYRqyGYjIaDUqfgNWk2vm4WzwRqoorn2dxtZ6QdJhEKbXjG8fG9chkkvr68qJf0fLUL6bIqBXZg2FJ30S7zS3oZ4IZsug-wLyRYuJ4Gu_86snNUo1whNrBdZm5OMREfc9sLbwJ"
558
+ />
559
+ <span className="font-arcade text-[8px] font-bold tracking-tight uppercase leading-tight">
560
+ MY COMP
561
+ </span>
562
+ </button>
563
+
564
+ {/* Terminal Tile */}
565
+ <button
566
+ onClick={() => toggleWindowMinimize('terminal')}
567
+ className="bg-[#1e293b] text-[#39ff14] border-[3px] border-ink-black p-4 flex flex-col justify-between aspect-square gadget-shadow active:translate-y-1 active:translate-x-1 active:shadow-none select-none text-left cursor-pointer transition-all"
568
+ >
569
+ <img
570
+ alt="Terminal"
571
+ className="w-10 h-10 object-cover border-2 border-ink-black bg-white"
572
+ src="https://lh3.googleusercontent.com/aida-public/AB6AXuA2AvcQ2oKWP8AJ8yR5nF82LLDEH1FKySUK-npnqEjvJ6Cs9xp8joCwH7x43oTCAC5xhO2rQdYzka3B6u72FNbdxMnsv3WJLye3bKochu8AnnRlS3szfYSaj724sYsiZo4n8G-oWqvl7C0rOGaDaU2nRH1xXmW2PBi6L2NryTsUaTCVZQKTKBBNNEOig5kh7B52e-iIuj2PTzaSjF9ebp6gMuCnBtJT8Sxo5Qsmvfm-t2U5r_qQpRiYj--Ut41T7NTh-tHgs4S4kBvz"
573
+ />
574
+ <span className="font-arcade text-[8px] text-[#39ff14] font-bold tracking-tight uppercase leading-tight">
575
+ TERMINAL
576
+ </span>
577
+ </button>
578
+
579
+ {/* Python Challenge Tile */}
580
+ <button
581
+ onClick={() => toggleWindowMinimize('python')}
582
+ className="bg-[#9d4edd] text-white border-[3px] border-ink-black p-4 flex flex-col justify-between aspect-square gadget-shadow active:translate-y-1 active:translate-x-1 active:shadow-none select-none text-left cursor-pointer transition-all"
583
+ >
584
+ <span className="material-symbols-outlined text-3xl align-top" style={{ fontVariationSettings: "'FILL' 1" }}>
585
+ sports_esports
586
+ </span>
587
+ <span className="font-arcade text-[8px] font-bold tracking-tight uppercase leading-tight">
588
+ PYTHON<br/>PLAY
589
+ </span>
590
+ </button>
591
+
592
+ {/* MySQL Playground Tile */}
593
+ <button
594
+ onClick={() => toggleWindowMinimize('mysql')}
595
+ className="bg-[#ffcc00] text-ink-black border-[3px] border-ink-black p-4 flex flex-col justify-between aspect-square gadget-shadow active:translate-y-1 active:translate-x-1 active:shadow-none select-none text-left cursor-pointer transition-all"
596
+ >
597
+ <span className="material-symbols-outlined text-3xl align-top" style={{ fontVariationSettings: "'FILL' 1" }}>
598
+ database
599
+ </span>
600
+ <span className="font-arcade text-[8px] font-bold tracking-tight uppercase leading-tight">
601
+ MYSQL<br/>PLAY
602
+ </span>
603
+ </button>
604
+
605
+ {/* Drive Sync Tile (Wide - 2 cols) */}
606
+ <button
607
+ onClick={triggerSync}
608
+ className="col-span-2 bg-[#ffe24c] hover:bg-yellow-300 text-ink-black border-[3px] border-ink-black p-4 flex items-center justify-between gadget-shadow active:translate-y-1 active:translate-x-1 active:shadow-none select-none text-left cursor-pointer transition-all"
609
+ >
610
+ <div className="flex items-center gap-3">
611
+ <span className="material-symbols-outlined text-3xl" style={{ fontVariationSettings: "'FILL' 1" }}>
612
+ cloud_sync
613
+ </span>
614
+ <span className="font-arcade text-[8px] font-bold tracking-tight uppercase">
615
+ DRIVE NOTES SYNC
616
+ </span>
617
+ </div>
618
+ <span className="material-symbols-outlined text-lg">chevron_right</span>
619
+ </button>
620
  </div>
621
  </div>
622
+ )}
623
 
624
  {/* Floating Windows Shell Containers */}
625
 
 
636
  setActiveWindow={setActiveWindow}
637
  defaultWidth="750px"
638
  defaultHeight="600px"
639
+ isMobile={isMobile}
640
  >
641
  <ReviewQueue
642
  overrideProblemId={overrideProblemId}
 
657
  setActiveWindow={setActiveWindow}
658
  defaultWidth="700px"
659
  defaultHeight="560px"
660
+ isMobile={isMobile}
661
  >
662
  <JourneyPath
663
  onSelectProblemForReview={handleSelectProblemForReview}
 
678
  defaultWidth="640px"
679
  defaultHeight="450px"
680
  titleBarColor="#1e293b"
681
+ isMobile={isMobile}
682
  >
683
  <TerminalEmulator
684
  onOpenWindow={openWindow}
 
700
  defaultWidth="480px"
701
  defaultHeight="320px"
702
  titleBarColor="#855400"
703
+ isMobile={isMobile}
704
  >
705
  <div className="w-full h-full bg-[#fdf8e1] p-6 flex flex-col justify-between">
706
  <div className="space-y-4">
 
761
  defaultWidth="640px"
762
  defaultHeight="480px"
763
  titleBarColor="#006686"
764
+ isMobile={isMobile}
765
  >
766
  <FileExplorer onSetWallpaper={setWallpaperUrl} activeWallpaperUrl={wallpaperUrl} />
767
  </WindowShell>
 
780
  defaultWidth="620px"
781
  defaultHeight="580px"
782
  titleBarColor="#9d4edd"
783
+ isMobile={isMobile}
784
  >
785
  <PythonChallenge />
786
  </WindowShell>
 
799
  defaultWidth="660px"
800
  defaultHeight="580px"
801
  titleBarColor="#0ea5e9"
802
+ isMobile={isMobile}
803
  >
804
  <MySQLPlayground />
805
  </WindowShell>
 
885
  e.stopPropagation();
886
  setIsStartOpen(!isStartOpen);
887
  }}
888
+ className={`h-full ${isMobile ? 'px-3' : 'px-6'} flex items-center gap-2 border-r-[4px] border-ink-black bg-[#39ff14] text-ink-black hover:bg-[#28e007] active:bg-[#1fb304] transition-colors shadow-[inset_-3px_-3px_0px_rgba(0,0,0,0.2),inset_3px_3px_0px_rgba(255,255,255,0.5)] font-bold cursor-pointer`}
889
  >
890
  <span className="material-symbols-outlined text-2xl font-bold" style={{ fontVariationSettings: "'FILL' 1" }}>
891
  sports_esports
892
  </span>
893
+ <span className={`font-display-lg ${isMobile ? 'text-sm' : 'text-lg'} italic tracking-wide`}>Start</span>
894
  </button>
895
 
896
  {/* Windows tabs in taskbar */}
 
899
  {windows.queue.isOpen && (
900
  <button
901
  onClick={() => toggleWindowMinimize('queue')}
902
+ className={`h-full ${isMobile ? 'px-2 text-[10px] gap-1' : 'px-4 text-xs gap-2'} border-r-[4px] border-ink-black font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
903
  activeWindow === 'queue' && !windows.queue.isMinimized
904
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
905
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
906
  }`}
907
  >
908
  <span className="material-symbols-outlined text-sm font-bold">view_list</span>
909
+ <span>{isMobile ? 'Queue' : 'Daily Queue'}</span>
910
  </button>
911
  )}
912
 
 
914
  {windows.journey.isOpen && (
915
  <button
916
  onClick={() => toggleWindowMinimize('journey')}
917
+ className={`h-full ${isMobile ? 'px-2 text-[10px] gap-1' : 'px-4 text-xs gap-2'} border-r-[4px] border-ink-black font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
918
  activeWindow === 'journey' && !windows.journey.isMinimized
919
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
920
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
921
  }`}
922
  >
923
  <span className="material-symbols-outlined text-sm font-bold">route</span>
924
+ <span>{isMobile ? 'Journey' : 'Journey Path'}</span>
925
  </button>
926
  )}
927
 
 
929
  {windows.terminal.isOpen && (
930
  <button
931
  onClick={() => toggleWindowMinimize('terminal')}
932
+ className={`h-full ${isMobile ? 'px-2 text-[10px] gap-1' : 'px-4 text-xs gap-2'} border-r-[4px] border-ink-black font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
933
  activeWindow === 'terminal' && !windows.terminal.isMinimized
934
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
935
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
936
  }`}
937
  >
938
  <span className="material-symbols-outlined text-sm font-bold">terminal</span>
939
+ <span>{isMobile ? 'Terminal' : 'Terminal'}</span>
940
  </button>
941
  )}
942
 
 
944
  {windows.sync.isOpen && (
945
  <button
946
  onClick={() => toggleWindowMinimize('sync')}
947
+ className={`h-full ${isMobile ? 'px-2 text-[10px] gap-1' : 'px-4 text-xs gap-2'} border-r-[4px] border-ink-black font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
948
  activeWindow === 'sync' && !windows.sync.isMinimized
949
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
950
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
951
  }`}
952
  >
953
  <span className="material-symbols-outlined text-sm font-bold">cloud_sync</span>
954
+ <span>{isMobile ? 'Sync' : 'Drive Sync'}</span>
955
  </button>
956
  )}
957
 
 
959
  {windows.computer.isOpen && (
960
  <button
961
  onClick={() => toggleWindowMinimize('computer')}
962
+ className={`h-full ${isMobile ? 'px-2 text-[10px] gap-1' : 'px-4 text-xs gap-2'} border-r-[4px] border-ink-black font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
963
  activeWindow === 'computer' && !windows.computer.isMinimized
964
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
965
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
966
  }`}
967
  >
968
  <span className="material-symbols-outlined text-sm font-bold">desktop_windows</span>
969
+ <span>{isMobile ? 'Comp' : 'My Computer'}</span>
970
  </button>
971
  )}
972
 
 
974
  {windows.python.isOpen && (
975
  <button
976
  onClick={() => toggleWindowMinimize('python')}
977
+ className={`h-full ${isMobile ? 'px-2 text-[10px] gap-1' : 'px-4 text-xs gap-2'} border-r-[4px] border-ink-black font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
978
  activeWindow === 'python' && !windows.python.isMinimized
979
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
980
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
981
  }`}
982
  >
983
  <span className="material-symbols-outlined text-sm font-bold">sports_esports</span>
984
+ <span>{isMobile ? 'Python' : 'Python Challenge'}</span>
985
  </button>
986
  )}
987
 
 
989
  {windows.mysql.isOpen && (
990
  <button
991
  onClick={() => toggleWindowMinimize('mysql')}
992
+ className={`h-full ${isMobile ? 'px-2 text-[10px] gap-1' : 'px-4 text-xs gap-2'} border-r-[4px] border-ink-black font-bold font-window-title cursor-pointer transition-all shadow-[inset_0px_3px_0px_rgba(255,255,255,0.8)] ${
993
  activeWindow === 'mysql' && !windows.mysql.isMinimized
994
  ? 'bg-paper-white text-ink-black font-extrabold translate-y-[2px]'
995
  : 'bg-surface-variant text-trash-gray hover:bg-white/40'
996
  }`}
997
  >
998
  <span className="material-symbols-outlined text-sm font-bold">database</span>
999
+ <span>{isMobile ? 'SQL' : 'MySQL Playground'}</span>
1000
  </button>
1001
  )}
1002
  </div>
algospaced-ui/src/components/WindowShell.tsx CHANGED
@@ -16,6 +16,7 @@ interface WindowShellProps {
16
  defaultX?: number;
17
  defaultY?: number;
18
  titleBarColor?: string;
 
19
  }
20
 
21
  export default function WindowShell({
@@ -34,6 +35,7 @@ export default function WindowShell({
34
  defaultX,
35
  defaultY,
36
  titleBarColor = '#0ea5e9',
 
37
  }: WindowShellProps) {
38
  // Helper to parse default dimensions (e.g. '700px') into integer values
39
  const parseDimension = (val: string): number => {
@@ -66,6 +68,7 @@ export default function WindowShell({
66
  }, [defaultX, defaultY]);
67
 
68
  const handleMouseDown = (e: React.MouseEvent) => {
 
69
  // Only drag on left click and not on control buttons or resize handles
70
  if (e.button !== 0) return;
71
  const target = e.target as HTMLElement;
@@ -81,6 +84,7 @@ export default function WindowShell({
81
  };
82
 
83
  const handleResizeMouseDown = (e: React.MouseEvent) => {
 
84
  if (e.button !== 0) return;
85
  e.stopPropagation();
86
  e.preventDefault();
@@ -129,7 +133,7 @@ export default function WindowShell({
129
  document.removeEventListener('mousemove', handleMouseMove);
130
  document.removeEventListener('mouseup', handleMouseUp);
131
  };
132
- }, [isDragging, isResizing]);
133
 
134
  if (!isOpen || isMinimized) return null;
135
 
@@ -137,13 +141,19 @@ export default function WindowShell({
137
  <div
138
  ref={windowRef}
139
  onMouseDown={() => setActiveWindow(id)}
140
- style={{
 
 
141
  width: `${dimensions.width}px`,
142
  height: `${dimensions.height}px`,
143
  transform: `translate(calc(-50% + ${position.x}px), calc(-50% + ${position.y}px))`,
144
  zIndex: isActive ? 40 : 30,
145
  }}
146
- className={`absolute top-1/2 left-1/2 max-w-[98vw] max-h-[90vh] bg-paper-white border-[4px] flex flex-col overflow-hidden window-shadow shadow-[inset_2px_2px_0px_rgba(255,255,255,0.8)] transition-all ${
 
 
 
 
147
  isActive ? 'border-ink-black shadow-[8px_8px_0px_0px_rgba(30,41,59,1)]' : 'border-ink-black opacity-95 shadow-[4px_4px_0px_0px_rgba(30,41,59,1)]'
148
  }`}
149
  >
@@ -162,15 +172,17 @@ export default function WindowShell({
162
  <span className="font-window-title text-sm md:text-base font-bold tracking-wide select-none">{title}</span>
163
  </div>
164
  <div className="flex gap-1.5">
165
- <button
166
- onClick={(e) => {
167
- e.stopPropagation();
168
- onMinimize();
169
- }}
170
- className="window-control-btn w-7 h-7 bg-white text-ink-black border-[3px] border-ink-black flex items-center justify-center hover:bg-yellow-300 active:translate-y-0.5 active:translate-x-0.5 shadow-[2px_2px_0px_0px_rgba(30,41,59,1)] active:shadow-none transition-all cursor-pointer"
171
- >
172
- <span className="material-symbols-outlined text-[14px] font-bold">minimize</span>
173
- </button>
 
 
174
  <button
175
  onClick={(e) => {
176
  e.stopPropagation();
@@ -189,15 +201,17 @@ export default function WindowShell({
189
  </div>
190
 
191
  {/* Resize Handle */}
192
- <div
193
- onMouseDown={handleResizeMouseDown}
194
- className="window-resize-handle absolute bottom-0 right-0 w-4 h-4 cursor-se-resize flex items-end justify-end p-0.5 select-none z-[50]"
195
- >
196
- <svg width="10" height="10" viewBox="0 0 10 10" className="text-ink-black opacity-60">
197
- <line x1="8" y1="2" x2="2" y2="8" stroke="currentColor" strokeWidth="1.5" />
198
- <line x1="8" y1="5" x2="5" y2="8" stroke="currentColor" strokeWidth="1.5" />
199
- </svg>
200
- </div>
 
 
201
  </div>
202
  );
203
  }
 
16
  defaultX?: number;
17
  defaultY?: number;
18
  titleBarColor?: string;
19
+ isMobile?: boolean;
20
  }
21
 
22
  export default function WindowShell({
 
35
  defaultX,
36
  defaultY,
37
  titleBarColor = '#0ea5e9',
38
+ isMobile = false,
39
  }: WindowShellProps) {
40
  // Helper to parse default dimensions (e.g. '700px') into integer values
41
  const parseDimension = (val: string): number => {
 
68
  }, [defaultX, defaultY]);
69
 
70
  const handleMouseDown = (e: React.MouseEvent) => {
71
+ if (isMobile) return;
72
  // Only drag on left click and not on control buttons or resize handles
73
  if (e.button !== 0) return;
74
  const target = e.target as HTMLElement;
 
84
  };
85
 
86
  const handleResizeMouseDown = (e: React.MouseEvent) => {
87
+ if (isMobile) return;
88
  if (e.button !== 0) return;
89
  e.stopPropagation();
90
  e.preventDefault();
 
133
  document.removeEventListener('mousemove', handleMouseMove);
134
  document.removeEventListener('mouseup', handleMouseUp);
135
  };
136
+ }, [isDragging, isResizing, isMobile]);
137
 
138
  if (!isOpen || isMinimized) return null;
139
 
 
141
  <div
142
  ref={windowRef}
143
  onMouseDown={() => setActiveWindow(id)}
144
+ style={isMobile ? {
145
+ zIndex: isActive ? 40 : 30,
146
+ } : {
147
  width: `${dimensions.width}px`,
148
  height: `${dimensions.height}px`,
149
  transform: `translate(calc(-50% + ${position.x}px), calc(-50% + ${position.y}px))`,
150
  zIndex: isActive ? 40 : 30,
151
  }}
152
+ className={`absolute bg-paper-white border-[4px] flex flex-col overflow-hidden window-shadow transition-all ${
153
+ isMobile
154
+ ? 'top-0 left-0 w-full h-[calc(100vh-56px)] max-w-none max-h-none border-t-0 border-x-0'
155
+ : 'top-1/2 left-1/2 max-w-[98vw] max-h-[90vh] border-ink-black'
156
+ } ${
157
  isActive ? 'border-ink-black shadow-[8px_8px_0px_0px_rgba(30,41,59,1)]' : 'border-ink-black opacity-95 shadow-[4px_4px_0px_0px_rgba(30,41,59,1)]'
158
  }`}
159
  >
 
172
  <span className="font-window-title text-sm md:text-base font-bold tracking-wide select-none">{title}</span>
173
  </div>
174
  <div className="flex gap-1.5">
175
+ {!isMobile && (
176
+ <button
177
+ onClick={(e) => {
178
+ e.stopPropagation();
179
+ onMinimize();
180
+ }}
181
+ className="window-control-btn w-7 h-7 bg-white text-ink-black border-[3px] border-ink-black flex items-center justify-center hover:bg-yellow-300 active:translate-y-0.5 active:translate-x-0.5 shadow-[2px_2px_0px_0px_rgba(30,41,59,1)] active:shadow-none transition-all cursor-pointer"
182
+ >
183
+ <span className="material-symbols-outlined text-[14px] font-bold">minimize</span>
184
+ </button>
185
+ )}
186
  <button
187
  onClick={(e) => {
188
  e.stopPropagation();
 
201
  </div>
202
 
203
  {/* Resize Handle */}
204
+ {!isMobile && (
205
+ <div
206
+ onMouseDown={handleResizeMouseDown}
207
+ className="window-resize-handle absolute bottom-0 right-0 w-4 h-4 cursor-se-resize flex items-end justify-end p-0.5 select-none z-[50]"
208
+ >
209
+ <svg width="10" height="10" viewBox="0 0 10 10" className="text-ink-black opacity-60">
210
+ <line x1="8" y1="2" x2="2" y2="8" stroke="currentColor" strokeWidth="1.5" />
211
+ <line x1="8" y1="5" x2="5" y2="8" stroke="currentColor" strokeWidth="1.5" />
212
+ </svg>
213
+ </div>
214
+ )}
215
  </div>
216
  );
217
  }