fix: using width atom for syncing app headers position (#7666)
may use global state to replace these sidebar state atoms fix AF-1109
This commit is contained in:
@@ -31,15 +31,3 @@ export const desktopTabsHeader = style({
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const desktopTabsHeaderTopLeft = style({
|
|
||||||
display: 'flex',
|
|
||||||
flexFlow: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
transition: 'width 0.3s, padding 0.3s',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
marginRight: -8, // make room for tab's padding
|
|
||||||
padding: '0 16px',
|
|
||||||
flexShrink: 0,
|
|
||||||
['WebkitAppRegion' as string]: 'drag',
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -35,12 +35,9 @@ import { WorkspaceAIOnboarding } from '../components/affine/ai-onboarding';
|
|||||||
import { AppContainer } from '../components/affine/app-container';
|
import { AppContainer } from '../components/affine/app-container';
|
||||||
import { SyncAwareness } from '../components/affine/awareness';
|
import { SyncAwareness } from '../components/affine/awareness';
|
||||||
import {
|
import {
|
||||||
appSidebarFloatingAtom,
|
|
||||||
appSidebarOpenAtom,
|
|
||||||
appSidebarResizingAtom,
|
appSidebarResizingAtom,
|
||||||
SidebarSwitch,
|
SidebarSwitch,
|
||||||
} from '../components/app-sidebar';
|
} from '../components/app-sidebar';
|
||||||
import { appSidebarWidthAtom } from '../components/app-sidebar/index.jotai';
|
|
||||||
import { AIIsland } from '../components/pure/ai-island';
|
import { AIIsland } from '../components/pure/ai-island';
|
||||||
import { RootAppSidebar } from '../components/root-app-sidebar';
|
import { RootAppSidebar } from '../components/root-app-sidebar';
|
||||||
import { MainContainer } from '../components/workspace';
|
import { MainContainer } from '../components/workspace';
|
||||||
@@ -181,29 +178,17 @@ const WorkspaceLayoutProviders = ({ children }: PropsWithChildren) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const DesktopLayout = ({ children }: PropsWithChildren) => {
|
const DesktopLayout = ({ children }: PropsWithChildren) => {
|
||||||
const resizing = useAtomValue(appSidebarResizingAtom);
|
|
||||||
const sidebarWidth = useAtomValue(appSidebarWidthAtom);
|
|
||||||
const sidebarOpen = useAtomValue(appSidebarOpenAtom);
|
|
||||||
const sidebarFloating = useAtomValue(appSidebarFloatingAtom);
|
|
||||||
const sidebarResizing = useAtomValue(appSidebarResizingAtom);
|
|
||||||
const isMacosDesktop = environment.isDesktop && environment.isMacOs;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.desktopAppViewContainer}>
|
<div className={styles.desktopAppViewContainer}>
|
||||||
<div className={styles.desktopTabsHeader}>
|
<div className={styles.desktopTabsHeader}>
|
||||||
<div
|
<AppTabsHeader
|
||||||
className={styles.desktopTabsHeaderTopLeft}
|
left={
|
||||||
style={{
|
<>
|
||||||
transition: sidebarResizing ? 'none' : undefined,
|
|
||||||
paddingLeft:
|
|
||||||
isMacosDesktop && sidebarOpen && !sidebarFloating ? 90 : 16,
|
|
||||||
width: sidebarOpen && !sidebarFloating ? sidebarWidth : 130,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SidebarSwitch show />
|
<SidebarSwitch show />
|
||||||
<NavigationButtons />
|
<NavigationButtons />
|
||||||
</div>
|
</>
|
||||||
<AppTabsHeader reportBoundingUpdate={!resizing} />
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.desktopAppViewMain}>
|
<div className={styles.desktopAppViewMain}>
|
||||||
<RootAppSidebar />
|
<RootAppSidebar />
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
import { IconButton, Loading, observeResize } from '@affine/component';
|
import { IconButton, Loading } from '@affine/component';
|
||||||
|
import {
|
||||||
|
appSidebarFloatingAtom,
|
||||||
|
appSidebarOpenAtom,
|
||||||
|
appSidebarResizingAtom,
|
||||||
|
} from '@affine/core/components/app-sidebar';
|
||||||
|
import { appSidebarWidthAtom } from '@affine/core/components/app-sidebar/index.jotai';
|
||||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||||
import { DesktopStateSynchronizer } from '@affine/core/modules/workbench/services/desktop-state-synchronizer';
|
import { DesktopStateSynchronizer } from '@affine/core/modules/workbench/services/desktop-state-synchronizer';
|
||||||
import type { WorkbenchMeta } from '@affine/electron-api';
|
import type { WorkbenchMeta } from '@affine/electron-api';
|
||||||
import { apis } from '@affine/electron-api';
|
import { apis, events } from '@affine/electron-api';
|
||||||
import {
|
import {
|
||||||
|
AllDocsIcon,
|
||||||
CloseIcon,
|
CloseIcon,
|
||||||
DeleteIcon,
|
DeleteIcon,
|
||||||
EdgelessIcon,
|
EdgelessIcon,
|
||||||
FolderIcon,
|
|
||||||
PageIcon,
|
PageIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
RightSidebarIcon,
|
RightSidebarIcon,
|
||||||
@@ -21,13 +27,15 @@ import {
|
|||||||
useService,
|
useService,
|
||||||
useServiceOptional,
|
useServiceOptional,
|
||||||
} from '@toeverything/infra';
|
} from '@toeverything/infra';
|
||||||
import { debounce, partition } from 'lodash-es';
|
import clsx from 'clsx';
|
||||||
|
import { useAtomValue } from 'jotai';
|
||||||
|
import { partition } from 'lodash-es';
|
||||||
import {
|
import {
|
||||||
Fragment,
|
Fragment,
|
||||||
type MouseEventHandler,
|
type MouseEventHandler,
|
||||||
type ReactNode,
|
type ReactNode,
|
||||||
useEffect,
|
useEffect,
|
||||||
useRef,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -39,7 +47,7 @@ import * as styles from './styles.css';
|
|||||||
type ModuleName = NonNullable<WorkbenchMeta['views'][0]['moduleName']>;
|
type ModuleName = NonNullable<WorkbenchMeta['views'][0]['moduleName']>;
|
||||||
|
|
||||||
const moduleNameToIcon = {
|
const moduleNameToIcon = {
|
||||||
all: <FolderIcon />,
|
all: <AllDocsIcon />,
|
||||||
collection: <ViewLayersIcon />,
|
collection: <ViewLayersIcon />,
|
||||||
doc: <PageIcon />,
|
doc: <PageIcon />,
|
||||||
page: <PageIcon />,
|
page: <PageIcon />,
|
||||||
@@ -140,13 +148,39 @@ const WorkbenchTab = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useIsFullScreen = () => {
|
||||||
|
const [fullScreen, setFullScreen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
apis?.ui
|
||||||
|
.isFullScreen()
|
||||||
|
.then(setFullScreen)
|
||||||
|
.then(() => {
|
||||||
|
events?.ui.onFullScreen(setFullScreen);
|
||||||
|
})
|
||||||
|
.catch(console.error);
|
||||||
|
}, []);
|
||||||
|
return fullScreen;
|
||||||
|
};
|
||||||
|
|
||||||
export const AppTabsHeader = ({
|
export const AppTabsHeader = ({
|
||||||
style,
|
style,
|
||||||
reportBoundingUpdate,
|
mode = 'app',
|
||||||
|
className,
|
||||||
|
left,
|
||||||
}: {
|
}: {
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
reportBoundingUpdate?: boolean;
|
mode?: 'app' | 'shell';
|
||||||
|
className?: string;
|
||||||
|
left?: ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
|
const sidebarWidth = useAtomValue(appSidebarWidthAtom);
|
||||||
|
const sidebarOpen = useAtomValue(appSidebarOpenAtom);
|
||||||
|
const sidebarFloating = useAtomValue(appSidebarFloatingAtom);
|
||||||
|
const sidebarResizing = useAtomValue(appSidebarResizingAtom);
|
||||||
|
const isMacosDesktop = environment.isDesktop && environment.isMacOs;
|
||||||
|
const fullScreen = useIsFullScreen();
|
||||||
|
|
||||||
const tabsHeaderService = useService(AppTabsHeaderService);
|
const tabsHeaderService = useService(AppTabsHeaderService);
|
||||||
const tabs = useLiveData(tabsHeaderService.tabsStatus$);
|
const tabs = useLiveData(tabsHeaderService.tabsStatus$);
|
||||||
|
|
||||||
@@ -160,42 +194,36 @@ export const AppTabsHeader = ({
|
|||||||
await tabsHeaderService.onToggleRightSidebar();
|
await tabsHeaderService.onToggleRightSidebar();
|
||||||
}, [tabsHeaderService]);
|
}, [tabsHeaderService]);
|
||||||
|
|
||||||
const ref = useRef<HTMLDivElement | null>(null);
|
|
||||||
|
|
||||||
useServiceOptional(DesktopStateSynchronizer);
|
useServiceOptional(DesktopStateSynchronizer);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ref.current && reportBoundingUpdate) {
|
if (mode === 'app') {
|
||||||
return observeResize(
|
apis?.ui.pingAppLayoutReady().catch(console.error);
|
||||||
ref.current,
|
|
||||||
debounce(() => {
|
|
||||||
if (document.visibilityState === 'visible') {
|
|
||||||
const rect = ref.current?.getBoundingClientRect();
|
|
||||||
if (!rect) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
const toInt = (value: number) => Math.round(value);
|
}, [mode]);
|
||||||
const boundRect = {
|
|
||||||
height: toInt(rect.height),
|
|
||||||
width: toInt(rect.width),
|
|
||||||
x: toInt(rect.x),
|
|
||||||
y: toInt(rect.y),
|
|
||||||
};
|
|
||||||
apis?.ui.updateTabsBoundingRect(boundRect).catch(console.error);
|
|
||||||
}
|
|
||||||
}, 50)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}, [reportBoundingUpdate]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={styles.root}
|
className={clsx(styles.root, className)}
|
||||||
ref={ref}
|
|
||||||
style={style}
|
style={style}
|
||||||
|
data-mode={mode}
|
||||||
data-is-windows={environment.isDesktop && environment.isWindows}
|
data-is-windows={environment.isDesktop && environment.isWindows}
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
transition: sidebarResizing ? 'none' : undefined,
|
||||||
|
paddingLeft:
|
||||||
|
isMacosDesktop && sidebarOpen && !sidebarFloating && !fullScreen
|
||||||
|
? 90
|
||||||
|
: 16,
|
||||||
|
width: sidebarOpen && !sidebarFloating ? sidebarWidth : 130,
|
||||||
|
// minus 16 to account for the padding on the right side of the header (for box shadow)
|
||||||
|
marginRight: sidebarOpen && !sidebarFloating ? -16 : 0,
|
||||||
|
}}
|
||||||
|
className={styles.headerLeft}
|
||||||
|
>
|
||||||
|
{left}
|
||||||
|
</div>
|
||||||
<div className={styles.tabs}>
|
<div className={styles.tabs}>
|
||||||
{pinned.map(tab => {
|
{pinned.map(tab => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -18,6 +18,20 @@ export const root = style({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const headerLeft = style({
|
||||||
|
display: 'flex',
|
||||||
|
flexFlow: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
padding: '0 16px',
|
||||||
|
flexShrink: 0,
|
||||||
|
selectors: {
|
||||||
|
[`${root}[data-mode="app"] &`]: {
|
||||||
|
transition: 'width 0.3s, padding 0.3s',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export const tabs = style({
|
export const tabs = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ export const PageNotFound = ({
|
|||||||
style={{
|
style={{
|
||||||
paddingLeft: environment.isMacOs ? 80 : 0,
|
paddingLeft: environment.isMacOs ? 80 : 0,
|
||||||
}}
|
}}
|
||||||
reportBoundingUpdate
|
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{noPermission ? (
|
{noPermission ? (
|
||||||
|
|||||||
@@ -153,7 +153,6 @@ export const Component = () => {
|
|||||||
style={{
|
style={{
|
||||||
paddingLeft: environment.isMacOs ? 80 : 0,
|
paddingLeft: environment.isMacOs ? 80 : 0,
|
||||||
}}
|
}}
|
||||||
reportBoundingUpdate
|
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import 'setimmediate';
|
import 'setimmediate';
|
||||||
import '@affine/component/theme/global.css';
|
import '@affine/component/theme/global.css';
|
||||||
import '@affine/component/theme/theme.css';
|
import '@affine/component/theme/theme.css';
|
||||||
|
import '@affine/core/bootstrap/preload';
|
||||||
|
|
||||||
import { ThemeProvider } from '@affine/component/theme-provider';
|
import { ThemeProvider } from '@affine/component/theme-provider';
|
||||||
import { appConfigProxy } from '@affine/core/hooks/use-app-config-storage';
|
|
||||||
import { configureAppTabsHeaderModule } from '@affine/core/modules/app-tabs-header';
|
import { configureAppTabsHeaderModule } from '@affine/core/modules/app-tabs-header';
|
||||||
import { configureElectronStateStorageImpls } from '@affine/core/modules/storage';
|
import { configureElectronStateStorageImpls } from '@affine/core/modules/storage';
|
||||||
import { performanceLogger } from '@affine/core/shared';
|
import { performanceLogger } from '@affine/core/shared';
|
||||||
|
import { apis, events } from '@affine/electron-api';
|
||||||
import {
|
import {
|
||||||
configureGlobalStorageModule,
|
configureGlobalStorageModule,
|
||||||
Framework,
|
Framework,
|
||||||
@@ -26,9 +27,17 @@ const frameworkProvider = framework.provider();
|
|||||||
const logger = performanceLogger.namespace('shell');
|
const logger = performanceLogger.namespace('shell');
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
appConfigProxy
|
const handleMaximized = (maximized: boolean | undefined) => {
|
||||||
.getSync()
|
document.documentElement.dataset.maximized = String(maximized);
|
||||||
.catch(() => console.error('failed to load app config'));
|
};
|
||||||
|
const handleFullscreen = (fullscreen: boolean | undefined) => {
|
||||||
|
document.documentElement.dataset.fullscreen = String(fullscreen);
|
||||||
|
};
|
||||||
|
|
||||||
|
apis?.ui.isMaximized().then(handleMaximized).catch(console.error);
|
||||||
|
apis?.ui.isFullScreen().then(handleFullscreen).catch(console.error);
|
||||||
|
events?.ui.onMaximized(handleMaximized);
|
||||||
|
events?.ui.onFullScreen(handleFullscreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mountApp() {
|
function mountApp() {
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { cssVar } from '@toeverything/theme';
|
import { cssVar } from '@toeverything/theme';
|
||||||
import { globalStyle, style } from '@vanilla-extract/css';
|
import { createVar, globalStyle, style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
|
export const sidebarOffsetVar = createVar();
|
||||||
|
|
||||||
export const root = style({
|
export const root = style({
|
||||||
width: '100vw',
|
width: '100vw',
|
||||||
height: '100vh',
|
height: '100vh',
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
|
display: 'flex',
|
||||||
transition: 'opacity 0.1s',
|
transition: 'opacity 0.1s',
|
||||||
background: cssVar('backgroundPrimaryColor'),
|
background: cssVar('backgroundPrimaryColor'),
|
||||||
selectors: {
|
selectors: {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
|
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
|
||||||
import { AppTabsHeader } from '@affine/core/modules/app-tabs-header';
|
import { AppTabsHeader } from '@affine/core/modules/app-tabs-header';
|
||||||
import { apis, events } from '@affine/electron-api';
|
import { events } from '@affine/electron-api';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import * as styles from './shell.css';
|
import * as styles from './shell.css';
|
||||||
|
|
||||||
const useIsShellActive = () => {
|
const useIsShellActive = () => {
|
||||||
const [active, setActive] = useState(true);
|
const [active, setActive] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsub = events?.ui.onTabShellViewActiveChange(active => {
|
const unsub = events?.ui.onTabShellViewActiveChange(active => {
|
||||||
@@ -20,48 +20,9 @@ const useIsShellActive = () => {
|
|||||||
return active;
|
return active;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useTabsBoundingRect = () => {
|
|
||||||
const [rect, setRect] = useState<{
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
}>({
|
|
||||||
x: environment.isDesktop && environment.isMacOs ? 80 : 0,
|
|
||||||
y: 0,
|
|
||||||
width: window.innerWidth,
|
|
||||||
height: 52,
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let unsub: (() => void) | undefined;
|
|
||||||
apis?.ui
|
|
||||||
.getTabsBoundingRect()
|
|
||||||
.then(rect => {
|
|
||||||
if (rect) {
|
|
||||||
setRect(rect);
|
|
||||||
}
|
|
||||||
unsub = events?.ui.onTabsBoundingRectChanged(rect => {
|
|
||||||
if (rect) {
|
|
||||||
setRect(rect);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
return () => {
|
|
||||||
unsub?.();
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return rect;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function ShellRoot() {
|
export function ShellRoot() {
|
||||||
const active = useIsShellActive();
|
const active = useIsShellActive();
|
||||||
const { appSettings } = useAppSettingHelper();
|
const { appSettings } = useAppSettingHelper();
|
||||||
const rect = useTabsBoundingRect();
|
|
||||||
const translucent =
|
const translucent =
|
||||||
environment.isDesktop &&
|
environment.isDesktop &&
|
||||||
environment.isMacOs &&
|
environment.isMacOs &&
|
||||||
@@ -72,15 +33,7 @@ export function ShellRoot() {
|
|||||||
data-translucent={translucent}
|
data-translucent={translucent}
|
||||||
data-active={active}
|
data-active={active}
|
||||||
>
|
>
|
||||||
<AppTabsHeader
|
<AppTabsHeader mode="shell" />
|
||||||
style={{
|
|
||||||
position: 'fixed',
|
|
||||||
top: rect.y,
|
|
||||||
left: rect.x,
|
|
||||||
width: rect.width,
|
|
||||||
height: rect.height,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import type { MainEventRegister } from '../type';
|
|||||||
import {
|
import {
|
||||||
onActiveTabChanged,
|
onActiveTabChanged,
|
||||||
onTabAction,
|
onTabAction,
|
||||||
onTabsBoundingRectChanged,
|
|
||||||
onTabShellViewActiveChange,
|
onTabShellViewActiveChange,
|
||||||
onTabsStatusChange,
|
onTabsStatusChange,
|
||||||
onTabViewsMetaChanged,
|
onTabViewsMetaChanged,
|
||||||
@@ -36,5 +35,4 @@ export const uiEvents = {
|
|||||||
onTabsStatusChange,
|
onTabsStatusChange,
|
||||||
onActiveTabChanged,
|
onActiveTabChanged,
|
||||||
onTabShellViewActiveChange,
|
onTabShellViewActiveChange,
|
||||||
onTabsBoundingRectChanged,
|
|
||||||
} satisfies Record<string, MainEventRegister>;
|
} satisfies Record<string, MainEventRegister>;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
closeTab,
|
closeTab,
|
||||||
getMainWindow,
|
getMainWindow,
|
||||||
getOnboardingWindow,
|
getOnboardingWindow,
|
||||||
getTabsBoundingRect,
|
|
||||||
getTabsStatus,
|
getTabsStatus,
|
||||||
getTabViewsMeta,
|
getTabViewsMeta,
|
||||||
getWorkbenchMeta,
|
getWorkbenchMeta,
|
||||||
@@ -19,10 +18,10 @@ import {
|
|||||||
initAndShowMainWindow,
|
initAndShowMainWindow,
|
||||||
isActiveTab,
|
isActiveTab,
|
||||||
launchStage,
|
launchStage,
|
||||||
|
pingAppLayoutReady,
|
||||||
showDevTools,
|
showDevTools,
|
||||||
showTab,
|
showTab,
|
||||||
showTabContextMenu,
|
showTabContextMenu,
|
||||||
updateTabsBoundingRect,
|
|
||||||
updateWorkbenchMeta,
|
updateWorkbenchMeta,
|
||||||
} from '../windows-manager';
|
} from '../windows-manager';
|
||||||
import { getChallengeResponse } from './challenge';
|
import { getChallengeResponse } from './challenge';
|
||||||
@@ -193,14 +192,8 @@ export const uiHandlers = {
|
|||||||
uiSubjects.onToggleRightSidebar$.next(tabId);
|
uiSubjects.onToggleRightSidebar$.next(tabId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getTabsBoundingRect: async () => {
|
pingAppLayoutReady: async e => {
|
||||||
return getTabsBoundingRect();
|
pingAppLayoutReady(e.sender);
|
||||||
},
|
|
||||||
updateTabsBoundingRect: async (
|
|
||||||
e,
|
|
||||||
rect: { x: number; y: number; width: number; height: number }
|
|
||||||
) => {
|
|
||||||
return updateTabsBoundingRect(e.sender, rect);
|
|
||||||
},
|
},
|
||||||
showDevTools: async (_, ...args: Parameters<typeof showDevTools>) => {
|
showDevTools: async (_, ...args: Parameters<typeof showDevTools>) => {
|
||||||
return showDevTools(...args);
|
return showDevTools(...args);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
type CookiesSetDetails,
|
type CookiesSetDetails,
|
||||||
globalShortcut,
|
globalShortcut,
|
||||||
Menu,
|
Menu,
|
||||||
type Rectangle,
|
|
||||||
type View,
|
type View,
|
||||||
type WebContents,
|
type WebContents,
|
||||||
WebContentsView,
|
WebContentsView,
|
||||||
@@ -130,7 +129,6 @@ export class WebContentViewsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
readonly tabViewsMeta$ = TabViewsMetaState.$;
|
readonly tabViewsMeta$ = TabViewsMetaState.$;
|
||||||
readonly tabsBoundingRect$ = new BehaviorSubject<Rectangle | null>(null);
|
|
||||||
readonly appTabsUIReady$ = new BehaviorSubject(new Set<string>());
|
readonly appTabsUIReady$ = new BehaviorSubject(new Set<string>());
|
||||||
|
|
||||||
// all web views
|
// all web views
|
||||||
@@ -202,14 +200,6 @@ export class WebContentViewsManager {
|
|||||||
TabViewsMetaState.patch(patch);
|
TabViewsMetaState.patch(patch);
|
||||||
};
|
};
|
||||||
|
|
||||||
get tabsBoundingRect() {
|
|
||||||
return this.tabsBoundingRect$.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
set tabsBoundingRect(rect: Rectangle | null) {
|
|
||||||
this.tabsBoundingRect$.next(rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
get shellView() {
|
get shellView() {
|
||||||
return this.webViewsMap$.value.get('shell');
|
return this.webViewsMap$.value.get('shell');
|
||||||
}
|
}
|
||||||
@@ -584,14 +574,6 @@ export class WebContentViewsManager {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
disposables.push(
|
|
||||||
this.tabsBoundingRect$.subscribe(rect => {
|
|
||||||
if (rect) {
|
|
||||||
this.reorderViews();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
app.on('ready', () => {
|
app.on('ready', () => {
|
||||||
// bind CMD/CTRL+1~8 to switch tabs
|
// bind CMD/CTRL+1~8 to switch tabs
|
||||||
// bind CMD/CTRL+9 to switch to the last tab
|
// bind CMD/CTRL+9 to switch to the last tab
|
||||||
@@ -745,6 +727,11 @@ export class WebContentViewsManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.resizeView(view);
|
this.resizeView(view);
|
||||||
|
|
||||||
|
view.webContents.on('did-finish-load', () => {
|
||||||
|
this.resizeView(view);
|
||||||
|
});
|
||||||
|
|
||||||
// reorder will add to main window when loaded
|
// reorder will add to main window when loaded
|
||||||
this.reorderViews();
|
this.reorderViews();
|
||||||
|
|
||||||
@@ -887,33 +874,13 @@ export const showDevTools = (id?: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const onTabsBoundingRectChanged = (
|
export const pingAppLayoutReady = (wc: WebContents) => {
|
||||||
fn: (rect: Rectangle | null) => void
|
|
||||||
) => {
|
|
||||||
const sub = WebContentViewsManager.instance.tabsBoundingRect$.subscribe(fn);
|
|
||||||
return () => {
|
|
||||||
sub.unsubscribe();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getTabsBoundingRect = () => {
|
|
||||||
return WebContentViewsManager.instance.tabsBoundingRect;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateTabsBoundingRect = (wc: WebContents, rect: Rectangle) => {
|
|
||||||
try {
|
|
||||||
if (isActiveTab(wc)) {
|
|
||||||
WebContentViewsManager.instance.tabsBoundingRect = rect;
|
|
||||||
}
|
|
||||||
const viewId = WebContentViewsManager.instance.getViewIdFromWebContentsId(
|
const viewId = WebContentViewsManager.instance.getViewIdFromWebContentsId(
|
||||||
wc.id
|
wc.id
|
||||||
);
|
);
|
||||||
if (viewId) {
|
if (viewId) {
|
||||||
WebContentViewsManager.instance.setTabUIReady(viewId);
|
WebContentViewsManager.instance.setTabUIReady(viewId);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
logger.error(err);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const showTabContextMenu = async (tabId: string, viewIndex: number) => {
|
export const showTabContextMenu = async (tabId: string, viewIndex: number) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user