UNPKG

gatsby-theme-guitar-book

Version:

A Gatsby theme for building guitar book websites

225 lines (204 loc) 5.02 kB
import PropTypes from 'prop-types'; import React, {useRef, useState} from 'react'; import SectionNav from './section-nav'; import styled from '@emotion/styled'; import useMount from 'react-use/lib/useMount'; import {HEADER_HEIGHT} from '../utils'; import {IconGithub} from '@apollo/space-kit/icons/IconGithub'; import PageNav from './page-nav'; import {colors} from '../utils/colors'; import breakpoints from '../utils/breakpoints'; import {withPrefix} from 'gatsby'; const Wrapper = styled.div({ display: 'flex', alignItems: 'flex-start' }); const InnerWrapper = styled.div({ flexGrow: 1, width: 0 }); const BodyContent = styled.div({ // style all anchors with an href and no prior classes // this helps avoid anchors with names and styled buttons 'a[href]:not([class])': { color: colors.primary, textDecoration: 'none', ':hover': { textDecoration: 'underline' }, code: { color: 'inherit' } }, [['h1', 'h2', 'h3', 'h4', 'h5', 'h6']]: { code: { whiteSpace: 'normal' }, a: { color: 'inherit', textDecoration: 'none', ':hover': { color: colors.text2 } } }, '*:not(style) +': { [['h2', 'h3', 'h4']]: { marginTop: 56 } }, img: { display: 'block', maxWidth: '100%', margin: '0 auto' }, '.mermaid svg': { maxWidth: '100%' } }); const Aside = styled.aside({ display: 'flex', flexDirection: 'column', flexShrink: 0, width: 240, maxHeight: `calc(100vh - ${HEADER_HEIGHT}px)`, marginTop: -36, padding: '40px 0', marginLeft: 40, position: 'sticky', top: HEADER_HEIGHT, [breakpoints.lg]: { display: 'none' }, [breakpoints.md]: { display: 'block' }, [breakpoints.sm]: { display: 'none' } }); const AsideHeading = styled.h4({ fontWeight: 600 }); const AsideLinkWrapper = styled.h5({ display: 'flex', marginBottom: 0, ':not(:last-child)': { marginBottom: 16 } }); const AsideLinkInner = styled.a({ display: 'flex', alignItems: 'center', color: colors.text2, textDecoration: 'none', ':hover': { color: colors.text3 }, svg: { width: 20, height: 20, marginRight: 6, fill: 'currentColor' } }); function AsideLink(props) { return ( <AsideLinkWrapper> <AsideLinkInner target="_blank" rel="noopener noreferrer" {...props} /> </AsideLinkWrapper> ); } const EditLink = styled.div({ display: 'none', marginTop: 48, justifyContent: 'flex-end', [breakpoints.lg]: { display: 'flex' }, [breakpoints.md]: { display: 'none' }, [breakpoints.sm]: { display: 'flex', marginTop: 24 } }); export default function PageContent(props) { const contentRef = useRef(null); const [imagesToLoad, setImagesToLoad] = useState(0); const [imagesLoaded, setImagesLoaded] = useState(0); useMount(() => { if (props.hash) { // turn numbers at the beginning of the hash to unicode // see https://stackoverflow.com/a/20306237/8190832 const hash = props.hash.toLowerCase().replace(/^#(\d)/, '#\\3$1 '); try { const hashElement = contentRef.current.querySelector(hash); if (hashElement) { hashElement.scrollIntoView(); } } catch (error) { // let errors pass } } let toLoad = 0; const images = contentRef.current.querySelectorAll('img'); images.forEach(image => { if (!image.complete) { image.addEventListener('load', handleImageLoad); toLoad++; } }); setImagesToLoad(toLoad); }); function handleImageLoad() { setImagesLoaded(prevImagesLoaded => prevImagesLoaded + 1); } const pageIndex = props.pages.findIndex(page => { const prefixedPath = withPrefix(page.path); return ( prefixedPath === props.pathname || prefixedPath.replace(/\/$/, '') === props.pathname ); }); const editLink = props.githubUrl && ( <AsideLink href={props.githubUrl}> <IconGithub /> Edit on GitHub </AsideLink> ); return ( <Wrapper> <InnerWrapper> <BodyContent ref={contentRef} className="content-wrapper"> {props.children} </BodyContent> <EditLink>{editLink}</EditLink> <PageNav prevPage={props.pages[pageIndex - 1]} nextPage={props.pages[pageIndex + 1]} /> </InnerWrapper> <Aside> <AsideHeading>{props.title}</AsideHeading> {props.headings.length > 0 && ( <SectionNav headings={props.headings} contentRef={contentRef} imagesLoaded={imagesLoaded === imagesToLoad} /> )} {editLink} </Aside> </Wrapper> ); } PageContent.propTypes = { children: PropTypes.node.isRequired, pathname: PropTypes.string.isRequired, githubUrl: PropTypes.string, pages: PropTypes.array.isRequired, hash: PropTypes.string.isRequired, title: PropTypes.string.isRequired, headings: PropTypes.array.isRequired };