Feed placeholders

This commit is contained in:
kvakazyambra 2024-05-10 19:52:13 +03:00
parent 7d24fe5598
commit 6a789d4a0e
9 changed files with 288 additions and 92 deletions

View File

@ -106,9 +106,11 @@
"Create an account to subscribe": "Create an account to subscribe",
"Create an account to vote": "Create an account to vote",
"Create gallery": "Create gallery",
"Create own feed": "Создать свою ленту",
"Create post": "Create post",
"Create video": "Create video",
"Crop image": "Crop image",
"Current discussions": "Актуальные дискуссии",
"Culture": "Culture",
"Date of Birth": "Date of Birth",
"Decline": "Decline",
@ -154,6 +156,8 @@
"Feed": "Feed",
"Feedback": "Feedback",
"Fill email": "Fill email",
"Find co-authors": "Найти соавторов",
"Find collaborators": "Найдите соавторов и экспертов",
"Fixed": "Fixed",
"Follow the topic": "Follow the topic",
"Follow": "Follow",
@ -260,6 +264,7 @@
"Our regular contributor": "Our regular contributor",
"Paragraphs": "Абзацев",
"Participate in the Discours: share information, join the editorial team": "Участвуйте в Дискурсе: делитесь информацией, присоединяйтесь к редакции",
"Participate in discussions": "Участвуйте в дискуссиях",
"Participating": "Participating",
"Participation": "Participation",
"Partners": "Partners",
@ -273,6 +278,9 @@
"Paste Embed code": "Paste Embed code",
"Personal": "Personal",
"Pin": "Pin",
"Placeholder feed": "Подпишитесь на любимые темы, авторов и сообщества — моментально узнавайте о новых публикациях и обсуждениях",
"Placeholder feedCollaborations": "На платформе можно писать материалы вместе. Здесь появятся публикации, в которые вы внесли вклад",
"Placeholder feedDiscussions": "Дискурс — свободная платформа для осмысленного общения. Здесь появятся все ваши реплики, чтобы в любой момент вернуться к диалогу",
"Platform Guide": "Platform Guide",
"Please check your email address": "Please check your email address",
"Please confirm your email to finish": "Confirm your email and the action will complete",

View File

@ -110,10 +110,12 @@
"Create an account to subscribe": "Создайте аккаунт, чтобы подписаться",
"Create an account to vote": "Создайте аккаунт, чтобы голосовать",
"Create gallery": "Создать галерею",
"Create own feed": "Создать свою ленту",
"Create post": "Создать публикацию",
"Create video": "Создать видео",
"Crop image": "Кадрировать изображение",
"Culture": "Культура",
"Current discussions": "Актуальные дискуссии",
"Date of Birth": "Дата рождения",
"Decline": "Отмена",
"Delete cover": "Удалить обложку",
@ -160,6 +162,8 @@
"Feed": "Лента",
"Feedback": "Обратная связь",
"Fill email": "Введите почту",
"Find co-authors": "Найти соавторов",
"Find collaborators": "Найдите соавторов и экспертов",
"Fixed": "Все поправлено",
"Follow the topic": "Подписаться на тему",
"Follow": "Подписаться",
@ -272,6 +276,7 @@
"Our regular contributor": "Наш постоянный автор",
"Paragraphs": "Абзацев",
"Participate in the Discours: share information, join the editorial team": "Participate in the Discours: share information, join the editorial team",
"Participate in discussions": "Участвуйте в дискуссиях",
"Participating": "Участвовать",
"Participation": "Соучастие",
"Partners": "Партнёры",
@ -285,6 +290,9 @@
"Paste Embed code": "Вставьте embed код",
"Personal": "Личные",
"Pin": "Закрепить",
"Placeholder feed": "Подпишитесь на любимые темы, авторов и сообщества — моментально узнавайте о новых публикациях и обсуждениях",
"Placeholder feedCollaborations": "На платформе можно писать материалы вместе. Здесь появятся публикации, в которые вы внесли вклад",
"Placeholder feedDiscussions": "Дискурс — свободная платформа для осмысленного общения. Здесь появятся все ваши реплики, чтобы в любой момент вернуться к диалогу",
"Platform Guide": "Гид по дискурсу",
"Please check your email address": "Пожалуйста, проверьте введенный адрес почты",
"Please check your inbox! We have sent a password reset link.": "Пожалуйста, проверьте свою почту, мы отправили вам письмо со ссылкой для сброса пароля",

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

View File

@ -0,0 +1,117 @@
.placeholder {
aspect-ratio: 1 / 0.8;
border-radius: 2.2rem;
display: flex;
@include font-size(1.4rem);
flex-direction: column;
font-weight: 500;
overflow: hidden;
position: relative;
h3 {
@include font-size(2.4rem);
}
button,
.button {
border-radius: 1.2rem;
display: block;
@include font-size(1.5rem);
margin-top: 3rem;
padding: 1rem 2rem;
width: 100%;
}
}
.placeholderCover {
flex: 0 100%;
position: relative;
width: 100%;
&:after {
bottom: 0;
content: '';
height: 20%;
left: 0;
position: absolute;
width: 100%;
.placeholder-feed & {
background: linear-gradient(to top, #171032, rgba(23, 16, 50, 0));
}
.placeholder-feedCollaborations & {
background: linear-gradient(to top, #070709, rgba(7, 7, 9, 0));
}
.placeholder-feedDiscussions & {
//background: linear-gradient(to top, #E9E9EE, rgba(233, 233, 238, 0));
}
}
img {
left: 0;
height: 100%;
object-fit: cover;
position: absolute;
width: 100%;
}
}
.placeholderContent {
padding: 1.6rem;
text-align: center;
}
.placeholder-feed,
.placeholder-feedCollaborations {
color: var(--default-color-invert);
button,
.button {
background: var(--background-color);
color: var(--default-color);
}
}
.placeholder-feed {
background: #171032;
.placeholderCover {
img {
object-position: top;
}
}
}
.placeholder-feedCollaborations {
background: #070709;
.placeholderCover {
img {
object-position: bottom;
}
}
}
.placeholder-feedDiscussions {
background: #E9E9EE;
.placeholderCover {
padding: 2rem;
text-align: center;
img {
height: 90%;
mix-blend-mode: multiply;
object-fit: contain;
top: 10%;
}
}
button,
.button {
background: var(--background-color-invert);
color: var(--default-color-invert);
}
}

View File

@ -0,0 +1,59 @@
import { clsx } from 'clsx'
import { Show } from 'solid-js'
import { useLocalize } from '../../../context/localize'
import { useSession } from '../../../context/session'
import styles from './Placeholder.module.scss'
export type PlaceholderProps = {
type: 'feed' | 'feedCollaborations' | 'feedDiscussions'
}
export const Placeholder = (props: PlaceholderProps) => {
const { t } = useLocalize()
const { author } = useSession()
const data = {
feed: {
image: 'placeholder-feed.webp',
header: t('Feed settings'),
text: t('Placeholder feed'),
buttonLabel: author() ? t('Popular authors') : t('Create own feed'),
},
feedCollaborations: {
image: 'placeholder-experts.webp',
header: t('Find collaborators'),
text: t('Placeholder feedCollaborations'),
buttonLabel: t('Find co-authors'),
},
feedDiscussions: {
image: 'placeholder-discussions.webp',
header: t('Participate in discussions'),
text: t('Placeholder feedDiscussions'),
buttonLabel: author() ? t('Current discussions') : t('Enter'),
},
}
return (
<div class={clsx(styles.placeholder, styles[`placeholder-${props.type}`])}>
<div class={styles.placeholderCover}>
<img src={`/public/${data[props.type].image}`} />
</div>
<div class={styles.placeholderContent}>
<h3 innerHTML={data[props.type].header} />
<p innerHTML={data[props.type].text} />
<Show
when={author()}
fallback={
<a class={styles.button} href="?m=auth&mode=login">
{data[props.type].buttonLabel}
</a>
}
>
<button>{data[props.type].buttonLabel}</button>
</Show>
</div>
</div>
)
}

View File

@ -0,0 +1 @@
export { Placeholder } from './Placeholder'

View File

@ -20,6 +20,7 @@ import { getShareUrl } from '../../Article/SharePopup'
import { AuthorBadge } from '../../Author/AuthorBadge'
import { AuthorLink } from '../../Author/AuthorLink'
import { ArticleCard } from '../../Feed/ArticleCard'
import { Placeholder } from '../../Feed/Placeholder'
import { Sidebar } from '../../Feed/Sidebar'
import { Modal } from '../../Nav/Modal'
import { DropDown } from '../../_shared/DropDown'
@ -100,7 +101,7 @@ export const FeedView = (props: Props) => {
const { page, searchParams, changeSearchParams } = useRouter<FeedSearchParams>()
const [isLoading, setIsLoading] = createSignal(false)
const [isRightColumnLoaded, setIsRightColumnLoaded] = createSignal(false)
const { session } = useSession()
const { author, session } = useSession()
const { loadReactionsBy } = useReactions()
const { sortedArticles } = useArticlesStore()
const { topTopics } = useTopics()
@ -234,107 +235,109 @@ export const FeedView = (props: Props) => {
</div>
<div class="col-md-12 offset-xl-1">
<div class={styles.filtersContainer}>
<ul class={clsx('view-switcher', styles.feedFilter)}>
<li
class={clsx({
'view-switcher__item--selected':
searchParams().by === 'publish_date' || !searchParams().by,
})}
>
<a href={getPagePath(router, page().route)}>{t('Recent')}</a>
</li>
{/*<li>*/}
{/* <a href="/feed/?by=views">{t('Most read')}</a>*/}
{/*</li>*/}
<li
class={clsx({
'view-switcher__item--selected': searchParams().by === 'likes',
})}
>
<span class="link" onClick={() => changeSearchParams({ by: 'likes' })}>
{t('Top rated')}
</span>
</li>
<li
class={clsx({
'view-switcher__item--selected': searchParams().by === 'last_comment',
})}
>
<span class="link" onClick={() => changeSearchParams({ by: 'last_comment' })}>
{t('Most commented')}
</span>
</li>
</ul>
<div class={styles.dropdowns}>
<Show when={searchParams().by && searchParams().by !== 'publish_date'}>
<Show when={author() || !sortedArticles().length} fallback={<Placeholder type={page().route} />}>
<div class={styles.filtersContainer}>
<ul class={clsx('view-switcher', styles.feedFilter)}>
<li
class={clsx({
'view-switcher__item--selected':
searchParams().by === 'publish_date' || !searchParams().by,
})}
>
<a href={getPagePath(router, page().route)}>{t('Recent')}</a>
</li>
{/*<li>*/}
{/* <a href="/feed/?by=views">{t('Most read')}</a>*/}
{/*</li>*/}
<li
class={clsx({
'view-switcher__item--selected': searchParams().by === 'likes',
})}
>
<span class="link" onClick={() => changeSearchParams({ by: 'likes' })}>
{t('Top rated')}
</span>
</li>
<li
class={clsx({
'view-switcher__item--selected': searchParams().by === 'last_comment',
})}
>
<span class="link" onClick={() => changeSearchParams({ by: 'last_comment' })}>
{t('Most commented')}
</span>
</li>
</ul>
<div class={styles.dropdowns}>
<Show when={searchParams().by && searchParams().by !== 'publish_date'}>
<DropDown
popupProps={{ horizontalAnchor: 'right' }}
options={periods}
currentOption={currentPeriod()}
triggerCssClass={styles.periodSwitcher}
onChange={(period: PeriodItem) => changeSearchParams({ period: period.value })}
/>
</Show>
<DropDown
popupProps={{ horizontalAnchor: 'right' }}
options={periods}
currentOption={currentPeriod()}
options={visibilities}
currentOption={currentVisibility()}
triggerCssClass={styles.periodSwitcher}
onChange={(period: PeriodItem) => changeSearchParams({ period: period.value })}
onChange={(visibility: VisibilityItem) =>
changeSearchParams({ visibility: visibility.value })
}
/>
</Show>
<DropDown
popupProps={{ horizontalAnchor: 'right' }}
options={visibilities}
currentOption={currentVisibility()}
triggerCssClass={styles.periodSwitcher}
onChange={(visibility: VisibilityItem) =>
changeSearchParams({ visibility: visibility.value })
}
/>
</div>
</div>
</div>
<Show when={!isLoading()} fallback={<Loading />}>
<Show when={sortedArticles().length > 0}>
<For each={sortedArticles().slice(0, 4)}>
{(article) => (
<ArticleCard
onShare={(shared) => handleShare(shared)}
onInvite={() => showModal('inviteMembers')}
article={article}
settings={{ isFeedMode: true }}
desktopCoverSize="M"
/>
)}
</For>
<Show when={!isLoading()} fallback={<Loading />}>
<Show when={sortedArticles().length > 0}>
<For each={sortedArticles().slice(0, 4)}>
{(article) => (
<ArticleCard
onShare={(shared) => handleShare(shared)}
onInvite={() => showModal('inviteMembers')}
article={article}
settings={{ isFeedMode: true }}
desktopCoverSize="M"
/>
)}
</For>
<div class={styles.asideSection}>
<div class={stylesBeside.besideColumnTitle}>
<h4>{t('Popular authors')}</h4>
<a href="/authors">
{t('All authors')}
<Icon name="arrow-right" class={stylesBeside.icon} />
</a>
<div class={styles.asideSection}>
<div class={stylesBeside.besideColumnTitle}>
<h4>{t('Popular authors')}</h4>
<a href="/authors">
{t('All authors')}
<Icon name="arrow-right" class={stylesBeside.icon} />
</a>
</div>
<ul class={stylesBeside.besideColumn}>
<For each={topAuthors().slice(0, 5)}>
{(author) => (
<li>
<AuthorBadge author={author} />
</li>
)}
</For>
</ul>
</div>
<ul class={stylesBeside.besideColumn}>
<For each={topAuthors().slice(0, 5)}>
{(author) => (
<li>
<AuthorBadge author={author} />
</li>
)}
</For>
</ul>
</div>
<For each={sortedArticles().slice(4)}>
{(article) => (
<ArticleCard article={article} settings={{ isFeedMode: true }} desktopCoverSize="M" />
)}
</For>
</Show>
<For each={sortedArticles().slice(4)}>
{(article) => (
<ArticleCard article={article} settings={{ isFeedMode: true }} desktopCoverSize="M" />
)}
</For>
</Show>
<Show when={isLoadMoreButtonVisible()}>
<p class="load-more-container">
<button class="button" onClick={loadMore}>
{t('Load more')}
</button>
</p>
<Show when={isLoadMoreButtonVisible()}>
<p class="load-more-container">
<button class="button" onClick={loadMore}>
{t('Load more')}
</button>
</p>
</Show>
</Show>
</Show>
</div>