Merge remote-tracking branch 'gitlab/dev' into create-shout-2
This commit is contained in:
commit
61a6448b61
|
@ -144,6 +144,7 @@ img {
|
||||||
|
|
||||||
.shoutStatsItem {
|
.shoutStatsItem {
|
||||||
@include font-size(1.5rem);
|
@include font-size(1.5rem);
|
||||||
|
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 3.2rem 1em 0;
|
margin: 0 3.2rem 1em 0;
|
||||||
|
@ -175,6 +176,19 @@ img {
|
||||||
|
|
||||||
a {
|
a {
|
||||||
border: none;
|
border: none;
|
||||||
|
text-decoration: none;
|
||||||
|
&:hover {
|
||||||
|
background: unset;
|
||||||
|
color: #000;
|
||||||
|
|
||||||
|
img {
|
||||||
|
filter: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import styles from './Comment.module.scss'
|
import styles from './Comment.module.scss'
|
||||||
import { Icon } from '../_shared/Icon'
|
import { Icon } from '../_shared/Icon'
|
||||||
import { AuthorCard } from '../Author/Card'
|
import { AuthorCard } from '../Author/Card'
|
||||||
import { Show, createMemo, createSignal, For, lazy, Suspense } from 'solid-js'
|
import { Show, createMemo, createSignal, For, lazy, Suspense, createEffect } from 'solid-js'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import type { Author, Reaction } from '../../graphql/types.gen'
|
import type { Author, Reaction } from '../../graphql/types.gen'
|
||||||
import MD from './MD'
|
import MD from './MD'
|
||||||
|
@ -30,6 +30,7 @@ export const Comment = (props: Props) => {
|
||||||
const [isReplyVisible, setIsReplyVisible] = createSignal(false)
|
const [isReplyVisible, setIsReplyVisible] = createSignal(false)
|
||||||
const [loading, setLoading] = createSignal<boolean>(false)
|
const [loading, setLoading] = createSignal<boolean>(false)
|
||||||
const [editMode, setEditMode] = createSignal<boolean>(false)
|
const [editMode, setEditMode] = createSignal<boolean>(false)
|
||||||
|
const [submitted, setSubmitted] = createSignal<boolean>(false)
|
||||||
const { session } = useSession()
|
const { session } = useSession()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -66,6 +67,7 @@ export const Comment = (props: Props) => {
|
||||||
})
|
})
|
||||||
setIsReplyVisible(false)
|
setIsReplyVisible(false)
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
|
setSubmitted(true)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[handleCreate reaction]:', error)
|
console.error('[handleCreate reaction]:', error)
|
||||||
}
|
}
|
||||||
|
@ -94,6 +96,7 @@ export const Comment = (props: Props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const createdAt = new Date(comment()?.createdAt)
|
const createdAt = new Date(comment()?.createdAt)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li class={clsx(styles.comment, { [styles.isNew]: !isCommentAuthor() && createdAt > props.lastSeen })}>
|
<li class={clsx(styles.comment, { [styles.isNew]: !isCommentAuthor() && createdAt > props.lastSeen })}>
|
||||||
<Show when={!!body()}>
|
<Show when={!!body()}>
|
||||||
|
@ -105,7 +108,6 @@ export const Comment = (props: Props) => {
|
||||||
<Userpic
|
<Userpic
|
||||||
user={comment().createdBy as Author}
|
user={comment().createdBy as Author}
|
||||||
isBig={false}
|
isBig={false}
|
||||||
isAuthorsList={false}
|
|
||||||
class={clsx({
|
class={clsx({
|
||||||
[styles.compactUserpic]: props.compact
|
[styles.compactUserpic]: props.compact
|
||||||
})}
|
})}
|
||||||
|
@ -202,7 +204,12 @@ export const Comment = (props: Props) => {
|
||||||
|
|
||||||
<Show when={isReplyVisible()}>
|
<Show when={isReplyVisible()}>
|
||||||
<Suspense fallback={<p>{t('Loading')}</p>}>
|
<Suspense fallback={<p>{t('Loading')}</p>}>
|
||||||
<CommentEditor placeholder={''} onSubmit={(value) => handleCreate(value)} />
|
<CommentEditor
|
||||||
|
placeholder={''}
|
||||||
|
clear={submitted()}
|
||||||
|
onSubmit={(value) => handleCreate(value)}
|
||||||
|
cancel={() => setIsReplyVisible(false)}
|
||||||
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Show>
|
</Show>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
|
@ -39,15 +39,16 @@ type Props = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CommentsTree = (props: Props) => {
|
export const CommentsTree = (props: Props) => {
|
||||||
|
const { session } = useSession()
|
||||||
|
const { t } = useLocalize()
|
||||||
const [commentsOrder, setCommentsOrder] = createSignal<CommentsOrder>('createdAt')
|
const [commentsOrder, setCommentsOrder] = createSignal<CommentsOrder>('createdAt')
|
||||||
|
const [newReactions, setNewReactions] = createSignal<Reaction[]>([])
|
||||||
|
const [submitted, setSubmitted] = createSignal(false)
|
||||||
const {
|
const {
|
||||||
reactionEntities,
|
reactionEntities,
|
||||||
actions: { createReaction }
|
actions: { createReaction }
|
||||||
} = useReactions()
|
} = useReactions()
|
||||||
|
|
||||||
const { t } = useLocalize()
|
|
||||||
const [newReactions, setNewReactions] = createSignal<Reaction[]>([])
|
|
||||||
|
|
||||||
const comments = createMemo(() =>
|
const comments = createMemo(() =>
|
||||||
Object.values(reactionEntities).filter((reaction) => reaction.kind === 'COMMENT')
|
Object.values(reactionEntities).filter((reaction) => reaction.kind === 'COMMENT')
|
||||||
)
|
)
|
||||||
|
@ -78,7 +79,7 @@ export const CommentsTree = (props: Props) => {
|
||||||
setCookie()
|
setCookie()
|
||||||
} else if (currentDate > dateFromLocalStorage) {
|
} else if (currentDate > dateFromLocalStorage) {
|
||||||
const newComments = comments().filter((c) => {
|
const newComments = comments().filter((c) => {
|
||||||
if (c.replyTo) {
|
if (c.replyTo || c.createdBy.slug === session()?.user.slug) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const created = new Date(c.createdAt)
|
const created = new Date(c.createdAt)
|
||||||
|
@ -89,8 +90,6 @@ export const CommentsTree = (props: Props) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const { session } = useSession()
|
|
||||||
const [submitted, setSubmitted] = createSignal<boolean>(false)
|
|
||||||
const handleSubmitComment = async (value) => {
|
const handleSubmitComment = async (value) => {
|
||||||
try {
|
try {
|
||||||
await createReaction({
|
await createReaction({
|
||||||
|
@ -113,41 +112,42 @@ export const CommentsTree = (props: Props) => {
|
||||||
<span class={styles.newReactions}> +{newReactions().length}</span>
|
<span class={styles.newReactions}> +{newReactions().length}</span>
|
||||||
</Show>
|
</Show>
|
||||||
</h2>
|
</h2>
|
||||||
|
<Show when={comments().length > 0}>
|
||||||
<ul class={clsx(styles.commentsViewSwitcher, 'view-switcher')}>
|
<ul class={clsx(styles.commentsViewSwitcher, 'view-switcher')}>
|
||||||
<Show when={newReactions().length > 0}>
|
<Show when={newReactions().length > 0}>
|
||||||
<li classList={{ selected: commentsOrder() === 'newOnly' }}>
|
<li classList={{ selected: commentsOrder() === 'newOnly' }}>
|
||||||
|
<Button
|
||||||
|
variant="inline"
|
||||||
|
value={t('New only')}
|
||||||
|
onClick={() => {
|
||||||
|
setCommentsOrder('newOnly')
|
||||||
|
}}
|
||||||
|
class={styles.commentsViewSwitcherButton}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</Show>
|
||||||
|
<li classList={{ selected: commentsOrder() === 'createdAt' }}>
|
||||||
<Button
|
<Button
|
||||||
variant="inline"
|
variant="inline"
|
||||||
value={t('New only')}
|
value={t('By time')}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCommentsOrder('newOnly')
|
setCommentsOrder('createdAt')
|
||||||
}}
|
}}
|
||||||
class={styles.commentsViewSwitcherButton}
|
class={styles.commentsViewSwitcherButton}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
</Show>
|
<li classList={{ selected: commentsOrder() === 'rating' }}>
|
||||||
<li classList={{ selected: commentsOrder() === 'createdAt' }}>
|
<Button
|
||||||
<Button
|
variant="inline"
|
||||||
variant="inline"
|
value={t('By rating')}
|
||||||
value={t('By time')}
|
onClick={() => {
|
||||||
onClick={() => {
|
setCommentsOrder('rating')
|
||||||
setCommentsOrder('createdAt')
|
}}
|
||||||
}}
|
class={styles.commentsViewSwitcherButton}
|
||||||
class={styles.commentsViewSwitcherButton}
|
/>
|
||||||
/>
|
</li>
|
||||||
</li>
|
</ul>
|
||||||
<li classList={{ selected: commentsOrder() === 'rating' }}>
|
</Show>
|
||||||
<Button
|
|
||||||
variant="inline"
|
|
||||||
value={t('By rating')}
|
|
||||||
onClick={() => {
|
|
||||||
setCommentsOrder('rating')
|
|
||||||
}}
|
|
||||||
class={styles.commentsViewSwitcherButton}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
<ul class={styles.comments}>
|
<ul class={styles.comments}>
|
||||||
<For each={sortedComments().filter((r) => !r.replyTo)}>
|
<For each={sortedComments().filter((r) => !r.replyTo)}>
|
||||||
|
|
|
@ -22,6 +22,7 @@ import styles from './Article.module.scss'
|
||||||
|
|
||||||
interface ArticleProps {
|
interface ArticleProps {
|
||||||
article: Shout
|
article: Shout
|
||||||
|
scrollToComments?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MediaItem {
|
interface MediaItem {
|
||||||
|
@ -87,6 +88,22 @@ export const FullArticle = (props: ArticleProps) => {
|
||||||
return mi
|
return mi
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const commentsRef: { current: HTMLDivElement } = { current: null }
|
||||||
|
|
||||||
|
const scrollToComments = () => {
|
||||||
|
window.scrollTo({
|
||||||
|
top: commentsRef.current.offsetTop - 96,
|
||||||
|
left: 0,
|
||||||
|
behavior: 'smooth'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (props.scrollToComments) {
|
||||||
|
scrollToComments()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const {
|
const {
|
||||||
actions: { loadReactionsBy }
|
actions: { loadReactionsBy }
|
||||||
} = useReactions()
|
} = useReactions()
|
||||||
|
@ -122,10 +139,12 @@ export const FullArticle = (props: ArticleProps) => {
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<Show when={props.article.cover}>
|
||||||
class={styles.shoutCover}
|
<div
|
||||||
style={{ 'background-image': `url('${props.article.cover}')` }}
|
class={styles.shoutCover}
|
||||||
/>
|
style={{ 'background-image': `url('${props.article.cover}')` }}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Show when={media() && props.article.layout !== 'image'}>
|
<Show when={media() && props.article.layout !== 'image'}>
|
||||||
|
@ -183,12 +202,10 @@ export const FullArticle = (props: ArticleProps) => {
|
||||||
{props.article.stat?.viewed}
|
{props.article.stat?.viewed}
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
<div class={styles.shoutStatsItem} onClick={scrollToComments}>
|
||||||
<a href="#comments" class={styles.shoutStatsItem}>
|
|
||||||
<Icon name="comment" class={styles.icon} />
|
<Icon name="comment" class={styles.icon} />
|
||||||
{props.article.stat?.commented ?? ''}
|
{props.article.stat?.commented ?? ''}
|
||||||
</a>
|
</div>
|
||||||
|
|
||||||
<div class={styles.shoutStatsItem}>
|
<div class={styles.shoutStatsItem}>
|
||||||
<SharePopup
|
<SharePopup
|
||||||
title={props.article.title}
|
title={props.article.title}
|
||||||
|
@ -251,12 +268,12 @@ export const FullArticle = (props: ArticleProps) => {
|
||||||
<For each={props.article.authors}>
|
<For each={props.article.authors}>
|
||||||
{(a) => (
|
{(a) => (
|
||||||
<div class="col-xl-12">
|
<div class="col-xl-12">
|
||||||
<AuthorCard author={a} compact={false} hasLink={true} liteButtons={true} />
|
<AuthorCard author={a} hasLink={true} liteButtons={true} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
</div>
|
</div>
|
||||||
<div id="comments">
|
<div id="comments" ref={(el) => (commentsRef.current = el)}>
|
||||||
<Show when={isReactionsLoaded()}>
|
<Show when={isReactionsLoaded()}>
|
||||||
<CommentsTree
|
<CommentsTree
|
||||||
shoutId={props.article.id}
|
shoutId={props.article.id}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { useLocalize } from '../../context/localize'
|
||||||
|
|
||||||
interface AuthorCardProps {
|
interface AuthorCardProps {
|
||||||
caption?: string
|
caption?: string
|
||||||
compact?: boolean
|
hideWriteButton?: boolean
|
||||||
hideDescription?: boolean
|
hideDescription?: boolean
|
||||||
hideFollow?: boolean
|
hideFollow?: boolean
|
||||||
hasLink?: boolean
|
hasLink?: boolean
|
||||||
|
@ -166,7 +166,7 @@ export const AuthorCard = (props: AuthorCardProps) => {
|
||||||
</button>
|
</button>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Show when={!props.compact && !props.isAuthorsList}>
|
<Show when={!props.hideWriteButton}>
|
||||||
<button
|
<button
|
||||||
class={styles.button}
|
class={styles.button}
|
||||||
classList={{
|
classList={{
|
||||||
|
|
|
@ -6,7 +6,7 @@ export const AuthorFull = (props: { author: Author }) => {
|
||||||
return (
|
return (
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-18 col-lg-16 user-details">
|
<div class="col-md-18 col-lg-16 user-details">
|
||||||
<AuthorCard author={props.author} compact={false} isAuthorPage={true} />
|
<AuthorCard author={props.author} isAuthorPage={true} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -69,7 +69,7 @@ export const Beside = (props: BesideProps) => {
|
||||||
<Show when={props.wrapper === 'author'}>
|
<Show when={props.wrapper === 'author'}>
|
||||||
<AuthorCard
|
<AuthorCard
|
||||||
author={value as Author}
|
author={value as Author}
|
||||||
compact={true}
|
hideWriteButton={true}
|
||||||
hasLink={true}
|
hasLink={true}
|
||||||
truncateBio={true}
|
truncateBio={true}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -15,9 +15,11 @@ import { useLocalize } from '../../context/localize'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title?: string
|
title?: string
|
||||||
|
slug?: string
|
||||||
isHeaderFixed?: boolean
|
isHeaderFixed?: boolean
|
||||||
articleBody?: string
|
articleBody?: string
|
||||||
cover?: string
|
cover?: string
|
||||||
|
scrollToComments?: (value: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Header = (props: Props) => {
|
export const Header = (props: Props) => {
|
||||||
|
@ -78,6 +80,10 @@ export const Header = (props: Props) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const scrollToComments = (value) => {
|
||||||
|
props.scrollToComments(value)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header
|
<header
|
||||||
class={styles.mainHeader}
|
class={styles.mainHeader}
|
||||||
|
@ -138,9 +144,9 @@ export const Header = (props: Props) => {
|
||||||
containerCssClass={styles.control}
|
containerCssClass={styles.control}
|
||||||
trigger={<Icon name="share-outline" class={styles.icon} />}
|
trigger={<Icon name="share-outline" class={styles.icon} />}
|
||||||
/>
|
/>
|
||||||
<a href={getPagePath(router, 'inbox')} class={styles.control}>
|
<div onClick={() => scrollToComments(true)} class={styles.control}>
|
||||||
<Icon name="comments-outline" class={styles.icon} />
|
<Icon name="comments-outline" class={styles.icon} />
|
||||||
</a>
|
</div>
|
||||||
<a href={getPagePath(router, 'create')} class={styles.control}>
|
<a href={getPagePath(router, 'create')} class={styles.control}>
|
||||||
<Icon name="pencil-outline" class={styles.icon} />
|
<Icon name="pencil-outline" class={styles.icon} />
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -99,7 +99,7 @@ export const AuthorView = (props: AuthorProps) => {
|
||||||
})
|
})
|
||||||
setCommented(data)
|
setCommented(data)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[getReactionsBy]:', error)
|
console.error('[getReactionsBy comment]', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -209,6 +209,19 @@ export const AuthorView = (props: AuthorProps) => {
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</Match>
|
</Match>
|
||||||
|
<Match when={searchParams().by === 'followed'}>
|
||||||
|
<div class="wide-container">
|
||||||
|
<div class="row">
|
||||||
|
<For each={followers()}>
|
||||||
|
{(follower: Author) => (
|
||||||
|
<div class="col-md-6 col-lg-4">
|
||||||
|
<AuthorCard author={follower} hideWriteButton={true} hasLink={true} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Match>
|
||||||
<Match when={searchParams().by === 'rating'}>
|
<Match when={searchParams().by === 'rating'}>
|
||||||
<Row1 article={sortedArticles()[0]} />
|
<Row1 article={sortedArticles()[0]} />
|
||||||
<Row2 articles={sortedArticles().slice(1, 3)} isEqual={true} />
|
<Row2 articles={sortedArticles().slice(1, 3)} isEqual={true} />
|
||||||
|
|
|
@ -122,7 +122,7 @@ export const FeedView = () => {
|
||||||
<For each={topAuthors().slice(0, 5)}>
|
<For each={topAuthors().slice(0, 5)}>
|
||||||
{(author) => (
|
{(author) => (
|
||||||
<li>
|
<li>
|
||||||
<AuthorCard author={author} compact={true} hasLink={true} />
|
<AuthorCard author={author} hideWriteButton={true} hasLink={true} />
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
|
@ -153,7 +153,7 @@ export const FeedView = () => {
|
||||||
<AuthorCard
|
<AuthorCard
|
||||||
author={comment.createdBy as Author}
|
author={comment.createdBy as Author}
|
||||||
isFeedMode={true}
|
isFeedMode={true}
|
||||||
compact={true}
|
hideWriteButton={true}
|
||||||
hideFollow={true}
|
hideFollow={true}
|
||||||
/>
|
/>
|
||||||
<div class={clsx('text-truncate', styles.commentArticleTitle)}>
|
<div class={clsx('text-truncate', styles.commentArticleTitle)}>
|
||||||
|
|
|
@ -21,6 +21,7 @@ type Props = {
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
onSubmit: (value: string) => void
|
onSubmit: (value: string) => void
|
||||||
clear?: boolean
|
clear?: boolean
|
||||||
|
cancel?: () => void
|
||||||
initialContent?: string
|
initialContent?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +70,9 @@ const CommentEditor = (props: Props) => {
|
||||||
const clearEditor = () => {
|
const clearEditor = () => {
|
||||||
editorViewRef.current.destroy()
|
editorViewRef.current.destroy()
|
||||||
initEditor()
|
initEditor()
|
||||||
|
if (props.cancel) {
|
||||||
|
props.cancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
|
@ -76,7 +80,6 @@ const CommentEditor = (props: Props) => {
|
||||||
clearEditor()
|
clearEditor()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={styles.commentEditor}>
|
<div class={styles.commentEditor}>
|
||||||
<div class={clsx('ProseMirrorOverrides', styles.textarea)} ref={(el) => (editorElRef.current = el)} />
|
<div class={clsx('ProseMirrorOverrides', styles.textarea)} ref={(el) => (editorElRef.current = el)} />
|
||||||
|
|
|
@ -2,7 +2,7 @@ import type { JSX } from 'solid-js'
|
||||||
import { Header } from '../Nav/Header'
|
import { Header } from '../Nav/Header'
|
||||||
import { Footer } from '../Discours/Footer'
|
import { Footer } from '../Discours/Footer'
|
||||||
|
|
||||||
import { Show } from 'solid-js'
|
import { createEffect, createSignal, Show } from 'solid-js'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import '../../styles/app.scss'
|
import '../../styles/app.scss'
|
||||||
import styles from './PageLayout.module.scss'
|
import styles from './PageLayout.module.scss'
|
||||||
|
@ -10,6 +10,7 @@ import { Meta } from '@solidjs/meta'
|
||||||
|
|
||||||
type PageLayoutProps = {
|
type PageLayoutProps = {
|
||||||
headerTitle?: string
|
headerTitle?: string
|
||||||
|
slug?: string
|
||||||
articleBody?: string
|
articleBody?: string
|
||||||
cover?: string
|
cover?: string
|
||||||
children: JSX.Element
|
children: JSX.Element
|
||||||
|
@ -17,19 +18,29 @@ type PageLayoutProps = {
|
||||||
hideFooter?: boolean
|
hideFooter?: boolean
|
||||||
class?: string
|
class?: string
|
||||||
withPadding?: boolean
|
withPadding?: boolean
|
||||||
|
scrollToComments?: (value: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PageLayout = (props: PageLayoutProps) => {
|
export const PageLayout = (props: PageLayoutProps) => {
|
||||||
const isHeaderFixed = props.isHeaderFixed === undefined ? true : props.isHeaderFixed
|
const isHeaderFixed = props.isHeaderFixed === undefined ? true : props.isHeaderFixed
|
||||||
|
const [scrollToComments, setScrollToComments] = createSignal<boolean>(false)
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (props.scrollToComments) {
|
||||||
|
props.scrollToComments(scrollToComments())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Meta name="viewport" content="width=device-width, initial-scale=1" />
|
<Meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<Header
|
<Header
|
||||||
|
slug={props.slug}
|
||||||
title={props.headerTitle}
|
title={props.headerTitle}
|
||||||
articleBody={props.articleBody}
|
articleBody={props.articleBody}
|
||||||
cover={props.articleBody}
|
cover={props.articleBody}
|
||||||
isHeaderFixed={isHeaderFixed}
|
isHeaderFixed={isHeaderFixed}
|
||||||
|
scrollToComments={(value) => setScrollToComments(value)}
|
||||||
/>
|
/>
|
||||||
<main
|
<main
|
||||||
class={clsx('main-content', {
|
class={clsx('main-content', {
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.trigger {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.popup {
|
.popup {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
color: #000;
|
color: #000;
|
||||||
|
|
|
@ -37,7 +37,9 @@ export const Popup = (props: PopupProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span class={clsx(styles.container, props.containerCssClass)} ref={(el) => (containerRef.current = el)}>
|
<span class={clsx(styles.container, props.containerCssClass)} ref={(el) => (containerRef.current = el)}>
|
||||||
<span onClick={toggle}>{props.trigger}</span>
|
<span class={styles.trigger} onClick={toggle}>
|
||||||
|
{props.trigger}
|
||||||
|
</span>
|
||||||
<Show when={isVisible()}>
|
<Show when={isVisible()}>
|
||||||
<div
|
<div
|
||||||
class={clsx(styles.popup, props.popupCssClass, {
|
class={clsx(styles.popup, props.popupCssClass, {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { createMemo, onMount, Show } from 'solid-js'
|
import { createMemo, createSignal, onMount, Show } from 'solid-js'
|
||||||
import type { Shout } from '../graphql/types.gen'
|
import type { Shout } from '../graphql/types.gen'
|
||||||
import { PageLayout } from '../components/_shared/PageLayout'
|
import { PageLayout } from '../components/_shared/PageLayout'
|
||||||
import type { PageProps } from './types'
|
import type { PageProps } from './types'
|
||||||
|
@ -48,12 +48,21 @@ export const ArticlePage = (props: PageProps) => {
|
||||||
script.dataset.ackeeDomainId = '1004abeb-89b2-4e85-ad97-74f8d2c8ed2d'
|
script.dataset.ackeeDomainId = '1004abeb-89b2-4e85-ad97-74f8d2c8ed2d'
|
||||||
document.body.appendChild(script)
|
document.body.appendChild(script)
|
||||||
})
|
})
|
||||||
|
const [scrollToComments, setScrollToComments] = createSignal<boolean>(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayout headerTitle={article()?.title || ''} articleBody={article()?.body} cover={article()?.cover}>
|
<PageLayout
|
||||||
|
headerTitle={article()?.title || ''}
|
||||||
|
slug={article()?.slug}
|
||||||
|
articleBody={article()?.body}
|
||||||
|
cover={article()?.cover}
|
||||||
|
scrollToComments={(value) => {
|
||||||
|
setScrollToComments(value)
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ReactionsProvider>
|
<ReactionsProvider>
|
||||||
<Show when={Boolean(article())} fallback={<Loading />}>
|
<Show when={Boolean(article())} fallback={<Loading />}>
|
||||||
<FullArticle article={article()} />
|
<FullArticle article={article()} scrollToComments={scrollToComments()} />
|
||||||
</Show>
|
</Show>
|
||||||
</ReactionsProvider>
|
</ReactionsProvider>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user