Add settings route with React Router

This commit is contained in:
tianma committed 2026-06-30 13:21:57 +08:00
1 parent 4b7956449d
commit bb19e2ca99
5 files changed
+91 -17

No files matched your search

+28 -16
View File
@@ -1,5 +1,6 @@
import { useEffect } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { Navigate, Route, Routes, useNavigate } from "react-router";
import { api } from "@/lib/api";
import { EvernoteImportGuidePane } from "@/components/EvernoteImportGuidePane";
import { LoginScreen } from "@/components/LoginScreen";
@@ -12,24 +13,26 @@ const AuthLoadingScreen = () => (
</div>
);
export const App = () => {
const EvernoteMigrationRoute = () => {
const navigate = useNavigate();
return (
<EvernoteImportGuidePane
onClose={() => {
if (window.opener) {
window.close();
return;
}
navigate("/");
}}
/>
);
};
const AuthenticatedWorkspace = () => {
const queryClient = useQueryClient();
if (window.location.pathname === "/evernote-migration") {
return (
<EvernoteImportGuidePane
onClose={() => {
if (window.opener) {
window.close();
return;
}
window.location.href = "/";
}}
/>
);
}
const sessionQuery = useQuery({
queryKey: ["auth", "session"],
queryFn: () => api.getSession(),
@@ -96,3 +99,12 @@ export const App = () => {
/>
);
};
export const App = () => (
<Routes>
<Route path="/evernote-migration" element={<EvernoteMigrationRoute />} />
<Route path="/" element={<AuthenticatedWorkspace />} />
<Route path="/settings" element={<AuthenticatedWorkspace />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
);
+53
View File
@@ -14,6 +14,7 @@ import {
} from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { Home, Search, UserRound, Plus, ChevronDown, ChevronRight, RefreshCw, X } from "lucide-react";
import { useLocation, useNavigate } from "react-router";
import { Button } from "@/components/ui/button";
import {
Drawer,
@@ -95,6 +96,8 @@ const NotebookPane = lazy(() => import("./NotebookPane").then((module) => ({ def
const TagsDialog = lazy(() => import("./dialogs/TagsDialog").then((module) => ({ default: module.TagsDialog })));
const TemplatesDialog = lazy(() => import("./dialogs/TemplatesDialog").then((module) => ({ default: module.TemplatesDialog })));
const SETTINGS_PATH = "/settings";
const emptySyncQueueSummary = (): SyncQueueSummary => ({
total: 0,
pending: 0,
@@ -451,6 +454,8 @@ export const WorkspaceApp = ({
onLogout: () => void;
}) => {
const queryClient = useQueryClient();
const location = useLocation();
const navigate = useNavigate();
const [activePane, setActivePane] = useState<Pane>("memos");
const [memoView, setMemoView] = useState<MemoView>("notebook");
const [selectedNotebookId, setSelectedNotebookId] = useState<string | null>(null);
@@ -483,6 +488,7 @@ export const WorkspaceApp = ({
const [pullToRefreshDistance, setPullToRefreshDistance] = useState(0);
const [isPullRefreshing, setIsPullRefreshing] = useState(false);
const isPullRefreshingRef = useRef(false);
const skipNextHomeRouteSyncRef = useRef(false);
const [mobileListActionsOpen, setMobileListActionsOpen] = useState(false);
const [mobileMoveOpen, setMobileMoveOpen] = useState(false);
@@ -491,6 +497,18 @@ export const WorkspaceApp = ({
const [desktopSortOpen, setDesktopSortOpen] = useState(false);
const [desktopActionsOpen, setDesktopActionsOpen] = useState(false);
const navigateWorkspaceHome = () => {
if (location.pathname !== "/") {
navigate("/");
}
};
const navigateWorkspaceSettings = () => {
if (location.pathname !== SETTINGS_PATH) {
navigate(SETTINGS_PATH);
}
};
const runQueuedSync = useCallback(async () => {
if (typeof navigator !== "undefined" && !navigator.onLine) {
setIsOnline(false);
@@ -638,6 +656,24 @@ export const WorkspaceApp = ({
writeImageCompressionPreference(imageCompressionEnabled);
}, [imageCompressionEnabled]);
useEffect(() => {
if (location.pathname === SETTINGS_PATH) {
skipNextHomeRouteSyncRef.current = false;
setRightView("settings");
setMobileBottomNavActive("settings");
setActivePane("editor");
return;
}
if (skipNextHomeRouteSyncRef.current) {
skipNextHomeRouteSyncRef.current = false;
return;
}
setRightView("editor");
setMobileBottomNavActive("home");
}, [location.pathname]);
useEffect(() => {
let unsubscribe: (() => void) | undefined;
let active = true;
@@ -873,6 +909,7 @@ export const WorkspaceApp = ({
queryClient.invalidateQueries({ queryKey: ["notebooks"] }),
]);
queryClient.setQueryData(["memo", data.memo.id], { memo: data.memo });
navigateWorkspaceHome();
setRightView("editor");
setCreatedMemoEditId(data.memo.id);
setSelectedMemoId(data.memo.id);
@@ -889,6 +926,7 @@ export const WorkspaceApp = ({
queryClient.invalidateQueries({ queryKey: ["notebooks"] }),
]);
queryClient.setQueryData(["memo", data.memo.id], { memo: data.memo });
navigateWorkspaceHome();
setRightView("editor");
setSelectedMemoId(data.memo.id);
setActivePane("editor");
@@ -1015,6 +1053,7 @@ export const WorkspaceApp = ({
]);
queryClient.setQueryData(["memo", data.memo.id], { memo: data.memo });
setSelectedNotebookId(data.memo.notebookId);
navigateWorkspaceHome();
setRightView("editor");
setSelectedMemoId(data.memo.id);
setActivePane("editor");
@@ -1269,6 +1308,7 @@ export const WorkspaceApp = ({
};
const handleSelectNotebook = (notebookId: string) => {
navigateWorkspaceHome();
setMemoView("notebook");
setSelectedNotebookId(notebookId);
setMobileBottomNavActive("home");
@@ -1278,6 +1318,7 @@ export const WorkspaceApp = ({
};
const handleSelectAllMemos = () => {
navigateWorkspaceHome();
setMemoView("notebook");
setSelectedNotebookId(null);
setMobileBottomNavActive("home");
@@ -1287,6 +1328,7 @@ export const WorkspaceApp = ({
};
const handleMobileHome = () => {
navigateWorkspaceHome();
if (memoView === "trash") {
setMemoView("notebook");
}
@@ -1318,6 +1360,8 @@ export const WorkspaceApp = ({
const handleOpenAssets = () => {
clearHiddenMobileSearch();
skipNextHomeRouteSyncRef.current = location.pathname !== "/";
navigateWorkspaceHome();
setRightView("assets");
setActivePane("editor");
};
@@ -1335,11 +1379,14 @@ export const WorkspaceApp = ({
const handleOpenSettings = () => {
clearHiddenMobileSearch();
navigateWorkspaceSettings();
setRightView("settings");
setMobileBottomNavActive("settings");
setActivePane("editor");
};
const handleCloseAssets = () => {
navigateWorkspaceHome();
setRightView("editor");
setMobileBottomNavActive("home");
};
@@ -1350,6 +1397,7 @@ export const WorkspaceApp = ({
};
const handleCloseSettings = () => {
navigateWorkspaceHome();
setRightView("editor");
setMobileBottomNavActive("home");
if (!isDesktopViewport()) {
@@ -1723,6 +1771,7 @@ export const WorkspaceApp = ({
canCreateMemo={canCreateMemo}
isCreatingMemo={createMemoMutation.isPending}
onSelect={(notebookId) => {
navigateWorkspaceHome();
setMemoView("notebook");
setSelectedNotebookId(notebookId);
clearMemoSelection();
@@ -1736,6 +1785,7 @@ export const WorkspaceApp = ({
onMoveNotebook={handleMoveNotebook}
onMoveMemos={handleMoveDraggedMemos}
onBackToList={() => {
navigateWorkspaceHome();
if (memoView === "trash") {
setMemoView("notebook");
}
@@ -1756,6 +1806,7 @@ export const WorkspaceApp = ({
onOpenTags={handleOpenTags}
onOpenSettings={handleOpenSettings}
onOpenTrash={() => {
navigateWorkspaceHome();
setMemoView("trash");
setSelectedNotebookId(null);
setMobileBottomNavActive("home");
@@ -1806,6 +1857,7 @@ export const WorkspaceApp = ({
onOpenTags={handleOpenTags}
onOpenSettings={handleOpenSettings}
onOpenTrash={() => {
navigateWorkspaceHome();
setMemoView("trash");
setSelectedNotebookId(null);
setMobileBottomNavActive("home");
@@ -1815,6 +1867,7 @@ export const WorkspaceApp = ({
setActivePane("memos");
}}
onOpenMemo={(memoId) => {
navigateWorkspaceHome();
setRightView("editor");
setCreatedMemoEditId(null);
setSelectedMemoId(memoId);
+4 -1
View File
@@ -1,6 +1,7 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import React from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router";
import { registerSW } from "virtual:pwa-register";
import { App } from "./app/App";
import "./styles/globals.css";
@@ -26,7 +27,9 @@ if (!root) {
createRoot(root).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<App />
<BrowserRouter>
<App />
</BrowserRouter>
</QueryClientProvider>
</React.StrictMode>
);
+5
View File
@@ -30,6 +30,7 @@
"lucide-react": "latest",
"react": "latest",
"react-dom": "latest",
"react-router": "^8.1.0",
"sharp": "^0.35.2",
"tailwind-merge": "latest",
"tailwindcss-animate": "^1.0.7",
@@ -777,6 +778,8 @@
"cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
"cookie-es": ["cookie-es@3.1.1", "", {}, "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg=="],
"core-js-compat": ["core-js-compat@3.49.0", "", { "dependencies": { "browserslist": "^4.28.1" } }, "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
@@ -1173,6 +1176,8 @@
"react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="],
"react-router": ["react-router@8.1.0", "", { "dependencies": { "cookie-es": "^3.1.1" }, "peerDependencies": { "react": ">=19.2.7", "react-dom": ">=19.2.7" }, "optionalPeers": ["react-dom"] }, "sha512-Mdfi61uObuvWNN9OhChOC0HV6YWOIfKRzEWOvCHRSuQg8IM+Nv10edaM/2HE8ZixBpUTdQbruyWqC3sDkkh9vw=="],
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
"read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="],
+1
View File
@@ -61,6 +61,7 @@
"lucide-react": "latest",
"react": "latest",
"react-dom": "latest",
"react-router": "^8.1.0",
"sharp": "^0.35.2",
"tailwind-merge": "latest",
"tailwindcss-animate": "^1.0.7",