2024-07-09 09:13:13 +00:00
|
|
|
import { Meta, Title } from '@solidjs/meta'
|
|
|
|
import { useLocation } from '@solidjs/router'
|
2022-11-16 21:08:04 +00:00
|
|
|
import { clsx } from 'clsx'
|
2024-07-09 09:13:13 +00:00
|
|
|
import type { JSX } from 'solid-js'
|
|
|
|
import { Show, createEffect, createMemo, createSignal } from 'solid-js'
|
|
|
|
import { useLocalize } from '~/context/localize'
|
|
|
|
import { Shout } from '~/graphql/schema/core.gen'
|
|
|
|
import enKeywords from '~/intl/locales/en/keywords.json'
|
|
|
|
import ruKeywords from '~/intl/locales/ru/keywords.json'
|
2024-07-13 12:25:25 +00:00
|
|
|
import { getImageUrl, getOpenGraphImageUrl } from '~/lib/getThumbUrl'
|
2024-07-13 09:06:49 +00:00
|
|
|
import { descFromBody } from '~/utils/meta'
|
2024-06-25 22:52:46 +00:00
|
|
|
import { FooterView } from '../Discours/Footer'
|
2024-07-21 02:17:42 +00:00
|
|
|
import { Header } from '../HeaderNav'
|
2023-02-17 09:21:02 +00:00
|
|
|
import styles from './PageLayout.module.scss'
|
2022-09-22 09:37:49 +00:00
|
|
|
|
2024-07-09 09:13:13 +00:00
|
|
|
type PageLayoutProps = {
|
2023-11-14 10:45:44 +00:00
|
|
|
title: string
|
2024-07-09 09:13:13 +00:00
|
|
|
desc?: string
|
2024-07-13 09:36:23 +00:00
|
|
|
keywords?: string
|
2022-09-22 09:37:49 +00:00
|
|
|
headerTitle?: string
|
2023-04-17 10:31:20 +00:00
|
|
|
slug?: string
|
2024-07-09 09:13:13 +00:00
|
|
|
article?: Shout
|
2023-01-30 10:39:36 +00:00
|
|
|
cover?: string
|
2022-09-22 09:37:49 +00:00
|
|
|
children: JSX.Element
|
2022-09-23 21:29:32 +00:00
|
|
|
isHeaderFixed?: boolean
|
2022-09-29 11:15:59 +00:00
|
|
|
hideFooter?: boolean
|
2022-11-16 21:08:04 +00:00
|
|
|
class?: string
|
2023-02-17 09:21:02 +00:00
|
|
|
withPadding?: boolean
|
2023-10-10 15:38:02 +00:00
|
|
|
zeroBottomPadding?: boolean
|
2023-04-17 10:31:20 +00:00
|
|
|
scrollToComments?: (value: boolean) => void
|
2024-07-09 09:13:13 +00:00
|
|
|
key?: string
|
2022-09-22 09:37:49 +00:00
|
|
|
}
|
|
|
|
|
2024-07-09 09:13:13 +00:00
|
|
|
export const PageLayout = (props: PageLayoutProps) => {
|
|
|
|
const isHeaderFixed = props.isHeaderFixed === undefined ? true : props.isHeaderFixed // FIXME: выглядит как костылек
|
|
|
|
const loc = useLocation()
|
|
|
|
const { t, lang } = useLocalize()
|
|
|
|
const imageUrl = props.cover ? getImageUrl(props.cover) : 'production/image/logo_image.png'
|
|
|
|
const ogImage = createMemo(() =>
|
|
|
|
// NOTE: preview generation logic works only for one article view
|
|
|
|
props.article
|
|
|
|
? getOpenGraphImageUrl(imageUrl, {
|
|
|
|
title: props.title,
|
|
|
|
topic: props.article?.topics?.[0]?.title || '',
|
|
|
|
author: props.article?.authors?.[0]?.name || '',
|
|
|
|
width: 1200
|
|
|
|
})
|
|
|
|
: imageUrl
|
|
|
|
)
|
2024-07-13 09:36:23 +00:00
|
|
|
const description = createMemo(() => props.desc || (props.article && descFromBody(props.article.body)))
|
2024-07-09 09:13:13 +00:00
|
|
|
const keypath = createMemo(() => (props.key || loc?.pathname.split('/')[0]) as keyof typeof ruKeywords)
|
|
|
|
const keywords = createMemo(
|
2024-07-13 09:36:23 +00:00
|
|
|
() => props.keywords || (lang() === 'ru' ? ruKeywords[keypath()] : enKeywords[keypath()])
|
2024-07-09 09:13:13 +00:00
|
|
|
)
|
2023-04-17 10:31:20 +00:00
|
|
|
const [scrollToComments, setScrollToComments] = createSignal<boolean>(false)
|
2024-07-09 09:13:13 +00:00
|
|
|
createEffect(() => props.scrollToComments?.(scrollToComments()))
|
2022-09-22 09:37:49 +00:00
|
|
|
return (
|
|
|
|
<>
|
2024-07-09 09:56:56 +00:00
|
|
|
<Title>{props.article?.title || t(props.title)}</Title>
|
2023-01-30 10:39:36 +00:00
|
|
|
<Header
|
2023-04-17 10:31:20 +00:00
|
|
|
slug={props.slug}
|
2023-01-30 10:39:36 +00:00
|
|
|
title={props.headerTitle}
|
2024-07-09 09:13:13 +00:00
|
|
|
desc={props.desc}
|
|
|
|
cover={imageUrl}
|
2023-01-30 10:39:36 +00:00
|
|
|
isHeaderFixed={isHeaderFixed}
|
2023-04-17 10:31:20 +00:00
|
|
|
scrollToComments={(value) => setScrollToComments(value)}
|
2023-01-30 10:39:36 +00:00
|
|
|
/>
|
2024-07-09 09:13:13 +00:00
|
|
|
<Meta name="descprition" content={description() || ''} />
|
|
|
|
<Meta name="keywords" content={keywords()} />
|
|
|
|
<Meta name="og:type" content="article" />
|
2024-07-09 09:56:56 +00:00
|
|
|
<Meta name="og:title" content={props.article?.title || t(props.title) || ''} />
|
2024-07-09 09:13:13 +00:00
|
|
|
<Meta name="og:image" content={ogImage() || ''} />
|
|
|
|
<Meta name="twitter:image" content={ogImage() || ''} />
|
|
|
|
<Meta name="og:description" content={description() || ''} />
|
|
|
|
<Meta name="twitter:card" content="summary_large_image" />
|
2024-07-09 09:56:56 +00:00
|
|
|
<Meta name="twitter:title" content={props.article?.title || t(props.title) || ''} />
|
2024-07-09 09:13:13 +00:00
|
|
|
<Meta name="twitter:description" content={description() || ''} />
|
2022-11-16 21:08:04 +00:00
|
|
|
<main
|
2023-02-17 09:21:02 +00:00
|
|
|
class={clsx('main-content', {
|
2023-10-10 15:38:02 +00:00
|
|
|
[styles.withPadding]: props.withPadding,
|
2024-06-26 08:22:05 +00:00
|
|
|
[styles.zeroBottomPadding]: props.zeroBottomPadding
|
2023-02-17 09:21:02 +00:00
|
|
|
})}
|
2022-11-16 21:08:04 +00:00
|
|
|
classList={{ 'main-content--no-padding': !isHeaderFixed }}
|
|
|
|
>
|
2024-07-09 09:13:13 +00:00
|
|
|
<div class={clsx([props.class, 'wide-container'])}>{props.children}</div>
|
2022-09-29 19:16:17 +00:00
|
|
|
</main>
|
2022-09-29 11:15:59 +00:00
|
|
|
<Show when={props.hideFooter !== true}>
|
2024-06-25 22:52:46 +00:00
|
|
|
<FooterView />
|
2022-09-29 11:15:59 +00:00
|
|
|
</Show>
|
2022-09-22 09:37:49 +00:00
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|