feat: toggle expand on hover&leave

This commit is contained in:
EnixCoda 2021-05-24 23:00:24 +08:00
parent 87f40565f0
commit 968a5a46f3
No known key found for this signature in database
GPG key ID: 0C1A07377913A1DD
5 changed files with 56 additions and 18 deletions

View file

@ -5,10 +5,13 @@ import { Size } from './SideBarBodyWrapper'
type Props = {
size: Size
onResize(size: Size): void
onResizeStateChange?(state: ResizeState): void
style?: React.CSSProperties
}
export function HorizontalResizeHandler({ onResize, size, style }: Props) {
type ResizeState = 'idle' | 'resizing'
export function HorizontalResizeHandler({ onResize, onResizeStateChange, size, style }: Props) {
const pointerDown = React.useRef(false)
const startX = React.useRef(0)
const baseSize = React.useRef(size)
@ -22,6 +25,7 @@ export function HorizontalResizeHandler({ onResize, size, style }: Props) {
startX.current = clientX
pointerDown.current = true
baseSize.current = latestPropSize.current
onResizeStateChange?.('resizing')
}, [])
React.useEffect(() => {
@ -39,6 +43,7 @@ export function HorizontalResizeHandler({ onResize, size, style }: Props) {
if (pointerDown.current) {
pointerDown.current = false
baseSize.current = latestPropSize.current
onResizeStateChange?.('idle')
}
}
window.addEventListener('mouseup', onPointerUp)

View file

@ -104,13 +104,21 @@ export function SideBar() {
<Theme>
<div className={'gitako-side-bar'}>
<Portal into={$logoContainerElement.value}>
{!shouldShow && <ToggleShowButton error={error} onClick={toggleShowSideBar} />}
<ToggleShowButton
error={error}
className={cx({
hidden: shouldShow,
})}
onHover={sidebarToggleMode === 'float' ? () => $shouldShow.onChange(true) : undefined}
onClick={toggleShowSideBar}
/>
</Portal>
<SideBarBodyWrapper
className={cx(`toggle-mode-${sidebarToggleMode}`, {
collapsed: error || !shouldShow,
})}
baseSize={baseSize}
onLeave={() => $shouldShow.onChange(false)}
>
<div className={'gitako-side-bar-body'}>
<div className={'close-side-bar-button-position'}>

View file

@ -11,6 +11,7 @@ export type Size = number
type Props = {
baseSize: Size
className?: string
onLeave?: React.HTMLAttributes<HTMLElement>['onMouseLeave']
}
const MINIMAL_CONTENT_VIEWPORT_WIDTH = 100
@ -20,9 +21,11 @@ export function SideBarBodyWrapper({
baseSize,
className,
children,
onLeave,
}: React.PropsWithChildren<Props>) {
const [size, setSize] = React.useState(baseSize)
const configContext = useConfigs()
const blockLeaveRef = React.useRef(false)
React.useEffect(() => {
setSize(baseSize)
@ -51,10 +54,27 @@ export function SideBarBodyWrapper({
else if (size < MINIMAL_WIDTH) setSize(MINIMAL_WIDTH)
else setSize(size)
}, [])
const onMouseLeave = React.useCallback(
e => {
if (blockLeaveRef.current) return
onLeave?.(e)
},
[onLeave],
)
return (
<div className={cx('gitako-side-bar-body-wrapper', className)}>
<div className={cx('gitako-side-bar-body-wrapper', className)} onMouseLeave={onMouseLeave}>
<div className={'gitako-side-bar-body-wrapper-content'}>{children}</div>
{features.resize && <HorizontalResizeHandler onResize={onResize} size={size} />}
{features.resize && (
<HorizontalResizeHandler
onResize={onResize}
onResizeStateChange={state => {
blockLeaveRef.current = state === 'resizing'
}}
size={size}
/>
)}
</div>
)
}

View file

@ -7,9 +7,11 @@ import { Icon } from './Icon'
type Props = {
error?: string | null
className?: React.HTMLAttributes<HTMLButtonElement>['className']
onHover?: React.HTMLAttributes<HTMLButtonElement>['onMouseEnter']
} & Pick<React.HTMLAttributes<HTMLButtonElement>, 'onClick'>
export function ToggleShowButton({ error, onClick }: Props) {
export function ToggleShowButton({ error, className, onClick, onHover }: Props) {
const ref = React.useRef<HTMLDivElement>(null)
const config = useConfigs()
const [distance, setDistance] = React.useState(config.value.toggleButtonVerticalDistance)
@ -36,12 +38,13 @@ export function ToggleShowButton({ error, onClick }: Props) {
const toggleIconMode = config.value.toggleButtonContent
return (
<div ref={ref} className={'gitako-toggle-show-button-wrapper'}>
<div ref={ref} className={cx('gitako-toggle-show-button-wrapper', className)}>
<button
className={cx('gitako-toggle-show-button', {
error,
})}
onClick={onClick}
onMouseEnter={onHover}
draggable
onDragStart={event => {
hideDragPreview(event)

View file

@ -182,12 +182,19 @@ $minimal-z-index: max($github-header-z-index, $github-pull-request-float-header-
left: 0px;
display: inline-flex;
align-items: center;
transition: left 0.25s linear;
&.hidden {
left: -40px;
}
.#{$name}-toggle-show-button {
@include icon-button;
background: transparent;
border: none;
padding: 0;
position: relative;
left: -8px;
&.error {
cursor: not-allowed;
@ -198,6 +205,7 @@ $minimal-z-index: max($github-header-z-index, $github-pull-request-float-header-
width: 32px;
height: 32px;
padding: 4px;
border-radius: 6px;
border: 1px solid var(--gitako-border-tertiary);
background: var(--gitako-bg-tertiary);
@ -207,33 +215,27 @@ $minimal-z-index: max($github-header-z-index, $github-pull-request-float-header-
}
transition: all ease 0.3s;
font-size: 16px;
transform: translateX(0px);
transform: translateX(8px);
&:active,
&:hover {
transform: translateX(4px);
transform: translateX(12px);
}
}
.tentacle {
width: 40px;
height: 40px;
object-fit: contain;
transition: all ease 0.4s;
transform: translateX(-16px);
transform: translateX(-8px);
filter: drop-shadow(0 0 1px var(--gitako-bg-backdrop));
}
&:active,
&:hover {
.tentacle {
transform: translateX(-12px);
transform: translateX(-4px);
filter: drop-shadow(0 0 2px var(--gitako-bg-backdrop));
}
}
img {
filter: drop-shadow(0 0 1px var(--gitako-bg-backdrop));
transition: all ease 0.3s;
width: 90%;
height: 90%;
object-fit: contain;
}
}
.error-message {