[ENG-1592] Correctly assign tab titles on desktop (#2030)

* correctly set tab titles

* use selectedTabIndex

* empty tabId

* prettier
This commit is contained in:
Brendan Allan 2024-02-01 23:40:38 +08:00 committed by GitHub
parent 8cbd38d6f9
commit 74d97d4957
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 36 additions and 31 deletions

View file

@ -80,18 +80,22 @@ const routes = createRoutes(platform, cache);
function AppInner() { function AppInner() {
const [tabs, setTabs] = useState(() => [createTab()]); const [tabs, setTabs] = useState(() => [createTab()]);
const [tabIndex, setTabIndex] = useState(0); const [selectedTabIndex, setSelectedTabIndex] = useState(0);
const selectedTab = tabs[selectedTabIndex]!;
function createTab() { function createTab() {
const history = createMemoryHistory(); const history = createMemoryHistory();
const router = createMemoryRouterWithHistory({ routes, history }); const router = createMemoryRouterWithHistory({ routes, history });
const id = Math.random().toString();
const dispose = router.subscribe((event) => { const dispose = router.subscribe((event) => {
// we don't care about non-idle events as those are artifacts of form mutations + suspense // we don't care about non-idle events as those are artifacts of form mutations + suspense
if (event.navigation.state !== 'idle') return; if (event.navigation.state !== 'idle') return;
setTabs((routers) => { setTabs((routers) => {
const index = routers.findIndex((r) => r.router === router); const index = routers.findIndex((r) => r.id === id);
if (index === -1) return routers; if (index === -1) return routers;
const routerAtIndex = routers[index]!; const routerAtIndex = routers[index]!;
@ -105,12 +109,12 @@ function AppInner() {
: Math.max(routerAtIndex.maxIndex, history.index) : Math.max(routerAtIndex.maxIndex, history.index)
}; };
return [...routers]; return [...routers]
}); });
}); });
return { return {
id: Math.random().toString(), id,
router, router,
history, history,
dispose, dispose,
@ -121,8 +125,6 @@ function AppInner() {
}; };
} }
const tab = tabs[tabIndex]!;
const createTabPromise = useRef(Promise.resolve()); const createTabPromise = useRef(Promise.resolve());
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
@ -131,38 +133,37 @@ function AppInner() {
const div = ref.current; const div = ref.current;
if (!div) return; if (!div) return;
div.appendChild(tab.element); div.appendChild(selectedTab.element);
return () => { return () => {
while (div.firstChild) { while (div.firstChild) {
div.removeChild(div.firstChild); div.removeChild(div.firstChild);
} }
}; };
}, [tab.element]); }, [selectedTab.element]);
return ( return (
<RouteTitleContext.Provider <RouteTitleContext.Provider
value={useMemo( value={useMemo(
() => ({ () => ({
setTitle(title) { setTitle(id, title) {
setTabs((oldTabs) => { setTabs((tabs) => {
const tabs = [...oldTabs]; const tabIndex = tabs.findIndex(t => t.id === id);
const tab = tabs[tabIndex]; if (tabIndex === -1) return tabs;
if (!tab) return tabs;
tabs[tabIndex] = { ...tab, title }; tabs[tabIndex] = { ...tabs[tabIndex]!, title };
return tabs; return [...tabs];
}); });
} }
}), }),
[tabIndex] []
)} )}
> >
<TabsContext.Provider <TabsContext.Provider
value={{ value={{
tabIndex, tabIndex: selectedTabIndex,
setTabIndex, setTabIndex: setSelectedTabIndex,
tabs: tabs.map(({ router, title }) => ({ router, title })), tabs: tabs.map(({ router, title }) => ({ router, title })),
createTab() { createTab() {
createTabPromise.current = createTabPromise.current.then( createTabPromise.current = createTabPromise.current.then(
@ -170,9 +171,10 @@ function AppInner() {
new Promise((res) => { new Promise((res) => {
startTransition(() => { startTransition(() => {
setTabs((tabs) => { setTabs((tabs) => {
const newTabs = [...tabs, createTab()]; const newTab = createTab();
const newTabs = [...tabs, newTab];
setTabIndex(newTabs.length - 1); setSelectedTabIndex(newTabs.length - 1);
return newTabs; return newTabs;
}); });
@ -192,7 +194,7 @@ function AppInner() {
tabs.splice(index, 1); tabs.splice(index, 1);
setTabIndex(Math.min(tabIndex, tabs.length - 1)); setSelectedTabIndex(Math.min(selectedTabIndex, tabs.length - 1));
return [...tabs]; return [...tabs];
}); });
@ -201,15 +203,16 @@ function AppInner() {
}} }}
> >
<SpacedriveInterfaceRoot> <SpacedriveInterfaceRoot>
{tabs.map((tab) => {tabs.map((tab, index) =>
createPortal( createPortal(
<SpacedriveRouterProvider <SpacedriveRouterProvider
key={tab.id} key={tab.id}
routing={{ routing={{
routes, routes,
visible: tabIndex === tabs.indexOf(tab), visible: selectedTabIndex === tabs.indexOf(tab),
router: tab.router, router: tab.router,
currentIndex: tab.currentIndex, currentIndex: tab.currentIndex,
tabId: tab.id,
maxIndex: tab.maxIndex maxIndex: tab.maxIndex
}} }}
/>, />,

View file

@ -112,6 +112,7 @@ function App() {
<SpacedriveRouterProvider <SpacedriveRouterProvider
routing={{ routing={{
...router, ...router,
tabId: '',
routes, routes,
visible: true visible: true
}} }}

View file

@ -1,8 +1,4 @@
use crate::{ use crate::{api::CoreEvent, object::media::thumbnail::get_indexed_thumbnail_path, sync, Node};
api::CoreEvent,
object::{media::thumbnail::get_indexed_thumbnail_path, orphan_remover::OrphanRemoverActor},
sync, Node,
};
use sd_file_path_helper::{file_path_to_full_path, IsolatedFilePathData}; use sd_file_path_helper::{file_path_to_full_path, IsolatedFilePathData};
use sd_p2p::spacetunnel::Identity; use sd_p2p::spacetunnel::Identity;

View file

@ -6,6 +6,7 @@ import { createRoutes } from './app';
export const RoutingContext = createContext<{ export const RoutingContext = createContext<{
visible: boolean; visible: boolean;
currentIndex: number; currentIndex: number;
tabId: string;
maxIndex: number; maxIndex: number;
routes: ReturnType<typeof createRoutes>; routes: ReturnType<typeof createRoutes>;
} | null>(null); } | null>(null);

View file

@ -1,17 +1,19 @@
import { createContext, useContext, useLayoutEffect } from 'react'; import { createContext, useContext, useLayoutEffect } from 'react';
import { useRoutingContext } from '~/RoutingContext';
export function useRouteTitle(title: string) { export function useRouteTitle(title: string) {
const routingCtx = useRoutingContext();
const ctx = useContext(RouteTitleContext); const ctx = useContext(RouteTitleContext);
// layout effect avoids 'New Tab' showing up briefly // layout effect avoids 'New Tab' showing up briefly
useLayoutEffect(() => { useLayoutEffect(() => {
document.title = title; document.title = title;
if (ctx) ctx.setTitle(title); if (ctx) ctx.setTitle(routingCtx.tabId, title);
}, [title, ctx]); }, [routingCtx.tabId, title, ctx]);
return title; return title;
} }
export const RouteTitleContext = createContext<{ export const RouteTitleContext = createContext<{
setTitle: (title: string) => void; setTitle: (id: string, title: string) => void;
} | null>(null); } | null>(null);

View file

@ -53,6 +53,7 @@ export function SpacedriveRouterProvider(props: {
visible: boolean; visible: boolean;
router: Router; router: Router;
currentIndex: number; currentIndex: number;
tabId: string;
maxIndex: number; maxIndex: number;
}; };
}) { }) {
@ -63,6 +64,7 @@ export function SpacedriveRouterProvider(props: {
routes: props.routing.routes, routes: props.routing.routes,
visible: props.routing.visible, visible: props.routing.visible,
currentIndex: props.routing.currentIndex, currentIndex: props.routing.currentIndex,
tabId: props.routing.tabId,
maxIndex: props.routing.maxIndex maxIndex: props.routing.maxIndex
}} }}
> >