media-audio-view

This commit is contained in:
tonyrewin 2022-11-27 14:00:44 +03:00
parent 9b4cede871
commit d0a165c3f4
6 changed files with 115 additions and 38 deletions

View File

@ -1,4 +1,6 @@
<svg width="20" height="13" viewBox="0 0 20 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 6C13 7.65685 11.6569 9 10 9C8.34315 9 7 7.65685 7 6C7 4.34315 8.34315 3 10 3C11.6569 3 13 4.34315 13 6Z" fill="#141414"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.7784 6.5C16.6611 8.44191 13.9671 11 10 11C6.03294 11 3.33893 8.44191 2.22163 6.5C3.33893 4.55809 6.03294 2 10 2C13.9671 2 16.6611 4.55809 17.7784 6.5ZM10 13C15.5228 13 19 9 20 6.5C19 4 15.5228 0 10 0C4.47715 0 1 4 0 6.5C1 9 4.47715 13 10 13Z" fill="#141414"/>
<svg xmlns="http://www.w3.org/2000/svg" width="512px" height="512px" viewBox="0 0 512 512">
<path
d="M255.66,112c-77.94,0-157.89,45.11-220.83,135.33a16,16,0,0,0-.27,17.77C82.92,340.8,161.8,400,255.66,400,348.5,400,429,340.62,477.45,264.75a16.14,16.14,0,0,0,0-17.47C428.89,172.28,347.8,112,255.66,112Z"
style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px" />
<circle cx="256" cy="256" r="80" style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:32px" />
</svg>

Before

Width:  |  Height:  |  Size: 551 B

After

Width:  |  Height:  |  Size: 532 B

View File

@ -2,8 +2,8 @@ import { capitalize, formatDate } from '../../utils'
import './Full.scss'
import { Icon } from '../_shared/Icon'
import { AuthorCard } from '../Author/Card'
import { createMemo, createSignal, For, onMount, Show } from 'solid-js'
import type { Author, Reaction, Shout } from '../../graphql/types.gen'
import { createMemo, createSignal, For, Match, onMount, Show, Switch } from 'solid-js'
import type { Author, Shout } from '../../graphql/types.gen'
import { t } from '../../utils/intl'
import MD from './MD'
import { SharePopup } from './SharePopup'
@ -12,11 +12,50 @@ import styles from '../../styles/Article.module.scss'
import RatingControl from './RatingControl'
import { clsx } from 'clsx'
import { CommentsTree } from './CommentsTree'
import { useSession } from '../../context/session'
interface ArticleProps {
article: Shout
}
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>
</>
)
}
export const FullArticle = (props: ArticleProps) => {
const { session } = useSession()
const formattedDate = createMemo(() => formatDate(new Date(props.article.createdAt)))
const [isSharePopupVisible, setIsSharePopupVisible] = createSignal(false)
@ -39,6 +78,20 @@ export const FullArticle = (props: ArticleProps) => {
}
})
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
})
return (
<div class="shout wide-container">
<article class="col-md-6 shift-content">
@ -65,13 +118,24 @@ export const FullArticle = (props: ArticleProps) => {
<div class={styles.shoutCover} style={{ 'background-image': `url('${props.article.cover}')` }} />
</div>
<Show when={Boolean(props.article.body)}>
<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()}>
<div class={styles.shoutBody}>
<Show
when={!props.article.body.startsWith('<')}
fallback={<div innerHTML={props.article.body} />}
>
<MD body={props.article.body} />
<Show when={!body().startsWith('<')} fallback={<div innerHTML={body()} />}>
<MD body={body()} />
</Show>
</div>
</Show>
@ -83,16 +147,18 @@ export const FullArticle = (props: ArticleProps) => {
<RatingControl rating={props.article.stat?.rating} class={styles.ratingControl} />
</div>
<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>
<div class={styles.shoutStatsItem}>
<Icon name="comment" class={styles.icon} />
{props.article.stat?.commented || ''}
</div>
{/*FIXME*/}
{/*<div class={styles.shoutStatsItem}>*/}
{/* <a href="#bookmark" onClick={() => console.log(props.article.slug, 'articles')}>*/}
{/* <Icon name={'bookmark' + (bookmarked() ? '' : '-x')} />*/}
{/* </a>*/}
{/*</div>*/}
<div class={styles.shoutStatsItem}>
<SharePopup
onVisibilityChange={(isVisible) => {
@ -102,36 +168,32 @@ export const FullArticle = (props: ArticleProps) => {
trigger={<Icon name="share-new" class={styles.icon} />}
/>
</div>
<div class={styles.shoutStatsItem}>
<div class={styles.shoutStatsItem} onClick={bookmark}>
<Icon name="bookmark" class={styles.icon} />
</div>
{/*FIXME*/}
{/*<Show when={canEdit()}>*/}
{/* <div class={styles.shoutStatsItem}>*/}
{/* <a href="/edit">*/}
{/* <Icon name="edit" />*/}
{/* {t('Edit')}*/}
{/* </a>*/}
{/* </div>*/}
{/*</Show>*/}
<Show when={canEdit()}>
<div class={styles.shoutStatsItem}>
<a href="/edit">
<Icon name="edit" />
{t('Edit')}
</a>
</div>
</Show>
<div class={clsx(styles.shoutStatsItem, styles.shoutStatsItemAdditionalData)}>
<div class={clsx(styles.shoutStatsItem, styles.shoutStatsItemAdditionalDataItem)}>
{formattedDate()}
</div>
<Show when={props.article.stat?.viewed}>
<div class={clsx(styles.shoutStatsItem, styles.shoutStatsItemAdditionalDataItem)}>
<Icon name="view" class={styles.icon} />
{props.article.stat?.viewed}
</div>
</Show>
</div>
</div>
<div class={styles.help}>
<button class="button">Соучаствовать</button>
<button class="button button--light">Пригласить к участию</button>
<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>
</div>
<div class={styles.topicsList}>

View File

@ -49,6 +49,7 @@ export const HomeView = (props: HomeProps) => {
onMount(async () => {
if (sortedArticles().length < PRERENDERED_ARTICLES_COUNT + CLIENT_LOAD_ARTICLES_COUNT) {
const { hasMore } = await loadShouts({
filters: { visibility: 'public' },
limit: CLIENT_LOAD_ARTICLES_COUNT,
offset: sortedArticles().length
})

View File

@ -10,6 +10,7 @@ export default gql`
layout
cover
body
media
# community
mainTopic
topics {

View File

@ -58,6 +58,17 @@ img {
}
}
.shoutMediaBody {
display: block;
audio {
display: inline-block;
}
video {
display: block;
}
}
.shoutAuthor,
.shoutDate {
@include font-size(1.5rem);

View File

@ -39,7 +39,7 @@ import reactionsLoadBy from '../graphql/query/reactions-load-by'
import { REACTIONS_AMOUNT_PER_PAGE } from '../stores/zine/reactions'
import authorsLoadBy from '../graphql/query/authors-load-by'
import shoutsLoadBy from '../graphql/query/articles-load-by'
import shoutLoad from '../graphql/query/articles-load'
import shoutLoad from '../graphql/query/article-load'
import loadRecipients from '../graphql/query/chat-recipients'
import createMessage from '../graphql/mutation/create-chat-message'