webapp/src/components/Nav/Header.tsx

165 lines
5.0 KiB
TypeScript
Raw Normal View History

2022-09-15 18:18:07 +00:00
import { For, Show, createSignal, createMemo, createEffect, onMount, onCleanup } from 'solid-js'
2022-09-09 11:53:35 +00:00
import Private from './Private'
import Notifications from './Notifications'
2022-09-22 09:37:49 +00:00
import { Icon } from './Icon'
2022-09-09 11:53:35 +00:00
import { Modal } from './Modal'
import AuthModal from './AuthModal'
import { t } from '../../utils/intl'
import { useModalStore, showModal, useWarningsStore } from '../../stores/ui'
import { useStore } from '@nanostores/solid'
import { session as ssession } from '../../stores/auth'
2022-09-22 09:37:49 +00:00
import { handleClientRouteLinkClick, router, Routes, useRouter } from '../../stores/router'
2022-09-09 11:53:35 +00:00
import './Header.scss'
2022-09-22 09:37:49 +00:00
import { getPagePath } from '@nanostores/router'
import { getLogger } from '../../utils/logger'
2022-09-09 11:53:35 +00:00
2022-09-22 09:37:49 +00:00
const log = getLogger('header')
const resources: { name: string; route: keyof Routes }[] = [
{ name: t('zine'), route: 'home' },
{ name: t('feed'), route: 'feed' },
{ name: t('topics'), route: 'topics' }
2022-09-09 11:53:35 +00:00
]
2022-09-22 09:37:49 +00:00
const handleEnterClick = () => {
showModal('auth')
}
type Props = {
title?: string
2022-09-23 21:29:32 +00:00
isHeaderFixed?: boolean
2022-09-22 09:37:49 +00:00
}
export const Header = (props: Props) => {
2022-09-09 11:53:35 +00:00
// signals
2022-09-15 18:18:07 +00:00
const [getIsScrollingBottom, setIsScrollingBottom] = createSignal(false)
2022-09-15 19:41:05 +00:00
const [getIsScrolled, setIsScrolled] = createSignal(false)
2022-09-09 11:53:35 +00:00
const [fixed, setFixed] = createSignal(false)
const [visibleWarnings, setVisibleWarnings] = createSignal(false)
// stores
const { getWarnings } = useWarningsStore()
const session = useStore(ssession)
const { getModal } = useModalStore()
2022-09-22 09:37:49 +00:00
const { getPage } = useRouter()
2022-09-09 11:53:35 +00:00
// methods
const toggleWarnings = () => setVisibleWarnings(!visibleWarnings())
const toggleFixed = () => setFixed(!fixed())
// effects
createEffect(() => {
if (fixed() || getModal()) {
document.body.classList.add('fixed')
} else {
document.body.classList.remove('fixed')
}
}, [fixed(), getModal()])
// derived
const authorized = createMemo(() => session()?.user?.slug)
2022-09-14 11:28:43 +00:00
2022-09-22 09:37:49 +00:00
const handleBellIconClick = () => {
2022-09-14 11:28:43 +00:00
if (!authorized()) {
2022-09-22 09:37:49 +00:00
showModal('auth')
2022-09-14 11:28:43 +00:00
return
}
toggleWarnings()
}
2022-09-14 21:07:47 +00:00
onMount(() => {
2022-09-15 18:18:07 +00:00
let scrollTop = window.scrollY
2022-09-14 21:07:47 +00:00
2022-09-15 18:18:07 +00:00
const handleScroll = () => {
setIsScrollingBottom(window.scrollY > scrollTop)
2022-09-15 19:41:05 +00:00
setIsScrolled(window.scrollY > 0)
2022-09-15 18:18:07 +00:00
scrollTop = window.scrollY
}
2022-09-14 21:07:47 +00:00
2022-09-15 18:18:07 +00:00
window.addEventListener('scroll', handleScroll, { passive: true })
onCleanup(() => {
window.removeEventListener('scroll', handleScroll)
})
})
2022-09-14 21:07:47 +00:00
2022-09-09 11:53:35 +00:00
return (
2022-09-15 18:18:07 +00:00
<header
2022-09-23 21:29:32 +00:00
class="main-header"
2022-09-15 18:18:07 +00:00
classList={{
2022-09-23 21:29:32 +00:00
['header--fixed']: props.isHeaderFixed,
2022-09-15 19:41:05 +00:00
['header--scrolled-top']: !getIsScrollingBottom() && getIsScrolled(),
['header--scrolled-bottom']: getIsScrollingBottom() && getIsScrolled()
2022-09-15 18:18:07 +00:00
}}
>
2022-09-09 11:53:35 +00:00
<Modal name="auth">
<AuthModal />
</Modal>
<div class="wide-container">
<nav class="row header__inner" classList={{ fixed: fixed() }}>
<div class="main-logo col-auto">
2022-09-22 09:37:49 +00:00
<a href={getPagePath(router, 'home')} onClick={handleClientRouteLinkClick}>
2022-09-09 11:53:35 +00:00
<img src="/logo.svg" alt={t('Discours')} />
</a>
</div>
2022-09-15 19:41:05 +00:00
<div class="col main-navigation">
2022-09-22 09:37:49 +00:00
<div class="article-header">{props.title}</div>
2022-09-15 19:41:05 +00:00
2022-09-22 09:37:49 +00:00
<ul class="col main-navigation text-xl inline-flex" classList={{ fixed: fixed() }}>
2022-09-15 19:41:05 +00:00
<For each={resources}>
2022-09-22 09:37:49 +00:00
{(r) => (
<li classList={{ selected: r.route === getPage().route }}>
<a href={getPagePath(router, r.route, null)} onClick={handleClientRouteLinkClick}>
2022-09-15 19:41:05 +00:00
{r.name}
</a>
</li>
)}
</For>
2022-09-18 15:31:48 +00:00
<li class="header__search">
<a href="#">
<Icon name="search" />
{t('Search')}
</a>
</li>
2022-09-15 19:41:05 +00:00
</ul>
</div>
2022-09-09 11:53:35 +00:00
<div class="usernav">
<div class="usercontrol col">
<div class="usercontrol__item">
2022-09-14 11:28:43 +00:00
<a href="#auth" onClick={handleBellIconClick}>
2022-09-09 11:53:35 +00:00
<div>
<Icon name="bell-white" counter={authorized() ? getWarnings().length : 1} />
</div>
</a>
</div>
<Show when={visibleWarnings()}>
<div class="usercontrol__item notifications">
<Notifications />
</div>
</Show>
<Show
when={authorized()}
fallback={
<div class="usercontrol__item loginbtn">
2022-09-14 11:28:43 +00:00
<a href="#auth" onClick={handleEnterClick}>
2022-09-09 11:53:35 +00:00
{t('enter')}
</a>
</div>
}
>
<Private />
</Show>
</div>
</div>
<div class="burger-container">
<div class="burger" classList={{ fixed: fixed() }} onClick={toggleFixed}>
<div />
</div>
</div>
</nav>
</div>
</header>
)
}