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'
|
2022-10-25 16:25:42 +00:00
|
|
|
import { AuthModal } from './AuthModal'
|
2022-09-09 11:53:35 +00:00
|
|
|
import { t } from '../../utils/intl'
|
2022-10-25 15:36:32 +00:00
|
|
|
import { useModalStore, showModal, useWarningsStore } from '../../stores/ui'
|
2022-09-30 14:22:33 +00:00
|
|
|
import { useAuthStore } from '../../stores/auth'
|
2022-09-22 09:37:49 +00:00
|
|
|
import { handleClientRouteLinkClick, router, Routes, useRouter } from '../../stores/router'
|
2022-09-28 21:08:14 +00:00
|
|
|
import styles from './Header.module.scss'
|
2022-10-03 21:31:11 +00:00
|
|
|
import privateStyles from './Private.module.scss'
|
2022-09-22 09:37:49 +00:00
|
|
|
import { getPagePath } from '@nanostores/router'
|
|
|
|
import { getLogger } from '../../utils/logger'
|
2022-09-28 21:08:14 +00:00
|
|
|
import { clsx } from 'clsx'
|
2022-10-25 15:36:32 +00:00
|
|
|
import { SharePopup } from '../Article/SharePopup'
|
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
|
|
|
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)
|
2022-10-25 15:36:32 +00:00
|
|
|
const [isSharePopupVisible, setIsSharePopupVisible] = createSignal(false)
|
2022-09-09 11:53:35 +00:00
|
|
|
// stores
|
2022-10-25 16:25:42 +00:00
|
|
|
const { warnings } = useWarningsStore()
|
2022-09-30 14:22:33 +00:00
|
|
|
const { session } = useAuthStore()
|
2022-10-25 16:25:42 +00:00
|
|
|
const { modal } = useModalStore()
|
2022-09-22 09:37:49 +00:00
|
|
|
|
2022-10-25 16:25:42 +00:00
|
|
|
const { page } = useRouter()
|
2022-09-22 09:37:49 +00:00
|
|
|
|
2022-09-09 11:53:35 +00:00
|
|
|
// methods
|
|
|
|
const toggleWarnings = () => setVisibleWarnings(!visibleWarnings())
|
2022-10-25 15:36:32 +00:00
|
|
|
const toggleFixed = () => setFixed((oldFixed) => !oldFixed)
|
2022-09-09 11:53:35 +00:00
|
|
|
// effects
|
|
|
|
createEffect(() => {
|
2022-10-25 16:25:42 +00:00
|
|
|
document.body.classList.toggle('fixed', fixed() || modal() !== null)
|
2022-10-25 21:17:35 +00:00
|
|
|
document.body.classList.toggle(styles.fixed, fixed() && !modal())
|
2022-10-25 15:36:32 +00:00
|
|
|
})
|
2022-09-09 11:53:35 +00:00
|
|
|
|
|
|
|
// derived
|
|
|
|
const authorized = createMemo(() => session()?.user?.slug)
|
2022-09-14 11:28:43 +00:00
|
|
|
|
2022-10-25 16:25:42 +00:00
|
|
|
const handleBellIconClick = (event: Event) => {
|
|
|
|
event.preventDefault()
|
|
|
|
|
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-28 21:08:14 +00:00
|
|
|
class={styles.mainHeader}
|
2022-09-15 18:18:07 +00:00
|
|
|
classList={{
|
2022-09-28 21:08:14 +00:00
|
|
|
[styles.headerFixed]: props.isHeaderFixed,
|
2022-09-29 20:10:00 +00:00
|
|
|
[styles.headerScrolledTop]: !getIsScrollingBottom() && getIsScrolled(),
|
2022-10-25 15:36:32 +00:00
|
|
|
[styles.headerScrolledBottom]: (getIsScrollingBottom() && getIsScrolled()) || isSharePopupVisible(),
|
2022-10-04 10:48:11 +00:00
|
|
|
[styles.headerWithTitle]: Boolean(props.title)
|
2022-09-15 18:18:07 +00:00
|
|
|
}}
|
|
|
|
>
|
2022-09-09 11:53:35 +00:00
|
|
|
<Modal name="auth">
|
|
|
|
<AuthModal />
|
|
|
|
</Modal>
|
2022-10-17 20:53:04 +00:00
|
|
|
|
|
|
|
<div class={clsx(styles.mainHeaderInner, 'wide-container')}>
|
2022-09-28 21:08:14 +00:00
|
|
|
<nav class={clsx(styles.headerInner, 'row')} classList={{ fixed: fixed() }}>
|
|
|
|
<div class={clsx(styles.mainLogo, '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-10-03 21:31:11 +00:00
|
|
|
<div class={clsx(styles.mainNavigationWrapper, 'col')}>
|
2022-10-03 21:44:21 +00:00
|
|
|
<Show when={props.title}>
|
|
|
|
<div class={styles.articleHeader}>{props.title}</div>
|
|
|
|
</Show>
|
2022-09-15 19:41:05 +00:00
|
|
|
|
2022-09-29 10:08:22 +00:00
|
|
|
<ul
|
|
|
|
class={clsx(styles.mainNavigation, 'col 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) => (
|
2022-10-25 16:25:42 +00:00
|
|
|
<li classList={{ [styles.selected]: r.route === page().route }}>
|
2022-09-22 09:37:49 +00:00
|
|
|
<a href={getPagePath(router, r.route, null)} onClick={handleClientRouteLinkClick}>
|
2022-09-15 19:41:05 +00:00
|
|
|
{r.name}
|
|
|
|
</a>
|
|
|
|
</li>
|
|
|
|
)}
|
|
|
|
</For>
|
2022-09-28 21:08:14 +00:00
|
|
|
<li class={styles.headerSearch}>
|
2022-09-18 15:31:48 +00:00
|
|
|
<a href="#">
|
2022-09-29 19:16:17 +00:00
|
|
|
<Icon name="search" class={styles.icon} iconClassName={styles.searchIcon} />
|
2022-09-18 15:31:48 +00:00
|
|
|
{t('Search')}
|
|
|
|
</a>
|
|
|
|
</li>
|
2022-09-15 19:41:05 +00:00
|
|
|
</ul>
|
|
|
|
</div>
|
2022-09-29 10:08:22 +00:00
|
|
|
<div class={styles.usernav}>
|
2022-10-03 21:31:11 +00:00
|
|
|
<div class={clsx(privateStyles.userControl, styles.userControl, 'col')}>
|
|
|
|
<div class={privateStyles.userControlItem}>
|
2022-10-25 16:25:42 +00:00
|
|
|
<a href="#" onClick={handleBellIconClick}>
|
2022-09-09 11:53:35 +00:00
|
|
|
<div>
|
2022-10-25 16:25:42 +00:00
|
|
|
<Icon name="bell-white" counter={authorized() ? warnings().length : 1} />
|
2022-09-09 11:53:35 +00:00
|
|
|
</div>
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<Show when={visibleWarnings()}>
|
2022-10-03 21:31:11 +00:00
|
|
|
<div class={clsx(privateStyles.userControlItem, 'notifications')}>
|
2022-09-09 11:53:35 +00:00
|
|
|
<Notifications />
|
|
|
|
</div>
|
|
|
|
</Show>
|
|
|
|
|
|
|
|
<Show
|
|
|
|
when={authorized()}
|
|
|
|
fallback={
|
2022-10-03 21:31:11 +00:00
|
|
|
<div class={clsx(privateStyles.userControlItem, 'loginbtn')}>
|
2022-10-25 16:25:42 +00:00
|
|
|
<a href="?modal=auth&mode=login" onClick={handleClientRouteLinkClick}>
|
2022-10-03 21:31:11 +00:00
|
|
|
<Icon name="user-anonymous" />
|
2022-09-09 11:53:35 +00:00
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<Private />
|
|
|
|
</Show>
|
|
|
|
</div>
|
2022-10-03 21:44:21 +00:00
|
|
|
<Show when={props.title}>
|
|
|
|
<div class={styles.articleControls}>
|
2022-10-25 15:36:32 +00:00
|
|
|
<SharePopup
|
|
|
|
onVisibilityChange={(isVisible) => {
|
|
|
|
console.log({ isVisible })
|
|
|
|
setIsSharePopupVisible(isVisible)
|
|
|
|
}}
|
|
|
|
containerCssClass={styles.control}
|
|
|
|
trigger={<Icon name="share-outline" class={styles.icon} />}
|
|
|
|
/>
|
|
|
|
<a href="#comments" class={styles.control}>
|
2022-10-03 21:44:21 +00:00
|
|
|
<Icon name="comments-outline" class={styles.icon} />
|
|
|
|
</a>
|
2022-10-25 15:36:32 +00:00
|
|
|
<a href="#" class={styles.control} onClick={(event) => event.preventDefault()}>
|
|
|
|
<Icon name="pencil-outline" class={styles.icon} />
|
|
|
|
</a>
|
|
|
|
<a href="#" class={styles.control} onClick={(event) => event.preventDefault()}>
|
|
|
|
<Icon name="bookmark" class={styles.icon} />
|
|
|
|
</a>
|
2022-10-03 21:44:21 +00:00
|
|
|
</div>
|
|
|
|
</Show>
|
2022-09-09 11:53:35 +00:00
|
|
|
</div>
|
2022-09-29 10:08:22 +00:00
|
|
|
<div class={styles.burgerContainer}>
|
|
|
|
<div class={styles.burger} classList={{ fixed: fixed() }} onClick={toggleFixed}>
|
2022-09-09 11:53:35 +00:00
|
|
|
<div />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</nav>
|
|
|
|
</div>
|
|
|
|
</header>
|
|
|
|
)
|
|
|
|
}
|