2022-11-26 21:27:54 +00:00
|
|
|
import { capitalize, formatDate } from '../../utils'
|
2022-09-09 11:53:35 +00:00
|
|
|
import './Full.scss'
|
2022-11-14 17:41:05 +00:00
|
|
|
import { Icon } from '../_shared/Icon'
|
2022-09-09 11:53:35 +00:00
|
|
|
import { AuthorCard } from '../Author/Card'
|
2022-11-27 11:00:44 +00:00
|
|
|
import { createMemo, createSignal, For, Match, onMount, Show, Switch } from 'solid-js'
|
|
|
|
import type { Author, Shout } from '../../graphql/types.gen'
|
2022-09-09 11:53:35 +00:00
|
|
|
import { t } from '../../utils/intl'
|
2022-10-07 11:02:34 +00:00
|
|
|
import MD from './MD'
|
2022-10-25 15:36:32 +00:00
|
|
|
import { SharePopup } from './SharePopup'
|
2022-11-23 19:14:59 +00:00
|
|
|
import stylesHeader from '../Nav/Header.module.scss'
|
|
|
|
import styles from '../../styles/Article.module.scss'
|
|
|
|
import RatingControl from './RatingControl'
|
|
|
|
import { clsx } from 'clsx'
|
2022-11-26 16:51:08 +00:00
|
|
|
import { CommentsTree } from './CommentsTree'
|
2022-11-27 11:00:44 +00:00
|
|
|
import { useSession } from '../../context/session'
|
|
|
|
|
2022-09-09 11:53:35 +00:00
|
|
|
interface ArticleProps {
|
|
|
|
article: Shout
|
|
|
|
}
|
|
|
|
|
2022-11-27 11:00:44 +00:00
|
|
|
interface MediaItem {
|
|
|
|
url?: string
|
|
|
|
pic?: string
|
|
|
|
title?: string
|
|
|
|
body?: string
|
|
|
|
}
|
|
|
|
|
|
|
|
const MediaView = (props: { media: MediaItem; kind: Shout['layout'] }) => {
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<Switch
|
|
|
|
fallback={
|
|
|
|
<picture>
|
|
|
|
<source src={props.media.url} />
|
|
|
|
</picture>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<Match when={props.kind === 'audio'}>
|
|
|
|
<div>
|
|
|
|
<h5>{props.media.title}</h5>
|
|
|
|
<audio controls>
|
|
|
|
<source src={props.media.url} />
|
|
|
|
</audio>
|
|
|
|
<hr />
|
|
|
|
</div>
|
|
|
|
</Match>
|
|
|
|
<Match when={props.kind === 'video'}>
|
|
|
|
<video controls>
|
|
|
|
<source src={props.media.url} />
|
|
|
|
</video>
|
|
|
|
</Match>
|
|
|
|
</Switch>
|
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-09-09 11:53:35 +00:00
|
|
|
export const FullArticle = (props: ArticleProps) => {
|
2022-11-27 11:00:44 +00:00
|
|
|
const { session } = useSession()
|
2022-09-09 11:53:35 +00:00
|
|
|
const formattedDate = createMemo(() => formatDate(new Date(props.article.createdAt)))
|
|
|
|
|
|
|
|
const mainTopic = () =>
|
|
|
|
(props.article.topics?.find((topic) => topic?.slug === props.article.mainTopic)?.title || '').replace(
|
|
|
|
' ',
|
|
|
|
' '
|
|
|
|
)
|
|
|
|
|
|
|
|
onMount(() => {
|
|
|
|
const windowHash = window.location.hash
|
|
|
|
if (windowHash?.length > 0) {
|
|
|
|
const comments = document.querySelector(windowHash)
|
|
|
|
if (comments) {
|
|
|
|
window.scrollTo({
|
|
|
|
top: comments.getBoundingClientRect().top,
|
|
|
|
behavior: 'smooth'
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-11-27 11:00:44 +00:00
|
|
|
const canEdit = () => props.article.authors?.some((a) => a.slug === session()?.user?.slug)
|
|
|
|
|
|
|
|
const bookmark = (ev) => {
|
|
|
|
// TODO: implement bookmark clicked
|
|
|
|
ev.preventDefault()
|
|
|
|
}
|
|
|
|
|
|
|
|
const body = createMemo(() => props.article.body)
|
|
|
|
const media = createMemo(() => {
|
|
|
|
const mi = JSON.parse(props.article.media || '[]')
|
|
|
|
console.debug(mi)
|
|
|
|
return mi
|
|
|
|
})
|
|
|
|
|
2022-09-09 11:53:35 +00:00
|
|
|
return (
|
|
|
|
<div class="shout wide-container">
|
|
|
|
<article class="col-md-6 shift-content">
|
2022-11-23 19:14:59 +00:00
|
|
|
<div class={styles.shoutHeader}>
|
|
|
|
<div class={styles.shoutTopic}>
|
2022-09-09 11:53:35 +00:00
|
|
|
<a href={`/topic/${props.article.mainTopic}`} innerHTML={mainTopic() || ''} />
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<h1>{props.article.title}</h1>
|
|
|
|
<Show when={props.article.subtitle}>
|
|
|
|
<h4>{capitalize(props.article.subtitle, false)}</h4>
|
|
|
|
</Show>
|
|
|
|
|
2022-11-23 19:14:59 +00:00
|
|
|
<div class={styles.shoutAuthor}>
|
2022-09-09 11:53:35 +00:00
|
|
|
<For each={props.article.authors}>
|
|
|
|
{(a: Author, index) => (
|
|
|
|
<>
|
|
|
|
<Show when={index() > 0}>, </Show>
|
|
|
|
<a href={`/author/${a.slug}`}>{a.name}</a>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</For>
|
|
|
|
</div>
|
2022-11-23 19:14:59 +00:00
|
|
|
<div class={styles.shoutCover} style={{ 'background-image': `url('${props.article.cover}')` }} />
|
2022-09-09 11:53:35 +00:00
|
|
|
</div>
|
|
|
|
|
2022-11-27 11:00:44 +00:00
|
|
|
<Show when={media()}>
|
|
|
|
<div class="media-items">
|
|
|
|
<For each={media() || []}>
|
|
|
|
{(m: MediaItem) => (
|
|
|
|
<div class={styles.shoutMediaBody}>
|
|
|
|
<MediaView media={m} kind={props.article.layout} />
|
|
|
|
<Show when={m?.body}>
|
|
|
|
<div innerHTML={m.body} />
|
|
|
|
</Show>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</For>
|
|
|
|
</div>
|
|
|
|
</Show>
|
|
|
|
<Show when={body()}>
|
2022-11-23 19:14:59 +00:00
|
|
|
<div class={styles.shoutBody}>
|
2022-11-27 11:00:44 +00:00
|
|
|
<Show when={!body().startsWith('<')} fallback={<div innerHTML={body()} />}>
|
|
|
|
<MD body={body()} />
|
2022-10-09 10:56:39 +00:00
|
|
|
</Show>
|
|
|
|
</div>
|
|
|
|
</Show>
|
2022-09-09 11:53:35 +00:00
|
|
|
</article>
|
|
|
|
|
|
|
|
<div class="col-md-8 shift-content">
|
2022-11-23 19:14:59 +00:00
|
|
|
<div class={styles.shoutStats}>
|
|
|
|
<div class={styles.shoutStatsItem}>
|
2022-11-26 21:27:54 +00:00
|
|
|
<RatingControl rating={props.article.stat?.rating} class={styles.ratingControl} />
|
2022-11-23 19:14:59 +00:00
|
|
|
</div>
|
|
|
|
|
2022-11-27 11:00:44 +00:00
|
|
|
<Show when={props.article.stat?.viewed}>
|
|
|
|
<div class={clsx(styles.shoutStatsItem)}>
|
|
|
|
<Icon name="eye" class={styles.icon} />
|
|
|
|
<sup>{props.article.stat?.viewed}</sup>
|
|
|
|
</div>
|
|
|
|
</Show>
|
|
|
|
|
2022-11-23 19:14:59 +00:00
|
|
|
<div class={styles.shoutStatsItem}>
|
|
|
|
<Icon name="comment" class={styles.icon} />
|
2022-09-09 11:53:35 +00:00
|
|
|
{props.article.stat?.commented || ''}
|
|
|
|
</div>
|
2022-11-27 11:00:44 +00:00
|
|
|
|
2022-11-23 19:14:59 +00:00
|
|
|
<div class={styles.shoutStatsItem}>
|
2022-10-25 15:36:32 +00:00
|
|
|
<SharePopup
|
2022-11-23 19:14:59 +00:00
|
|
|
containerCssClass={stylesHeader.control}
|
2022-11-27 08:15:03 +00:00
|
|
|
trigger={<Icon name="share-new" class={styles.icon} />}
|
2022-10-25 15:36:32 +00:00
|
|
|
/>
|
2022-09-09 11:53:35 +00:00
|
|
|
</div>
|
2022-11-27 11:00:44 +00:00
|
|
|
|
|
|
|
<div class={styles.shoutStatsItem} onClick={bookmark}>
|
2022-11-23 19:14:59 +00:00
|
|
|
<Icon name="bookmark" class={styles.icon} />
|
|
|
|
</div>
|
|
|
|
|
2022-11-27 11:00:44 +00:00
|
|
|
<Show when={canEdit()}>
|
|
|
|
<div class={styles.shoutStatsItem}>
|
|
|
|
<a href="/edit">
|
|
|
|
<Icon name="edit" />
|
|
|
|
{t('Edit')}
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</Show>
|
2022-11-23 19:14:59 +00:00
|
|
|
<div class={clsx(styles.shoutStatsItem, styles.shoutStatsItemAdditionalData)}>
|
|
|
|
<div class={clsx(styles.shoutStatsItem, styles.shoutStatsItemAdditionalDataItem)}>
|
2022-11-26 16:51:08 +00:00
|
|
|
{formattedDate()}
|
2022-11-23 19:14:59 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2022-09-09 11:53:35 +00:00
|
|
|
</div>
|
2022-11-26 21:27:54 +00:00
|
|
|
<div class={styles.help}>
|
2022-11-27 11:00:44 +00:00
|
|
|
<Show when={session()?.token}>
|
|
|
|
<button class="button">{t('Cooperate')}</button>
|
|
|
|
</Show>
|
|
|
|
<Show when={canEdit()}>
|
|
|
|
<button class="button button--light">{t('Invite to collab')}</button>
|
|
|
|
</Show>
|
2022-11-26 21:27:54 +00:00
|
|
|
</div>
|
|
|
|
|
2022-11-23 19:14:59 +00:00
|
|
|
<div class={styles.topicsList}>
|
2022-09-13 09:59:04 +00:00
|
|
|
<For each={props.article.topics}>
|
|
|
|
{(topic) => (
|
2022-11-23 19:14:59 +00:00
|
|
|
<div class={styles.shoutTopic}>
|
2022-09-13 09:59:04 +00:00
|
|
|
<a href={`/topic/${topic.slug}`}>{topic.title}</a>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</For>
|
|
|
|
</div>
|
2022-09-09 11:53:35 +00:00
|
|
|
|
2022-11-23 19:14:59 +00:00
|
|
|
<div class={styles.shoutAuthorsList}>
|
2022-09-09 11:53:35 +00:00
|
|
|
<Show when={props.article?.authors?.length > 1}>
|
|
|
|
<h4>{t('Authors')}</h4>
|
|
|
|
</Show>
|
|
|
|
<For each={props.article?.authors}>
|
2022-11-23 19:14:59 +00:00
|
|
|
{(a: Author) => (
|
2022-11-26 21:27:54 +00:00
|
|
|
<div class="col-xl-6">
|
2022-11-23 19:14:59 +00:00
|
|
|
<AuthorCard author={a} compact={false} hasLink={true} liteButtons={true} />
|
|
|
|
</div>
|
|
|
|
)}
|
2022-09-09 11:53:35 +00:00
|
|
|
</For>
|
|
|
|
</div>
|
2022-11-26 16:51:08 +00:00
|
|
|
<CommentsTree shout={props.article?.slug} />
|
2022-09-09 11:53:35 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|