1
0
Fork 0
freesewing/sites/org/components/header/index.mjs

185 lines
5.3 KiB
JavaScript
Raw Normal View History

import { useState, useEffect } from 'react'
2023-04-07 17:10:54 +02:00
import {
CommunityIcon,
DesignIcon,
DocsIcon,
MenuIcon,
RssIcon,
SearchIcon,
ShowcaseIcon,
UserIcon,
ThemeIcon,
I18nIcon,
} from 'shared/components/icons.mjs'
import { Ribbon } from 'shared/components/ribbon.mjs'
2023-04-07 17:10:54 +02:00
import Link from 'next/link'
import { useTranslation } from 'next-i18next'
import { ModalThemePicker, ns as themeNs } from 'shared/components/modal/theme-picker.mjs'
import { ModalLocalePicker, ns as localeNs } from 'shared/components/modal/locale-picker.mjs'
2023-04-09 15:57:25 +02:00
import { ModalMenu } from 'site/components/navigation/modal-menu.mjs'
export const ns = ['header', themeNs, localeNs]
2023-04-07 17:10:54 +02:00
const NavButton = ({ href, label, color, children, onClick = false, extraClasses = '' }) => {
const className =
'border-0 px-1 lg:px-4 text-base py-3 lg:py-4 text-center flex flex-col items-center 2xl:w-36 ' +
`hover:bg-${color}-400 text-${color}-400 hover:text-neutral grow lg:grow-0 ${extraClasses}`
const span = <span className="block font-bold hidden 2xl:block">{label}</span>
return onClick ? (
<button {...{ onClick, className }} title={label}>
{children}
{span}
</button>
) : (
<Link {...{ href, className }} title={label}>
{children}
{span}
</Link>
)
}
const NavSpacer = () => (
<div className="hidden lg:block text-base lg:text-4xl font-thin opacity-30 px-0.5 lg:px-2">|</div>
)
2023-04-09 15:57:25 +02:00
export const colors = {
menu: 'red',
designs: 'orange',
showcase: 'yellow',
docs: 'lime',
blog: 'green',
community: 'cyan',
theme: 'blue',
language: 'indigo',
search: 'violet',
account: 'purple',
}
2023-04-07 17:33:45 +02:00
const NavIcons = ({ app, setSearch }) => {
2023-04-07 17:10:54 +02:00
const { t } = useTranslation(['header'])
const iconSize = 'h-6 w-6 lg:h-12 lg:w-12'
return (
<>
2023-04-09 15:57:25 +02:00
<NavButton
onClick={() => app.setModal(<ModalMenu app={app} />)}
label={t('header:menu')}
color={colors.menu}
>
2023-04-07 17:10:54 +02:00
<MenuIcon className={iconSize} />
</NavButton>
<NavSpacer />
2023-04-09 15:57:25 +02:00
<NavButton href="/designs" label={t('header:designs')} color={colors.designs}>
2023-04-07 17:10:54 +02:00
<DesignIcon className={iconSize} />
</NavButton>
<NavButton
href="/showcase"
label={t('header:showcase')}
2023-04-09 15:57:25 +02:00
color={colors.showcase}
2023-04-07 17:10:54 +02:00
extraClasses="hidden lg:flex"
>
<ShowcaseIcon className={iconSize} />
</NavButton>
2023-04-09 15:57:25 +02:00
<NavButton
href="/docs"
label={t('header:docs')}
color={colors.docs}
extraClasses="hidden lg:flex"
>
2023-04-07 17:10:54 +02:00
<DocsIcon className={iconSize} />
</NavButton>
2023-04-09 15:57:25 +02:00
<NavButton
href="/blog"
label={t('header:blog')}
color={colors.blog}
extraClasses="hidden lg:flex"
>
2023-04-07 17:10:54 +02:00
<RssIcon className={iconSize} />
</NavButton>
<NavButton
href="/community"
label={t('header:community')}
2023-04-09 15:57:25 +02:00
color={colors.community}
2023-04-07 17:10:54 +02:00
extraClasses="hidden lg:flex"
>
<CommunityIcon className={iconSize} />
</NavButton>
<NavSpacer />
<NavButton
onClick={() => app.setModal(<ModalThemePicker app={app} />)}
label={t('header:theme')}
2023-04-09 15:57:25 +02:00
color={colors.theme}
2023-04-07 17:10:54 +02:00
>
<ThemeIcon className={iconSize} />
</NavButton>
2023-04-07 17:33:45 +02:00
<NavButton
onClick={() => app.setModal(<ModalLocalePicker app={app} />)}
label={t('header:language')}
2023-04-09 15:57:25 +02:00
color={colors.language}
2023-04-07 17:33:45 +02:00
>
2023-04-07 17:10:54 +02:00
<I18nIcon className={iconSize} />
</NavButton>
2023-04-09 15:57:25 +02:00
<NavButton onClick={() => setSearch(true)} label={t('header:search')} color={colors.search}>
2023-04-07 17:10:54 +02:00
<SearchIcon className={iconSize} />
</NavButton>
<NavSpacer />
2023-04-09 15:57:25 +02:00
<NavButton href="/account" label={t('header:account')} color={colors.account}>
2023-04-07 17:10:54 +02:00
<UserIcon className={iconSize} />
</NavButton>
</>
)
}
export const Header = ({ app, setSearch }) => {
const [prevScrollPos, setPrevScrollPos] = useState(0)
const [show, setShow] = useState(true)
useEffect(() => {
if (typeof window !== 'undefined') {
2022-01-20 09:07:38 +01:00
const handleScroll = () => {
2022-11-23 21:42:22 +01:00
const curScrollPos = typeof window !== 'undefined' ? window.pageYOffset : 0
2022-01-20 09:07:38 +01:00
if (curScrollPos >= prevScrollPos) {
if (show && curScrollPos > 20) setShow(false)
2022-11-23 21:42:22 +01:00
} else setShow(true)
2022-01-20 09:07:38 +01:00
setPrevScrollPos(curScrollPos)
}
window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}
2022-01-20 09:07:38 +01:00
}, [prevScrollPos, show])
return (
2022-11-23 21:42:22 +01:00
<header
className={`
fixed bottom-0 lg:bottom-auto lg:top-0 left-0
bg-neutral
w-full
z-30
transition-transform
${
2023-03-24 21:30:04 +01:00
show || app.state.loading
? ''
2023-04-07 17:10:54 +02:00
: 'fixed bottom-0 lg:top-0 left-0 translate-y-36 lg:-translate-y-36'
}
2022-11-23 21:42:22 +01:00
drop-shadow-xl
`}
>
2022-12-24 18:16:09 +01:00
<div className="m-auto md:px-8">
<div className="p-0 flex flex-row gap-2 justify-between text-neutral-content items-center">
2023-04-07 17:10:54 +02:00
{/* Non-mobile content */}
<div className="hidden lg:flex lg:px-2 flex-row items-center justify-center w-full">
2023-04-07 17:33:45 +02:00
<NavIcons app={app} setSearch={setSearch} />
2022-11-23 21:42:22 +01:00
</div>
2023-04-07 17:10:54 +02:00
{/* Mobile content */}
<div className="flex lg:hidden flex-row items-center justify-between w-full">
2023-04-07 17:33:45 +02:00
<NavIcons app={app} setSearch={setSearch} />
</div>
</div>
2022-11-23 21:42:22 +01:00
</div>
2023-03-24 21:30:04 +01:00
<Ribbon loading={app.state.loading} theme={app.theme} />
2022-11-23 21:42:22 +01:00
</header>
)
}