mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
feat: optimize resizing performance
This commit is contained in:
parent
f88d7c0575
commit
da930bc35f
4 changed files with 62 additions and 32 deletions
|
|
@ -126,6 +126,7 @@ export function SideBar() {
|
|||
})}
|
||||
baseSize={baseSize}
|
||||
onLeave={sidebarToggleMode === 'float' ? () => setShowSideBar(false) : undefined}
|
||||
sizeVariableMountPoint={sidebarToggleMode === 'persistent' ? document.body : undefined}
|
||||
>
|
||||
<div className={'gitako-side-bar-body'}>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -4,25 +4,32 @@ import * as React from 'react'
|
|||
import { useDebounce, useWindowSize } from 'react-use'
|
||||
import { defaultConfigs } from 'utils/config/helper'
|
||||
import { cx } from 'utils/cx'
|
||||
import { setResizingState } from 'utils/DOMHelper'
|
||||
import { setCSSVariable } from 'utils/DOMHelper'
|
||||
import * as features from 'utils/features'
|
||||
import { useCSSVariable } from 'utils/hooks/useCSSVariable'
|
||||
|
||||
export type Size = number
|
||||
type Props = {
|
||||
baseSize: Size
|
||||
className?: string
|
||||
onLeave?: React.HTMLAttributes<HTMLElement>['onMouseLeave']
|
||||
sizeVariableMountPoint?: HTMLElement
|
||||
}
|
||||
|
||||
const MINIMAL_CONTENT_VIEWPORT_WIDTH = 100
|
||||
const MINIMAL_WIDTH = 240
|
||||
|
||||
function getSafeSize(size: number, width: number) {
|
||||
if (size > width - MINIMAL_CONTENT_VIEWPORT_WIDTH) return width - MINIMAL_CONTENT_VIEWPORT_WIDTH
|
||||
if (size < MINIMAL_WIDTH) return MINIMAL_WIDTH
|
||||
return size
|
||||
}
|
||||
|
||||
export function SideBarBodyWrapper({
|
||||
baseSize,
|
||||
className,
|
||||
children,
|
||||
onLeave,
|
||||
sizeVariableMountPoint,
|
||||
}: React.PropsWithChildren<Props>) {
|
||||
const [size, setSize] = React.useState(baseSize)
|
||||
const configContext = useConfigs()
|
||||
|
|
@ -34,27 +41,50 @@ export function SideBarBodyWrapper({
|
|||
|
||||
const { width } = useWindowSize()
|
||||
React.useEffect(() => {
|
||||
if (size > width - MINIMAL_CONTENT_VIEWPORT_WIDTH)
|
||||
setSize(width - MINIMAL_CONTENT_VIEWPORT_WIDTH)
|
||||
else if (size < MINIMAL_WIDTH) setSize(MINIMAL_WIDTH)
|
||||
const safeSize = getSafeSize(size, width)
|
||||
if (safeSize !== size) setSize(safeSize)
|
||||
}, [width, size])
|
||||
|
||||
React.useEffect(() => {
|
||||
setResizingState(true)
|
||||
const timer = setTimeout(() => setResizingState(false), 100)
|
||||
return () => clearTimeout(timer)
|
||||
}, [width, size])
|
||||
|
||||
useCSSVariable('--gitako-width', `${size}px`)
|
||||
const bodyWrapperRef = React.useRef<HTMLDivElement | null>(null)
|
||||
useDebounce(() => configContext.onChange({ sideBarWidth: size }), 100, [size])
|
||||
|
||||
const onResize = React.useCallback((size: number) => {
|
||||
// do NOT merge this with the above similar effect, side bar will jump otherwise
|
||||
if (size > width - MINIMAL_CONTENT_VIEWPORT_WIDTH)
|
||||
setSize(width - MINIMAL_CONTENT_VIEWPORT_WIDTH)
|
||||
else if (size < MINIMAL_WIDTH) setSize(MINIMAL_WIDTH)
|
||||
else setSize(size)
|
||||
}, [])
|
||||
function apply(sizeVariableMountPoint: HTMLElement | undefined, size: number) {
|
||||
if (sizeVariableMountPoint)
|
||||
setCSSVariable(
|
||||
'--gitako-width',
|
||||
sizeVariableMountPoint ? `${size}px` : undefined,
|
||||
sizeVariableMountPoint,
|
||||
)
|
||||
|
||||
if (bodyWrapperRef.current)
|
||||
setCSSVariable(
|
||||
'--gitako-width',
|
||||
sizeVariableMountPoint ? undefined : `${size}px`,
|
||||
bodyWrapperRef.current,
|
||||
)
|
||||
}
|
||||
|
||||
// Update size using useEffect would cause delay
|
||||
const onResize = React.useMemo(() => {
|
||||
let sizeToApply: number,
|
||||
applied = true
|
||||
return (size: number) => {
|
||||
// do NOT merge this with the above similar effect, side bar will jump otherwise
|
||||
sizeToApply = getSafeSize(size, width)
|
||||
setSize(sizeToApply)
|
||||
|
||||
if (applied) {
|
||||
applied = false
|
||||
requestAnimationFrame(() => {
|
||||
applied = true
|
||||
apply(sizeVariableMountPoint, sizeToApply)
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [width, sizeVariableMountPoint])
|
||||
|
||||
React.useEffect(() => {
|
||||
apply(sizeVariableMountPoint, size)
|
||||
}, [sizeVariableMountPoint])
|
||||
|
||||
const onMouseLeave = React.useCallback(
|
||||
e => {
|
||||
|
|
@ -65,7 +95,11 @@ export function SideBarBodyWrapper({
|
|||
)
|
||||
|
||||
return (
|
||||
<div className={cx('gitako-side-bar-body-wrapper', className)} onMouseLeave={onMouseLeave}>
|
||||
<div
|
||||
ref={bodyWrapperRef}
|
||||
className={cx('gitako-side-bar-body-wrapper', className)}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
<div className={'gitako-side-bar-body-wrapper-content'}>{children}</div>
|
||||
{features.resize && (
|
||||
<HorizontalResizeHandler
|
||||
|
|
|
|||
|
|
@ -81,9 +81,6 @@ $minimal-z-index: max($github-header-z-index, $github-pull-request-float-header-
|
|||
}
|
||||
}
|
||||
|
||||
:root {
|
||||
--gitako-width: #{$side-bar-base-width};
|
||||
}
|
||||
|
||||
.#{$name}-ready {
|
||||
// github
|
||||
|
|
|
|||
|
|
@ -123,15 +123,13 @@ export function focusSearchInput() {
|
|||
})
|
||||
}
|
||||
|
||||
export function setResizingState(on: boolean) {
|
||||
const target = document.querySelector('.gitako-toggle-show-button-wrapper')
|
||||
if (!target) return
|
||||
if (on) target.classList.add('resizing')
|
||||
else target.classList.remove('resizing')
|
||||
}
|
||||
|
||||
export function findNodeElement(node:TreeNode, rootElement: HTMLElement): HTMLElement | null {
|
||||
export function findNodeElement(node: TreeNode, rootElement: HTMLElement): HTMLElement | null {
|
||||
const nodeElement = rootElement.querySelector(`a[href="${node.url}"]`)
|
||||
if (nodeElement instanceof HTMLElement) return nodeElement
|
||||
return null
|
||||
}
|
||||
|
||||
export function setCSSVariable(name: string, value: string | undefined, element: HTMLElement) {
|
||||
if (value === undefined) element.style.removeProperty(name)
|
||||
else element.style.setProperty(name, value)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue