fix: 去除路由改为 Store 控制当前激活 Tab
This commit is contained in:
parent
cc3a8984c1
commit
ff35f5b105
|
|
@ -1,5 +1,3 @@
|
||||||
import { useEffect } from "react";
|
|
||||||
import { useLocation, useNavigate } from "react-router";
|
|
||||||
import { X } from "lucide-react";
|
import { X } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { useProjectTabsStore } from "@/store/project-tabs-store";
|
import { useProjectTabsStore } from "@/store/project-tabs-store";
|
||||||
|
|
@ -10,16 +8,6 @@ export function ProjectTabsBar() {
|
||||||
const activateTab = useProjectTabsStore((state) => state.activateTab);
|
const activateTab = useProjectTabsStore((state) => state.activateTab);
|
||||||
const activateHome = useProjectTabsStore((state) => state.activateHome);
|
const activateHome = useProjectTabsStore((state) => state.activateHome);
|
||||||
const closeTab = useProjectTabsStore((state) => state.closeTab);
|
const closeTab = useProjectTabsStore((state) => state.closeTab);
|
||||||
const location = useLocation();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const active = tabs.find((tab) => tab.id === activeTabId);
|
|
||||||
if (!active) return;
|
|
||||||
const targetPath = active.kind === "home" ? "/" : `/editor/${active.projectId}`;
|
|
||||||
if (location.pathname === targetPath) return;
|
|
||||||
navigate(targetPath);
|
|
||||||
}, [activeTabId, tabs, location.pathname, navigate]);
|
|
||||||
|
|
||||||
function handleSelect(tabId: string, kind: "home" | "project") {
|
function handleSelect(tabId: string, kind: "home" | "project") {
|
||||||
if (kind === "home") activateHome();
|
if (kind === "home") activateHome();
|
||||||
|
|
|
||||||
26
src/main.tsx
26
src/main.tsx
|
|
@ -1,26 +1,26 @@
|
||||||
import { StrictMode } from "react";
|
import { StrictMode } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
import { createHashRouter } from "react-router";
|
|
||||||
import { RouterProvider } from "react-router/dom";
|
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
import Home from "./pages/home.tsx";
|
import Home from "./pages/home.tsx";
|
||||||
import Editor from "./pages/editor.tsx";
|
import Editor from "./pages/editor.tsx";
|
||||||
import { Toaster } from "@/components/ui/sonner";
|
import { Toaster } from "@/components/ui/sonner";
|
||||||
|
import { useProjectTabsStore } from "@/store/project-tabs-store";
|
||||||
|
|
||||||
const router = createHashRouter([
|
function App() {
|
||||||
{
|
const tabs = useProjectTabsStore((state) => state.tabs);
|
||||||
path: "/",
|
const activeTabId = useProjectTabsStore((state) => state.activeTabId);
|
||||||
element: <Home />,
|
const active = tabs.find((tab) => tab.id === activeTabId);
|
||||||
},
|
|
||||||
{
|
if (active?.kind === "project") {
|
||||||
path: "/editor/:id",
|
return <Editor projectId={active.projectId} />;
|
||||||
element: <Editor />,
|
}
|
||||||
},
|
|
||||||
]);
|
return <Home />;
|
||||||
|
}
|
||||||
|
|
||||||
createRoot(document.getElementById("root")!).render(
|
createRoot(document.getElementById("root")!).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<RouterProvider router={router} />
|
<App />
|
||||||
<Toaster position="top-center" />
|
<Toaster position="top-center" />
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
import { useParams, useNavigate } from "react-router";
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import {
|
import {
|
||||||
|
|
@ -18,7 +17,7 @@ import {
|
||||||
updateProject,
|
updateProject,
|
||||||
deleteProjectDeep,
|
deleteProjectDeep,
|
||||||
} from "@/lib/db";
|
} from "@/lib/db";
|
||||||
import { ArrowBigDownDash, ArrowBigUpDash, Brackets, CaseSensitive, Filter, FolderOpen, Languages, LocateFixed, MoreVertical, PencilLine, Reply, Save, Settings, Trash2 } from "lucide-react";
|
import { ArrowBigDownDash, ArrowBigUpDash, Brackets, CaseSensitive, Filter, FolderOpen, Languages, LocateFixed, MoreVertical, PencilLine, Save, Settings, Trash2 } from "lucide-react";
|
||||||
import { useTranslationInlineEdit } from "@/hooks/biz/use-translation-inline-edit";
|
import { useTranslationInlineEdit } from "@/hooks/biz/use-translation-inline-edit";
|
||||||
import { buildStructureFromObject, flattenEntries, flattenValues, type FlatEntry, insertEntrySibling, removeEntryAtPath, renameEntryAtPath, moveEntryByOffset } from "@/lib/i18n-structure";
|
import { buildStructureFromObject, flattenEntries, flattenValues, type FlatEntry, insertEntrySibling, removeEntryAtPath, renameEntryAtPath, moveEntryByOffset } from "@/lib/i18n-structure";
|
||||||
import { ImportLanguageModal } from "@/components/biz/import-language-modal";
|
import { ImportLanguageModal } from "@/components/biz/import-language-modal";
|
||||||
|
|
@ -51,9 +50,11 @@ import { loadNativeProjectSources, saveNativeLanguageFile, type LoadedProjectSou
|
||||||
import { useProjectSourcesStore } from "@/store/sources-store";
|
import { useProjectSourcesStore } from "@/store/sources-store";
|
||||||
import CommonMenubar, { type CommonMenubarItem } from "@/components/biz/editor/common-menubar";
|
import CommonMenubar, { type CommonMenubarItem } from "@/components/biz/editor/common-menubar";
|
||||||
|
|
||||||
export default function Editor() {
|
type EditorProps = {
|
||||||
const { id: projectId } = useParams();
|
projectId?: string;
|
||||||
const navigate = useNavigate();
|
};
|
||||||
|
|
||||||
|
export default function Editor({ projectId }: EditorProps) {
|
||||||
const [project, setProject] = useState<Project | null>(null);
|
const [project, setProject] = useState<Project | null>(null);
|
||||||
const [structure, setStructure] = useState<ProjectStructure | null>(null);
|
const [structure, setStructure] = useState<ProjectStructure | null>(null);
|
||||||
const [languages, setLanguages] = useState<string[]>([]);
|
const [languages, setLanguages] = useState<string[]>([]);
|
||||||
|
|
@ -605,23 +606,6 @@ export default function Editor() {
|
||||||
<CommonMenubar disabledItems={disabledItems} onClickItem={onClickItem} />
|
<CommonMenubar disabledItems={disabledItems} onClickItem={onClickItem} />
|
||||||
<div className="flex items-center justify-end gap-2 text-foreground">
|
<div className="flex items-center justify-end gap-2 text-foreground">
|
||||||
<HeaderConnectionIndicator projectId={projectId ?? ""} />
|
<HeaderConnectionIndicator projectId={projectId ?? ""} />
|
||||||
{!structure ? (
|
|
||||||
<Button onClick={() => { setSourcesWizardOpen(true); }}>
|
|
||||||
<FolderOpen />
|
|
||||||
通过目录导入
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Button variant="outline" onClick={() => { setSourcesWizardOpen(true); }}>
|
|
||||||
<FolderOpen />
|
|
||||||
目录导入
|
|
||||||
</Button>
|
|
||||||
<Button variant="outline" onClick={() => { setImportOpen(true); }}>
|
|
||||||
<Reply />
|
|
||||||
单文件导入
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{projectId && (
|
{projectId && (
|
||||||
<SyncFromFilesButton
|
<SyncFromFilesButton
|
||||||
projectId={projectId ?? ""}
|
projectId={projectId ?? ""}
|
||||||
|
|
@ -640,9 +624,9 @@ export default function Editor() {
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{project && (
|
{project && (
|
||||||
<Button variant="outline" onClick={() => setSettingsOpen(true)}>
|
<Button variant="ghost" onClick={() => setSettingsOpen(true)}>
|
||||||
<Settings />
|
<Settings />
|
||||||
设置
|
<span className="sr-only">设置</span>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -832,7 +816,6 @@ export default function Editor() {
|
||||||
await deleteProjectDeep(projectId);
|
await deleteProjectDeep(projectId);
|
||||||
forgetProjectInTabs(projectId);
|
forgetProjectInTabs(projectId);
|
||||||
activateHomeTab();
|
activateHomeTab();
|
||||||
navigate("/");
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { useNavigate } from "react-router";
|
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { createProject, deleteProjectDeep, listProjects, type Project, updateProject } from "@/lib/db";
|
import { createProject, deleteProjectDeep, listProjects, type Project, updateProject } from "@/lib/db";
|
||||||
|
|
@ -26,7 +25,6 @@ function App() {
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [settingsOpen, setSettingsOpen] = useState(false);
|
const [settingsOpen, setSettingsOpen] = useState(false);
|
||||||
const [currentProject, setCurrentProject] = useState<Project | null>(null);
|
const [currentProject, setCurrentProject] = useState<Project | null>(null);
|
||||||
const navigate = useNavigate();
|
|
||||||
const flags = useConnectionFlags();
|
const flags = useConnectionFlags();
|
||||||
const activateHomeTab = useProjectTabsStore((state) => state.activateHome);
|
const activateHomeTab = useProjectTabsStore((state) => state.activateHome);
|
||||||
const registerProjectsInTabs = useProjectTabsStore((state) => state.registerProjects);
|
const registerProjectsInTabs = useProjectTabsStore((state) => state.registerProjects);
|
||||||
|
|
@ -119,14 +117,12 @@ function App() {
|
||||||
className="relative cursor-pointer rounded-md border p-4 transition hover:shadow-sm"
|
className="relative cursor-pointer rounded-md border p-4 transition hover:shadow-sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openProjectTab(p);
|
openProjectTab(p);
|
||||||
navigate(`/editor/${p.id}`);
|
|
||||||
}}
|
}}
|
||||||
role="button"
|
role="button"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter" || e.key === " ") {
|
if (e.key === "Enter" || e.key === " ") {
|
||||||
openProjectTab(p);
|
openProjectTab(p);
|
||||||
navigate(`/editor/${p.id}`);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,8 @@ export const useProjectTabsStore = create<ProjectTabsStore>((set, get) => ({
|
||||||
get().closeProjectTab(projectId);
|
get().closeProjectTab(projectId);
|
||||||
set((state) => {
|
set((state) => {
|
||||||
if (!state.projectIndex[projectId]) return state;
|
if (!state.projectIndex[projectId]) return state;
|
||||||
const { [projectId]: _removed, ...rest } = state.projectIndex;
|
|
||||||
|
const { [projectId]: _removed, ...rest } = state.projectIndex; // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||||
return {
|
return {
|
||||||
projectIndex: rest,
|
projectIndex: rest,
|
||||||
lastActiveProjectId: state.lastActiveProjectId === projectId ? null : state.lastActiveProjectId,
|
lastActiveProjectId: state.lastActiveProjectId === projectId ? null : state.lastActiveProjectId,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue