add leads for feed (#167)

* add leads for feed

* Fix Media Items description autosave

* resolve conversation

---------

Co-authored-by: ilya-bkv <i.yablokov@ccmp.me>
This commit is contained in:
Arkadzi Rakouski 2023-08-17 19:00:53 +03:00 committed by GitHub
parent a877613d8e
commit 63c52ac6e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 50 deletions

View File

@ -71,7 +71,6 @@
&::before { &::before {
content: ''; content: '';
height: 100%;
left: 0; left: 0;
position: absolute; position: absolute;
top: 0; top: 0;
@ -181,6 +180,15 @@
} }
} }
.shoutCardLead {
@include font-size(1.6rem);
color: var(--secondary-color);
font-weight: 400;
line-height: 1.3;
margin-bottom: 1.4rem;
}
.shoutCardSubtitle { .shoutCardSubtitle {
@include font-size(1.8rem); @include font-size(1.8rem);
color: #141414; color: #141414;
@ -202,8 +210,8 @@
transition: background-color 0.2s, color 0.2s; transition: background-color 0.2s, color 0.2s;
&:hover { &:hover {
background: #000; background: var(--background-color-invert);
color: #fff; color: var(--default-color-invert);
} }
} }
@ -214,7 +222,7 @@
a, a,
.shoutCardTitle, .shoutCardTitle,
.shoutCardSubtitle { .shoutCardSubtitle {
color: #fff; color: var(--default-color-invert);
} }
.shoutCardCover { .shoutCardCover {
@ -247,14 +255,14 @@
z-index: 2; z-index: 2;
a:link { a:link {
background: #fff; background: var(--default-color-invert);
border-radius: 100%; border-radius: 100%;
display: block; display: block;
height: 100%; height: 100%;
width: 100%; width: 100%;
&:hover { &:hover {
background: #000; background: var(--background-color-invert);
.icon { .icon {
display: inline-block; display: inline-block;
@ -326,7 +334,7 @@
} }
.shoutCardSubtitle { .shoutCardSubtitle {
color: #fff; color: var(--background-color-invert);
} }
.shoutAuthor { .shoutAuthor {
@ -347,29 +355,29 @@
} }
a:hover { a:hover {
background-color: #fff !important; background-color: var(--background-color) !important;
} }
} }
a:link, a:link,
a:visited { a:visited {
color: #fff; color: var(--default-color-invert);
} }
a:hover { a:hover {
background: #fff; background: var(--background-color);
color: #000; color: var(--default-color);
} }
.shoutCardTitlesContainer { .shoutCardTitlesContainer {
a:link { a:link {
border: none; border: none;
color: #fff; color: var(--default-color-invert);
&:hover { &:hover {
.shoutCardTitle .shoutCardLinkContainer { .shoutCardTitle .shoutCardLinkContainer {
background-color: #fff; background-color: var(--background-color);
color: #000; color: var(--default-color);
} }
} }
} }
@ -411,7 +419,7 @@
a, a,
.shoutCardTitle, .shoutCardTitle,
.shoutCardSubtitle { .shoutCardSubtitle {
color: #fff !important; color: var(--default-color-invert) !important;
} }
.shoutAuthor, .shoutAuthor,
@ -419,8 +427,8 @@
a:hover { a:hover {
&, &,
.shoutCardTitle .shoutCardLinkContainer { .shoutCardTitle .shoutCardLinkContainer {
background-color: #fff; background-color: var(--background-color);
color: #000 !important; color: var(--default-color) !important;
} }
} }
} }
@ -466,8 +474,8 @@
&:link, &:link,
&:visited { &:visited {
&:hover { &:hover {
background: #fff !important; background: var(--background-color) !important;
color: #000 !important; color: var(--default-color) !important;
} }
} }
} }
@ -505,7 +513,7 @@
@include font-size(1.5rem); @include font-size(1.5rem);
align-items: flex-start; align-items: flex-start;
border-top: 2px solid #141414; border-top: 2px solid var(--black-500);
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
flex-wrap: wrap; flex-wrap: wrap;
@ -638,7 +646,7 @@
a:hover { a:hover {
.shoutCardLinkContainer { .shoutCardLinkContainer {
color: #fff; color: var(--default-color-invert);
} }
} }
} }
@ -693,7 +701,7 @@
} }
.shoutCardSubtitle { .shoutCardSubtitle {
color: #000; color: var(--default-color);
} }
.shoutCardTitle { .shoutCardTitle {
@ -708,7 +716,7 @@
a:hover { a:hover {
.shoutCardLinkContainer { .shoutCardLinkContainer {
color: #fff; color: var(--default-color-invert);
} }
} }
} }

View File

@ -78,14 +78,12 @@ export const ArticleCard = (props: ArticleCardProps) => {
const { title, subtitle } = getTitleAndSubtitle(props.article) const { title, subtitle } = getTitleAndSubtitle(props.article)
const { id, cover, layout, slug, authors, stat, body } = props.article const canEdit = () => props.article.authors?.some((a) => a.slug === user()?.slug)
const canEdit = () => authors?.some((a) => a.slug === user()?.slug)
const { changeSearchParam } = useRouter() const { changeSearchParam } = useRouter()
const scrollToComments = (event) => { const scrollToComments = (event) => {
event.preventDefault() event.preventDefault()
openPage(router, 'article', { slug }) openPage(router, 'article', { slug: props.article.slug })
changeSearchParam('scrollTo', 'comments') changeSearchParam('scrollTo', 'comments')
} }
@ -106,14 +104,14 @@ export const ArticleCard = (props: ArticleCardProps) => {
[styles.shoutCardCompact]: props.settings?.isCompact, [styles.shoutCardCompact]: props.settings?.isCompact,
[styles.shoutCardSingle]: props.settings?.isSingle, [styles.shoutCardSingle]: props.settings?.isSingle,
[styles.shoutCardBeside]: props.settings?.isBeside, [styles.shoutCardBeside]: props.settings?.isBeside,
[styles.shoutCardNoImage]: !cover [styles.shoutCardNoImage]: !props.article.cover
}} }}
> >
<Show when={!props.settings?.noimage && !props.settings?.isFeedMode}> <Show when={!props.settings?.noimage && !props.settings?.isFeedMode}>
<div class={styles.shoutCardCoverContainer}> <div class={styles.shoutCardCoverContainer}>
<div class={styles.shoutCardCover}> <div class={styles.shoutCardCover}>
<Show when={cover}> <Show when={props.article.cover}>
<img src={imageProxy(cover)} alt={title || ''} loading="lazy" /> <img src={imageProxy(props.article.cover)} alt={title || ''} loading="lazy" />
</Show> </Show>
</div> </div>
</div> </div>
@ -122,15 +120,15 @@ export const ArticleCard = (props: ArticleCardProps) => {
<div class={styles.shoutCardContent}> <div class={styles.shoutCardContent}>
<Show <Show
when={ when={
layout && props.article.layout &&
layout !== 'article' && props.article.layout !== 'article' &&
!(props.settings?.noicon || props.settings?.noimage) && !(props.settings?.noicon || props.settings?.noimage) &&
!props.settings?.isFeedMode !props.settings?.isFeedMode
} }
> >
<div class={styles.shoutCardType}> <div class={styles.shoutCardType}>
<a href={`/expo/${layout}`}> <a href={`/expo/${props.article.layout}`}>
<Icon name={layout} class={styles.icon} /> <Icon name={props.article.layout} class={styles.icon} />
{/*<Icon name={`${layout}-hover`} class={clsx(styles.icon, styles.iconHover)} />*/} {/*<Icon name={`${layout}-hover`} class={clsx(styles.icon, styles.iconHover)} />*/}
</a> </a>
</div> </div>
@ -153,7 +151,7 @@ export const ArticleCard = (props: ArticleCardProps) => {
[styles.shoutCardTitlesContainerFeedMode]: props.settings?.isFeedMode [styles.shoutCardTitlesContainerFeedMode]: props.settings?.isFeedMode
})} })}
> >
<a href={`/${slug || ''}`}> <a href={`/${props.article.slug || ''}`}>
<div class={styles.shoutCardTitle}> <div class={styles.shoutCardTitle}>
<span class={styles.shoutCardLinkWrapper}> <span class={styles.shoutCardLinkWrapper}>
<span class={styles.shoutCardLinkContainer}>{title}</span> <span class={styles.shoutCardLinkContainer}>{title}</span>
@ -166,6 +164,10 @@ export const ArticleCard = (props: ArticleCardProps) => {
</div> </div>
</Show> </Show>
</a> </a>
<Show when={props.article.lead}>
<div class={styles.shoutCardLead}>{props.article.lead}</div>
</Show>
</div> </div>
<Show when={!props.settings?.noauthor || !props.settings?.nodate}> <Show when={!props.settings?.noauthor || !props.settings?.nodate}>
@ -174,7 +176,7 @@ export const ArticleCard = (props: ArticleCardProps) => {
> >
<Show when={!props.settings?.noauthor}> <Show when={!props.settings?.noauthor}>
<div class={styles.shoutAuthor}> <div class={styles.shoutAuthor}>
<For each={authors}> <For each={props.article.authors}>
{(author) => { {(author) => {
return ( return (
<AuthorCard <AuthorCard
@ -196,22 +198,24 @@ export const ArticleCard = (props: ArticleCardProps) => {
</Show> </Show>
<Show when={props.settings?.isFeedMode}> <Show when={props.settings?.isFeedMode}>
<Show when={!props.settings?.noimage && cover}> <Show when={!props.settings?.noimage && props.article.cover}>
<div class={styles.shoutCardCoverContainer}> <div class={styles.shoutCardCoverContainer}>
<Show <Show
when={ when={
layout && layout !== 'article' && !(props.settings?.noicon || props.settings?.noimage) props.article.layout &&
props.article.layout !== 'article' &&
!(props.settings?.noicon || props.settings?.noimage)
} }
> >
<div class={styles.shoutCardType}> <div class={styles.shoutCardType}>
<a href={`/expo/${layout}`}> <a href={`/expo/${props.article.layout}`}>
<Icon name={layout} class={styles.icon} /> <Icon name={props.article.layout} class={styles.icon} />
{/*<Icon name={`${layout}-hover`} class={clsx(styles.icon, styles.iconHover)} />*/} {/*<Icon name={`${layout}-hover`} class={clsx(styles.icon, styles.iconHover)} />*/}
</a> </a>
</div> </div>
</Show> </Show>
<div class={styles.shoutCardCover}> <div class={styles.shoutCardCover}>
<img src={imageProxy(cover)} alt={title || ''} loading="lazy" /> <img src={imageProxy(props.article.cover)} alt={title || ''} loading="lazy" />
</div> </div>
</div> </div>
</Show> </Show>
@ -230,14 +234,16 @@ export const ArticleCard = (props: ArticleCardProps) => {
name="comment-hover" name="comment-hover"
class={clsx(styles.icon, styles.iconHover, styles.feedControlIcon)} class={clsx(styles.icon, styles.iconHover, styles.feedControlIcon)}
/> />
<span class={styles.shoutCardLinkContainer}>{stat?.commented || t('Add comment')}</span> <span class={styles.shoutCardLinkContainer}>
{props.article.stat?.commented || t('Add comment')}
</span>
</a> </a>
</div> </div>
<Show when={props.settings?.withViewed}> <Show when={props.settings?.withViewed}>
<div class={clsx(styles.shoutCardDetailsItem, styles.shoutCardDetailsViewed)}> <div class={clsx(styles.shoutCardDetailsItem, styles.shoutCardDetailsViewed)}>
<Icon name="eye" class={clsx(styles.icon, styles.feedControlIcon)} /> <Icon name="eye" class={clsx(styles.icon, styles.feedControlIcon)} />
{stat?.viewed} {props.article.stat?.viewed}
</div> </div>
</Show> </Show>
</div> </div>
@ -247,7 +253,7 @@ export const ArticleCard = (props: ArticleCardProps) => {
<Popover content={t('Edit')}> <Popover content={t('Edit')}>
{(triggerRef: (el) => void) => ( {(triggerRef: (el) => void) => (
<div class={styles.shoutCardDetailsItem} ref={triggerRef}> <div class={styles.shoutCardDetailsItem} ref={triggerRef}>
<a href={getPagePath(router, 'edit', { shoutId: id.toString() })}> <a href={getPagePath(router, 'edit', { shoutId: props.article.id.toString() })}>
<Icon name="pencil-outline" class={clsx(styles.icon, styles.feedControlIcon)} /> <Icon name="pencil-outline" class={clsx(styles.icon, styles.feedControlIcon)} />
<Icon <Icon
name="pencil-outline-hover" name="pencil-outline-hover"
@ -279,9 +285,9 @@ export const ArticleCard = (props: ArticleCardProps) => {
<SharePopup <SharePopup
containerCssClass={stylesHeader.control} containerCssClass={stylesHeader.control}
title={title} title={title}
description={getDescription(body)} description={getDescription(props.article.body)}
imageUrl={cover} imageUrl={props.article.cover}
shareUrl={getShareUrl({ pathname: `/${slug}` })} shareUrl={getShareUrl({ pathname: `/${props.article.slug}` })}
isVisible={(value) => setIsActionPopupActive(value)} isVisible={(value) => setIsActionPopupActive(value)}
trigger={ trigger={
<button> <button>
@ -302,9 +308,9 @@ export const ArticleCard = (props: ArticleCardProps) => {
isOwner={canEdit()} isOwner={canEdit()}
containerCssClass={stylesHeader.control} containerCssClass={stylesHeader.control}
title={title} title={title}
description={getDescription(body)} description={getDescription(props.article.body)}
imageUrl={cover} imageUrl={props.article.cover}
shareUrl={getShareUrl({ pathname: `/${slug}` })} shareUrl={getShareUrl({ pathname: `/${props.article.slug}` })}
isVisible={(value) => setIsActionPopupActive(value)} isVisible={(value) => setIsActionPopupActive(value)}
trigger={ trigger={
<button> <button>

View File

@ -44,6 +44,7 @@ export const FeedView = () => {
// state // state
const { sortedArticles } = useArticlesStore() const { sortedArticles } = useArticlesStore()
const { sortedAuthors } = useAuthorsStore() const { sortedAuthors } = useAuthorsStore()
const { topTopics } = useTopicsStore() const { topTopics } = useTopicsStore()
const { topAuthors } = useTopAuthorsStore() const { topAuthors } = useTopAuthorsStore()
@ -90,6 +91,7 @@ export const FeedView = () => {
const loadMore = async () => { const loadMore = async () => {
setIsLoading(true) setIsLoading(true)
const { hasMore, newShouts } = await loadFeedShouts() const { hasMore, newShouts } = await loadFeedShouts()
setIsLoading(false) setIsLoading(false)
loadReactionsBy({ loadReactionsBy({

View File

@ -9,6 +9,7 @@ export default gql`
slug slug
layout layout
cover cover
lead
# community # community
mainTopic mainTopic
topics { topics {