feat: create sticky version of components involved

Notices problems are
- Links in content area are higher (in terms of z value) than the sticky header.
- The sidebar header for table of contents seems to be positioned higher than it should.
- Text size of breadcrumb and title are too big.
- Flickering problem on pages that are short (less content/one page content).
This commit is contained in:
jumpyapple
2021-06-01 00:02:56 -04:00
committed by Jean-Philippe Sirois
parent 5ba1e86672
commit 8a5970107f
2 changed files with 122 additions and 13 deletions
+59 -13
View File
@@ -17,7 +17,7 @@ interface IBoxedTitleProps {
} }
type HeaderBareboneState = { type HeaderBareboneState = {
scrollY: Number scrollY: number
} }
const BoxedTitle: React.FC<IBoxedTitleProps> = (props) => { const BoxedTitle: React.FC<IBoxedTitleProps> = (props) => {
@@ -39,6 +39,29 @@ const BoxedTitle: React.FC<IBoxedTitleProps> = (props) => {
) )
} }
const StickyBoxedTitle: React.FC<IBoxedTitleProps> = (props) => {
return (
<SC.StickyBox>
{props.above}
<SC.Title
className={cx({
"has-content-above": props.above,
"has-content-below": props.content,
})}
>
{props.children}
</SC.Title>
{props.content}
</SC.StickyBox>
)
}
const StickyContainer: React.FC = ({ children, ...restProps }) => {
return <SC.StickyContainerWrapper {...restProps}>{children}</SC.StickyContainerWrapper>
}
const debounce = (fn) => { const debounce = (fn) => {
let frame let frame
return (...params) => { return (...params) => {
@@ -52,11 +75,15 @@ const debounce = (fn) => {
} }
export class HeaderBarebone extends Component<IHeaderBareboneProps, HeaderBareboneState> { export class HeaderBarebone extends Component<IHeaderBareboneProps, HeaderBareboneState> {
controller: AbortController
state: HeaderBareboneState = {
scrollY: 0
}
constructor(props) { constructor(props) {
super(props) super(props)
this.tick = this.tick.bind(this) this.tick = this.tick.bind(this)
this.state = { scrollY: 0 } this.controller = new AbortController()
} }
tick() { tick() {
@@ -67,32 +94,51 @@ export class HeaderBarebone extends Component<IHeaderBareboneProps, HeaderBarebo
} }
} }
componentWillMount() { componentDidMount() {
document.addEventListener('scroll', debounce(this.tick), { passive: true, signal: this.controller.signal })
this.tick() this.tick()
} }
componentDidMount() { componentWillUnmount() {
document.addEventListener('scroll', debounce(this.tick), { passive: true }) this.controller.abort()
} }
render() { render() {
const props = this.props; const props = this.props;
const isBoxed = props.above || props.content const isBoxed = props.above || props.content
return ( if (this.state.scrollY <= 250) {
return (
<SC.HeaderWrapper className={props.className}> <SC.HeaderWrapper className={props.className}>
<SC.Background /> <SC.Background />
<Container> <Container>
{(isBoxed && this.state.scrollY < 30) && ( {isBoxed && (
<BoxedTitle above={props.above} content={props.content}> <BoxedTitle above={props.above} content={props.content}>
{props.title} {props.title}
</BoxedTitle> </BoxedTitle>
)} )}
{!isBoxed && <SC.SingleTitle>{props.title}</SC.SingleTitle>} {!isBoxed && <SC.SingleTitle>{props.title}</SC.SingleTitle>}
</Container> </Container>
</SC.HeaderWrapper> </SC.HeaderWrapper>
) )
} else {
return (
<SC.HeaderWrapperSticky className={props.className}>
<SC.Background />
<StickyContainer>
{isBoxed && (
<StickyBoxedTitle above={props.above}>
{props.title}
</StickyBoxedTitle>
)}
{!isBoxed && <SC.SingleTitle>{props.title}</SC.SingleTitle>}
</StickyContainer>
</SC.HeaderWrapperSticky>
)
}
} }
} }
+63
View File
@@ -9,6 +9,11 @@ import HeaderMobile from "../../images/header-mobile-375x300.png"
const spaceAbove = 67 const spaceAbove = 67
const height = 300 - spaceAbove const height = 300 - spaceAbove
export const StickyContainerWrapper = styled.div`
margin: 0;
width: 100%;
`
export const HeaderWrapper = styled.div` export const HeaderWrapper = styled.div`
display: flex; display: flex;
width: 100%; width: 100%;
@@ -34,6 +39,31 @@ export const HeaderWrapper = styled.div`
} }
` `
export const HeaderWrapperSticky = styled.div`
display: flex;
width: 100%;
height: 7px;
padding-top: ${spaceAbove}px;
position: fixed;
&.shifted {
width: calc(100% - 305px);
padding-right: 305px;
}
@media screen and (max-width: 1200px) {
width: 100% !important;
padding-right: 0 !important;
}
@media screen and (max-width: 767px) {
display: flex;
align-items: flex-end;
height: auto;
min-height: ${height}px;
}
`
export const Background = styled.div` export const Background = styled.div`
position: absolute; position: absolute;
top: 0; top: 0;
@@ -99,6 +129,39 @@ export const Box = styled.div`
} }
` `
export const StickyBox = styled.div`
display: inline-flex;
flex-direction: column;
position: absolute;
bottom: 0;
background: ${(props) => transparentize(0.3, props.theme.main.background)};
padding: 16px;
backdrop-filter: blur(14px);
width: 100%;
@media screen and (max-width: 1200px) {
max-width: 100%;
left: 32px;
right: 32px;
margin-left: 0;
}
@media screen and (max-width: 767px) {
position: static;
bottom: auto;
top: auto;
margin: 32px 0;
left: 0px;
right: 0px;
@-moz-document url-prefix() {
& {
position: relative;
}
}
}
`
const title = css` const title = css`
font-family: ${fontFamily.header}; font-family: ${fontFamily.header};
font-size: 34px; font-size: 34px;