SarahXia0405 commited on
Commit
9aa8914
·
verified ·
1 Parent(s): 1eaec96

Update web/src/App.tsx

Browse files
Files changed (1) hide show
  1. web/src/App.tsx +55 -47
web/src/App.tsx CHANGED
@@ -348,7 +348,7 @@ function App() {
348
  localStorage.setItem("theme", isDarkMode ? "dark" : "light");
349
  }, [isDarkMode]);
350
 
351
- // ✅ 额外保险:锁 body 滚动(避免某些情况下仍出现页面滚动条)
352
  useEffect(() => {
353
  const prev = document.body.style.overflow;
354
  document.body.style.overflow = "hidden";
@@ -575,18 +575,19 @@ function App() {
575
  setUploadedFiles((prev) => prev.filter((_, i) => i !== index));
576
  };
577
 
 
578
  const handleFileTypeChange = async (index: number, type: FileType) => {
579
- setUploadedFiles((prev) => prev.map((file, i) => (i === index ? { ...file, type } : file)));
580
-
581
  if (!user) return;
582
 
583
- const target = uploadedFiles[index];
 
 
 
584
  const file = target?.file;
585
  if (!file) return;
586
 
587
  const fp = `${file.name}::${file.size}::${file.lastModified}`;
588
  if (uploadedFingerprintsRef.current.has(fp)) return;
589
-
590
  uploadedFingerprintsRef.current.add(fp);
591
 
592
  try {
@@ -858,17 +859,18 @@ function App() {
858
  if (showOnboarding && user) return <Onboarding user={user} onComplete={handleOnboardingComplete} onSkip={handleOnboardingSkip} />;
859
 
860
  return (
861
- <div className="appShell bg-background">
 
862
  <Toaster />
863
 
864
- {/* APP: column layout (header + main) */}
865
- <div className="col flex-1 min-w-0">
866
  {/* Header fixed */}
867
- <div className="colFixed flex-shrink-0">
868
  <Header
869
  user={user}
870
  onMenuClick={() => setLeftSidebarOpen(!leftSidebarOpen)}
871
- onUserClick={() => setShowProfileEditor(true)} // ✅ open profile editor
872
  isDarkMode={isDarkMode}
873
  onToggleDarkMode={() => setIsDarkMode(!isDarkMode)}
874
  language={language}
@@ -883,17 +885,19 @@ function App() {
883
  />
884
  </div>
885
 
886
- {showProfileEditor && user && <ProfileEditor user={user} onSave={setUser} onClose={() => setShowProfileEditor(false)} />}
 
 
887
 
888
  {/* Review banner fixed */}
889
  {showReviewBanner && (
890
- <div className="colFixed flex-shrink-0 w-full bg-background border-b border-border relative z-50">
891
  <ReviewBanner onReview={handleReviewClick} onDismiss={handleDismissReviewBanner} />
892
  </div>
893
  )}
894
 
895
  {/* Main area: NO page scroll, only inner panes scroll */}
896
- <div className="colFlex flex min-h-0 overflow-hidden relative" style={{ overscrollBehavior: "none" }}>
897
  {!leftPanelVisible && (
898
  <Button
899
  variant="secondary"
@@ -907,11 +911,13 @@ function App() {
907
  </Button>
908
  )}
909
 
910
- {leftSidebarOpen && <div className="fixed inset-0 bg-black/50 z-40 lg:hidden" onClick={() => setLeftSidebarOpen(false)} />}
 
 
911
 
912
  {/* Desktop left panel */}
913
  {leftPanelVisible ? (
914
- <aside className="hidden lg:flex w-80 bg-card border-r border-border col min-h-0 overflow-hidden relative">
915
  <Button
916
  variant="secondary"
917
  size="icon"
@@ -923,32 +929,34 @@ function App() {
923
  <ChevronLeft className="h-3 w-3" />
924
  </Button>
925
 
926
- {/* LeftSidebar 内部自己控制滚动(Saved list),外层绝不滚 */}
927
- <LeftSidebar
928
- learningMode={learningMode}
929
- language={language}
930
- onLearningModeChange={setLearningMode}
931
- onLanguageChange={setLanguage}
932
- spaceType={spaceType}
933
- groupMembers={groupMembers}
934
- user={user}
935
- onLogin={setUser}
936
- onLogout={() => setUser(null)}
937
- isLoggedIn={!!user}
938
- onEditProfile={() => setShowProfileEditor(true)}
939
- savedItems={savedItems}
940
- recentlySavedId={recentlySavedId}
941
- onUnsave={handleUnsave}
942
- onSave={handleSave}
943
- savedChats={savedChats}
944
- onLoadChat={handleLoadChat}
945
- onDeleteSavedChat={handleDeleteSavedChat}
946
- onRenameSavedChat={handleRenameSavedChat}
947
- currentWorkspaceId={currentWorkspaceId}
948
- workspaces={workspaces}
949
- selectedCourse={currentCourseId}
950
- availableCourses={availableCourses}
951
- />
 
 
952
  </aside>
953
  ) : null}
954
 
@@ -959,21 +967,21 @@ function App() {
959
  w-80 bg-card border-r border-border
960
  transform transition-transform duration-300 ease-in-out
961
  ${leftSidebarOpen ? "translate-x-0" : "-translate-x-full"}
962
- col
963
  mt-16
964
  h-[calc(100vh-4rem)]
965
  min-h-0
966
  overflow-hidden
 
967
  `}
968
  >
969
- <div className="colFixed p-4 border-b border-border flex justify-between items-center flex-shrink-0">
970
  <h3>Settings & Guide</h3>
971
  <Button variant="ghost" size="icon" onClick={() => setLeftSidebarOpen(false)}>
972
  <X className="h-5 w-5" />
973
  </Button>
974
  </div>
975
 
976
- <div className="colFlex min-h-0 overflow-hidden">
977
  <LeftSidebar
978
  learningMode={learningMode}
979
  language={language}
@@ -993,7 +1001,7 @@ function App() {
993
  savedChats={savedChats}
994
  onLoadChat={handleLoadChat}
995
  onDeleteSavedChat={handleDeleteSavedChat}
996
- onRenameSavedChat={handleRenameSavedChat} // ✅ 补齐:避免 LeftSidebar props TS 报错
997
  currentWorkspaceId={currentWorkspaceId}
998
  workspaces={workspaces}
999
  selectedCourse={currentCourseId}
@@ -1003,8 +1011,8 @@ function App() {
1003
  </aside>
1004
 
1005
  {/* Chat column: outer never scroll, ChatArea controls internal scroll */}
1006
- <main className="flex-1 min-w-0 col min-h-0 overflow-hidden">
1007
- <div className="colFlex min-h-0 overflow-hidden">
1008
  <ChatArea
1009
  messages={messages}
1010
  onSendMessage={handleSendMessage}
 
348
  localStorage.setItem("theme", isDarkMode ? "dark" : "light");
349
  }, [isDarkMode]);
350
 
351
+ // ✅ lock body scroll (avoid outer page scrollbars)
352
  useEffect(() => {
353
  const prev = document.body.style.overflow;
354
  document.body.style.overflow = "hidden";
 
575
  setUploadedFiles((prev) => prev.filter((_, i) => i !== index));
576
  };
577
 
578
+ // ✅ FIX: use the same "next" array for state update and for uploading; do NOT read stale `uploadedFiles`
579
  const handleFileTypeChange = async (index: number, type: FileType) => {
 
 
580
  if (!user) return;
581
 
582
+ const next = uploadedFiles.map((f, i) => (i === index ? { ...f, type } : f));
583
+ setUploadedFiles(next);
584
+
585
+ const target = next[index];
586
  const file = target?.file;
587
  if (!file) return;
588
 
589
  const fp = `${file.name}::${file.size}::${file.lastModified}`;
590
  if (uploadedFingerprintsRef.current.has(fp)) return;
 
591
  uploadedFingerprintsRef.current.add(fp);
592
 
593
  try {
 
859
  if (showOnboarding && user) return <Onboarding user={user} onComplete={handleOnboardingComplete} onSkip={handleOnboardingSkip} />;
860
 
861
  return (
862
+ // CRITICAL: make the whole app fill viewport and avoid page scroll
863
+ <div className="h-screen w-full overflow-hidden bg-background">
864
  <Toaster />
865
 
866
+ {/* APP column layout (header + main) */}
867
+ <div className="flex flex-col h-full min-h-0 min-w-0">
868
  {/* Header fixed */}
869
+ <div className="flex-shrink-0">
870
  <Header
871
  user={user}
872
  onMenuClick={() => setLeftSidebarOpen(!leftSidebarOpen)}
873
+ onUserClick={() => setShowProfileEditor(true)}
874
  isDarkMode={isDarkMode}
875
  onToggleDarkMode={() => setIsDarkMode(!isDarkMode)}
876
  language={language}
 
885
  />
886
  </div>
887
 
888
+ {showProfileEditor && user && (
889
+ <ProfileEditor user={user} onSave={setUser} onClose={() => setShowProfileEditor(false)} />
890
+ )}
891
 
892
  {/* Review banner fixed */}
893
  {showReviewBanner && (
894
+ <div className="flex-shrink-0 w-full bg-background border-b border-border relative z-50">
895
  <ReviewBanner onReview={handleReviewClick} onDismiss={handleDismissReviewBanner} />
896
  </div>
897
  )}
898
 
899
  {/* Main area: NO page scroll, only inner panes scroll */}
900
+ <div className="flex-1 min-h-0 min-w-0 flex overflow-hidden relative" style={{ overscrollBehavior: "none" }}>
901
  {!leftPanelVisible && (
902
  <Button
903
  variant="secondary"
 
911
  </Button>
912
  )}
913
 
914
+ {leftSidebarOpen && (
915
+ <div className="fixed inset-0 bg-black/50 z-40 lg:hidden" onClick={() => setLeftSidebarOpen(false)} />
916
+ )}
917
 
918
  {/* Desktop left panel */}
919
  {leftPanelVisible ? (
920
+ <aside className="hidden lg:flex w-80 h-full min-h-0 min-w-0 bg-card border-r border-border overflow-hidden relative">
921
  <Button
922
  variant="secondary"
923
  size="icon"
 
929
  <ChevronLeft className="h-3 w-3" />
930
  </Button>
931
 
932
+ {/* LeftSidebar controls internal scroll (Saved list), outer never scrolls */}
933
+ <div className="flex-1 min-h-0 min-w-0 overflow-hidden">
934
+ <LeftSidebar
935
+ learningMode={learningMode}
936
+ language={language}
937
+ onLearningModeChange={setLearningMode}
938
+ onLanguageChange={setLanguage}
939
+ spaceType={spaceType}
940
+ groupMembers={groupMembers}
941
+ user={user}
942
+ onLogin={setUser}
943
+ onLogout={() => setUser(null)}
944
+ isLoggedIn={!!user}
945
+ onEditProfile={() => setShowProfileEditor(true)}
946
+ savedItems={savedItems}
947
+ recentlySavedId={recentlySavedId}
948
+ onUnsave={handleUnsave}
949
+ onSave={handleSave}
950
+ savedChats={savedChats}
951
+ onLoadChat={handleLoadChat}
952
+ onDeleteSavedChat={handleDeleteSavedChat}
953
+ onRenameSavedChat={handleRenameSavedChat}
954
+ currentWorkspaceId={currentWorkspaceId}
955
+ workspaces={workspaces}
956
+ selectedCourse={currentCourseId}
957
+ availableCourses={availableCourses}
958
+ />
959
+ </div>
960
  </aside>
961
  ) : null}
962
 
 
967
  w-80 bg-card border-r border-border
968
  transform transition-transform duration-300 ease-in-out
969
  ${leftSidebarOpen ? "translate-x-0" : "-translate-x-full"}
 
970
  mt-16
971
  h-[calc(100vh-4rem)]
972
  min-h-0
973
  overflow-hidden
974
+ flex flex-col
975
  `}
976
  >
977
+ <div className="p-4 border-b border-border flex justify-between items-center flex-shrink-0">
978
  <h3>Settings & Guide</h3>
979
  <Button variant="ghost" size="icon" onClick={() => setLeftSidebarOpen(false)}>
980
  <X className="h-5 w-5" />
981
  </Button>
982
  </div>
983
 
984
+ <div className="flex-1 min-h-0 overflow-hidden">
985
  <LeftSidebar
986
  learningMode={learningMode}
987
  language={language}
 
1001
  savedChats={savedChats}
1002
  onLoadChat={handleLoadChat}
1003
  onDeleteSavedChat={handleDeleteSavedChat}
1004
+ onRenameSavedChat={handleRenameSavedChat}
1005
  currentWorkspaceId={currentWorkspaceId}
1006
  workspaces={workspaces}
1007
  selectedCourse={currentCourseId}
 
1011
  </aside>
1012
 
1013
  {/* Chat column: outer never scroll, ChatArea controls internal scroll */}
1014
+ <main className="flex-1 min-w-0 min-h-0 overflow-hidden flex flex-col">
1015
+ <div className="flex-1 min-h-0 overflow-hidden">
1016
  <ChatArea
1017
  messages={messages}
1018
  onSendMessage={handleSendMessage}