omnivore/packages/web/components/templates/reader/ReaderHeader.tsx

149 lines
4 KiB
TypeScript
Raw Permalink Normal View History

import { HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
2023-02-27 01:49:49 +00:00
import { Button } from '../../elements/Button'
import { LogoBox } from '../../elements/LogoBox'
import { ReactNode, useEffect, useState } from 'react'
import { DEFAULT_HEADER_HEIGHT } from '../homeFeed/HeaderSpacer'
import { theme } from '../../tokens/stitches.config'
2023-08-01 04:31:12 +00:00
import { ReaderSettingsIcon } from '../../elements/icons/ReaderSettingsIcon'
2023-02-25 11:31:06 +00:00
function useScrollDirection() {
const [scrollDirection, setScrollDirection] = useState('up')
useEffect(() => {
let lastScrollY = window.pageYOffset
const updateScrollDirection = () => {
const scrollY = window.pageYOffset
const direction = scrollY > lastScrollY ? 'down' : 'up'
if (
direction !== scrollDirection &&
(scrollY - lastScrollY > 10 || scrollY - lastScrollY < -10)
) {
setScrollDirection(direction)
}
lastScrollY = scrollY > 0 ? scrollY : 0
}
window.addEventListener('scroll', updateScrollDirection) // add event listener
return () => {
window.removeEventListener('scroll', updateScrollDirection) // clean up
}
}, [scrollDirection])
return scrollDirection
}
2023-02-27 07:37:00 +00:00
type ReaderHeaderProps = {
alwaysDisplayToolbar: boolean
hideDisplaySettings: boolean
2023-02-27 07:37:00 +00:00
showDisplaySettingsModal: (show: boolean) => void
2023-03-02 09:04:31 +00:00
children?: ReactNode
2023-02-27 07:37:00 +00:00
}
export function ReaderHeader(props: ReaderHeaderProps): JSX.Element {
const scrollDirection = useScrollDirection()
2023-02-25 11:31:06 +00:00
return (
<>
<VStack
alignment="center"
distribution="start"
css={{
top: '0',
left: '0',
zIndex: 1,
pt: '0px',
pb: '15px',
2023-02-25 11:31:06 +00:00
position: 'fixed',
width: '100%',
2024-02-08 11:03:22 +00:00
height: DEFAULT_HEADER_HEIGHT,
display: props.alwaysDisplayToolbar ? 'flex' : 'transparent',
2023-05-30 08:18:11 +00:00
pointerEvents: props.alwaysDisplayToolbar ? 'unset' : 'none',
borderBottom: '1px solid transparent',
'@xlgDown': {
bg: '$readerBg',
pointerEvents: 'unset',
2023-02-25 11:31:06 +00:00
},
'@mdDown': {
top: scrollDirection === 'down' ? '-90px' : '0',
bg: '$readerBg',
pointerEvents: 'unset',
transitionProperty: 'top',
transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
transitionDuration: '200ms',
},
2023-06-27 10:27:45 +00:00
'@media print': {
display: 'none',
},
2023-02-25 11:31:06 +00:00
}}
>
<HStack
alignment="center"
distribution="start"
css={{
width: '100%',
height: '100%',
}}
>
<LogoBox />
2023-03-03 13:55:04 +00:00
<SpanBox
css={{
width: '100%',
px: '25px',
'@lg': {
display: props.alwaysDisplayToolbar ? 'flex' : 'none',
},
2023-03-03 13:55:04 +00:00
'@mdDown': { px: '15px' },
}}
>
{props.children}
</SpanBox>
{!props.alwaysDisplayToolbar && !props.hideDisplaySettings && (
<SpanBox
css={{
width: '100%',
'@lgDown': {
display: 'none',
},
}}
>
<ControlButtonBox {...props} />
</SpanBox>
)}
2023-02-25 11:31:06 +00:00
</HStack>
</VStack>
</>
)
}
2023-02-27 07:37:00 +00:00
function ControlButtonBox(props: ReaderHeaderProps): JSX.Element {
2023-02-25 11:31:06 +00:00
return (
<>
<HStack
alignment="center"
distribution="end"
css={{
marginLeft: 'auto',
marginRight: '25px',
2023-02-25 11:31:06 +00:00
width: '100px',
height: '100%',
gap: '20px',
minWidth: '121px',
2023-05-25 12:16:55 +00:00
pointerEvents: 'all',
2023-02-25 11:31:06 +00:00
}}
>
<Button
2023-11-01 07:16:05 +00:00
title="Reader preferences (d)"
2023-02-25 11:31:06 +00:00
style="articleActionIcon"
2023-02-27 07:37:00 +00:00
onClick={() => {
props.showDisplaySettingsModal(true)
}}
2023-02-25 11:31:06 +00:00
>
2023-08-01 09:27:58 +00:00
<ReaderSettingsIcon
size={25}
color={theme.colors.thHighContrast.toString()}
/>
2023-02-25 11:31:06 +00:00
</Button>
</HStack>
</>
)
}