mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
refactor(core): use element atom (#4026)
This commit is contained in:
@@ -5,112 +5,40 @@ import {
|
||||
SidebarSwitch,
|
||||
} from '@affine/component/app-sidebar';
|
||||
import { isDesktop } from '@affine/env/constant';
|
||||
import { useIsTinyScreen } from '@toeverything/hooks/use-is-tiny-screen';
|
||||
import clsx from 'clsx';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import debounce from 'lodash.debounce';
|
||||
import type { MutableRefObject, ReactNode } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { type Atom, useAtomValue } from 'jotai';
|
||||
import type { ReactElement } from 'react';
|
||||
import { forwardRef, useRef } from 'react';
|
||||
|
||||
import * as style from './style.css';
|
||||
import { TopTip } from './top-tip';
|
||||
import { WindowsAppControls } from './windows-app-controls';
|
||||
|
||||
interface HeaderPros {
|
||||
left?: ReactNode;
|
||||
right?: ReactNode;
|
||||
center?: ReactNode;
|
||||
left?: ReactElement;
|
||||
right?: ReactElement;
|
||||
center?: ReactElement;
|
||||
mainContainerAtom: Atom<HTMLDivElement | null>;
|
||||
}
|
||||
|
||||
const useIsTinyScreen = ({
|
||||
mainContainer,
|
||||
leftStatic,
|
||||
leftSlot,
|
||||
centerDom,
|
||||
rightStatic,
|
||||
rightSlot,
|
||||
}: {
|
||||
mainContainer: HTMLElement;
|
||||
leftStatic: MutableRefObject<HTMLElement | null>;
|
||||
leftSlot: MutableRefObject<HTMLElement | null>[];
|
||||
centerDom: MutableRefObject<HTMLElement | null>;
|
||||
rightStatic: MutableRefObject<HTMLElement | null>;
|
||||
rightSlot: MutableRefObject<HTMLElement | null>[];
|
||||
}) => {
|
||||
const [isTinyScreen, setIsTinyScreen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleResize = debounce(() => {
|
||||
if (!centerDom.current) {
|
||||
return;
|
||||
}
|
||||
const leftStaticWidth = leftStatic.current?.clientWidth || 0;
|
||||
const leftSlotWidth = leftSlot.reduce((accWidth, dom) => {
|
||||
return accWidth + (dom.current?.clientWidth || 0);
|
||||
}, 0);
|
||||
|
||||
const rightStaticWidth = rightStatic.current?.clientWidth || 0;
|
||||
|
||||
const rightSlotWidth = rightSlot.reduce((accWidth, dom) => {
|
||||
return accWidth + (dom.current?.clientWidth || 0);
|
||||
}, 0);
|
||||
|
||||
if (!leftSlotWidth && !rightSlotWidth) {
|
||||
if (isTinyScreen) {
|
||||
setIsTinyScreen(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const containerRect = mainContainer.getBoundingClientRect();
|
||||
const centerRect = centerDom.current.getBoundingClientRect();
|
||||
|
||||
if (
|
||||
leftStaticWidth + leftSlotWidth + containerRect.left >=
|
||||
centerRect.left ||
|
||||
containerRect.right - centerRect.right <=
|
||||
rightSlotWidth + rightStaticWidth
|
||||
) {
|
||||
setIsTinyScreen(true);
|
||||
} else {
|
||||
setIsTinyScreen(false);
|
||||
}
|
||||
}, 100);
|
||||
|
||||
handleResize();
|
||||
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
handleResize();
|
||||
});
|
||||
|
||||
resizeObserver.observe(mainContainer);
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect();
|
||||
};
|
||||
}, [
|
||||
centerDom,
|
||||
isTinyScreen,
|
||||
leftSlot,
|
||||
leftStatic,
|
||||
mainContainer,
|
||||
rightSlot,
|
||||
rightStatic,
|
||||
]);
|
||||
|
||||
return isTinyScreen;
|
||||
};
|
||||
|
||||
// The Header component is used to solve the following problems
|
||||
// 1. Manage layout issues independently of page or business logic
|
||||
// 2. Dynamic centered middle element (relative to the main-container), when the middle element is detected to collide with the two elements, the line wrapping process is performed
|
||||
export const Header = ({ left, center, right }: HeaderPros) => {
|
||||
export const Header = forwardRef<HTMLDivElement, HeaderPros>(function Header(
|
||||
{ left, center, right, mainContainerAtom },
|
||||
ref
|
||||
) {
|
||||
const sidebarSwitchRef = useRef<HTMLDivElement | null>(null);
|
||||
const leftSlotRef = useRef<HTMLDivElement | null>(null);
|
||||
const centerSlotRef = useRef<HTMLDivElement | null>(null);
|
||||
const rightSlotRef = useRef<HTMLDivElement | null>(null);
|
||||
const windowControlsRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const mainContainer = useAtomValue(mainContainerAtom);
|
||||
|
||||
const isTinyScreen = useIsTinyScreen({
|
||||
mainContainer: document.querySelector('.main-container') || document.body,
|
||||
mainContainer,
|
||||
leftStatic: sidebarSwitchRef,
|
||||
leftSlot: [leftSlotRef],
|
||||
centerDom: centerSlotRef,
|
||||
@@ -130,6 +58,7 @@ export const Header = ({ left, center, right }: HeaderPros) => {
|
||||
data-open={open}
|
||||
data-sidebar-floating={appSidebarFloating}
|
||||
data-testid="header"
|
||||
ref={ref}
|
||||
>
|
||||
<div
|
||||
className={clsx(style.headerSideContainer, {
|
||||
@@ -175,4 +104,6 @@ export const Header = ({ left, center, right }: HeaderPros) => {
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
Header.displayName = 'Header';
|
||||
|
||||
Reference in New Issue
Block a user