Add scroll to top button

This commit is contained in:
Sakura Knoll
2022-03-06 17:06:29 +09:00 Unverified
parent f204492786
commit a17fb2d584
2 changed files with 57 additions and 6 deletions
+54 -4
View File
@@ -1,18 +1,42 @@
/** @jsxImportSource theme-ui */ /** @jsxImportSource theme-ui */
import { mdiMenu } from '@mdi/js' import { mdiArrowUp, mdiMenu } from '@mdi/js'
import Icon from '@mdi/react' import Icon from '@mdi/react'
import React, { useCallback, useState } from 'react' import React, { useCallback, useRef, useState } from 'react'
import { Box, Flex, IconButton } from 'theme-ui' import { Box, Flex, IconButton } from 'theme-ui'
import Honkai3rdNavigator from '../organisms/Honkai3rdNavigator' import Honkai3rdNavigator from '../organisms/Honkai3rdNavigator'
const Honkai3rdLayout: React.FC = ({ children }) => { const Honkai3rdLayout: React.FC = ({ children }) => {
const [hiddenMobileNav, setHiddenMobileNav] = useState(true) const [hiddenMobileNav, setHiddenMobileNav] = useState(true)
const contentBoxRef = useRef<HTMLDivElement>(null)
const [scrolled, setScrolled] = useState(false)
const close = useCallback(() => { const close = useCallback(() => {
setHiddenMobileNav(true) setHiddenMobileNav(true)
}, []) }, [])
const handleScroll = useCallback(() => {
if (contentBoxRef.current == null) {
return
}
if (contentBoxRef.current.scrollTop === 0) {
return setScrolled(false)
}
if (scrolled) {
return
}
setScrolled(true)
}, [scrolled])
const scrollToTop = useCallback(() => {
if (contentBoxRef.current == null) {
return
}
contentBoxRef.current.scrollTop = 0
}, [])
return ( return (
<Flex <Flex
sx={{ sx={{
@@ -33,14 +57,40 @@ const Honkai3rdLayout: React.FC = ({ children }) => {
> >
<Honkai3rdNavigator close={close} /> <Honkai3rdNavigator close={close} />
</Box> </Box>
<Box sx={{ flex: 1, overflowY: 'auto', overflowX: 'hidden' }}> <Box
sx={{
flex: 1,
overflowY: 'auto',
overflowX: 'hidden',
scrollBehavior: 'smooth',
}}
onScroll={handleScroll}
ref={contentBoxRef}
>
<IconButton
sx={{
width: 50,
height: 50,
position: 'absolute',
bottom: 1,
right: 1,
zIndex: 1000,
pointerEvents: scrolled ? 'auto' : 'none',
opacity: scrolled ? 1 : 0,
transition: 'opacity 200ms ease-in-out',
backgroundColor: 'transparent',
}}
onClick={scrollToTop}
>
<Icon path={mdiArrowUp} size={1} />
</IconButton>
<Flex <Flex
sx={{ sx={{
position: 'sticky', position: 'sticky',
display: ['block', 'none'], display: ['block', 'none'],
top: 0, top: 0,
height: 50, height: 50,
bg: 'rgba(255,255,255,0.8)', bg: 'transparent',
}} }}
> >
<IconButton <IconButton
+3 -2
View File
@@ -19,6 +19,7 @@ export const theme: Theme = {
light: '#f8f9fa', light: '#f8f9fa',
dark: '#343a40', dark: '#343a40',
textMuted: '#6c757d', textMuted: '#6c757d',
transparent: 'transparent',
}, },
space: ['0rem', '0.25rem', '0.5rem', '1rem', '1.5rem', '3rem'], space: ['0rem', '0.25rem', '0.5rem', '1rem', '1.5rem', '3rem'],
fonts: { fonts: {
@@ -107,7 +108,7 @@ export const theme: Theme = {
'box-shadow 200ms ease-in-out, color 200ms ease-in-out, background-color 200ms ease-in-out', 'box-shadow 200ms ease-in-out, color 200ms ease-in-out, background-color 200ms ease-in-out',
'&:hover': { '&:hover': {
bg: 'rgba(0, 123, 255, 0.2)', bg: 'rgba(0, 123, 255, 0.2)',
boxShadow: 'rgba(0, 0, 0, 0.2) 0px 4px 8px;', boxShadow: 'default',
}, },
'&.hidden': { '&.hidden': {
display: 'none', display: 'none',
@@ -228,7 +229,7 @@ export const theme: Theme = {
transition: transition:
'box-shadow 200ms ease-in-out, color 200ms ease-in-out, background-color 200ms ease-in-out', 'box-shadow 200ms ease-in-out, color 200ms ease-in-out, background-color 200ms ease-in-out',
'&:hover': { '&:hover': {
boxShadow: 'rgba(0, 0, 0, 0.2) 0px 4px 8px;', boxShadow: 'default',
}, },
}, },
stigmata: { stigmata: {