expo pages (#111)

* layout pages

* lint

* code review, lint, build fix

* lint
This commit is contained in:
Igor Lobanov 2023-06-16 16:47:24 +02:00 committed by GitHub
parent 03bcd7eced
commit 75c3d5faea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 249 additions and 229 deletions

View File

@ -56,11 +56,11 @@
"Create Chat": "Create Chat",
"Create Group": "Create a group",
"Create account": "Create an account",
"Create account from subscribe": "Create an account to subscribe to new publications",
"Create account from discussions": "Create an account to participate in discussions",
"Create account from vote": "Create an account to vote",
"Create account from bookmark": "Create an account to add to your bookmarks",
"Create account from discussions": "Create an account to participate in discussions",
"Create account from follow": "Create an account to subscribe",
"Create account from subscribe": "Create an account to subscribe to new publications",
"Create account from vote": "Create an account to vote",
"Create post": "Create post",
"Date of Birth": "Date of Birth",
"Delete": "Delete",
@ -69,6 +69,7 @@
"Discours is created with our common effort": "Discours exists because of our common effort",
"Discussing": "Discussing",
"Discussion rules": "Discussion rules",
"Discussions": "Discussions",
"Dogma": "Dogma",
"Drafts": "Drafts",
"Drag the image to this area": "Drag the image to this area",
@ -79,11 +80,11 @@
"Enter URL address": "Enter URL address",
"Enter text": "Enter text",
"Enter the Discours": "Enter the Discours",
"Enter the Discours from subscribe": "Sign in to subscribe to new publications",
"Enter the Discours from discussions": "Sign in to participate in the discussions",
"Enter the Discours from vote": "Sign in to vote",
"Enter the Discours from bookmark": "Sign in to add to bookmarks",
"Enter the Discours from discussions": "Sign in to participate in the discussions",
"Enter the Discours from follow": "Sign in to follow",
"Enter the Discours from subscribe": "Sign in to subscribe to new publications",
"Enter the Discours from vote": "Sign in to vote",
"Enter the code or click the link from email to confirm": "Enter the code from the email or follow the link in the email to confirm registration",
"Enter your new password": "Enter your new password",
"Error": "Error",
@ -115,6 +116,7 @@
"Highlight": "Highlight",
"Hooray! Welcome!": "Hooray! Welcome!",
"Horizontal collaborative journalistic platform": "Horizontal collaborative journalism platform",
"Hot topics": "Hot topics",
"Hotkeys": "Горячие клавиши",
"How can I help/skills": "How can I help/skills",
"How it works": "How it works",
@ -127,6 +129,7 @@
"Incut": "Incut",
"Independant magazine with an open horizontal cooperation about culture, science and society": "Independant magazine with an open horizontal cooperation about culture, science and society",
"Insert footnote": "Insert footnote",
"Insert video link": "Insert video link",
"Introduce": "Introduction",
"Invalid email": "Check if your email is correct",
"Invalid image URL": "Invalid image URL",
@ -149,6 +152,7 @@
"Load more": "Show more",
"Loading": "Loading",
"Logout": "Logout",
"Looks like you forgot to upload the video": "Looks like you forgot to upload the video",
"Manifest": "Manifest",
"Many files, choose only one": "Many files, choose only one",
"Material card": "Material card",
@ -165,6 +169,7 @@
"No such account, please try to register": "No such account found, please try to register",
"Nothing here yet": "There's nothing here yet",
"Nothing is here": "There is nothing here",
"Notifications": "Notifications",
"Or continue with social network": "Or continue with social network",
"Or paste a link to an image": "Or paste a link to an image",
"Ordered list": "Ordered list",
@ -256,7 +261,6 @@
"Top viewed": "Most viewed",
"Topic is supported by": "Topic is supported by",
"Topics": "Topics",
"Hot topics": "Hot topics",
"Topics which supported by author": "Topics which supported by author",
"Try to find another way": "Try to find another way",
"Unfollow": "Unfollow",
@ -305,7 +309,6 @@
"community": "community",
"delimiter": "delimiter",
"discussion": "discourse",
"Discussions": "Discussions",
"drafts": "drafts",
"email not confirmed": "email not confirmed",
"enter": "enter",
@ -322,7 +325,6 @@
"marker list": "marker list",
"music": "music",
"my feed": "my ribbon",
"Notifications": "Notifications",
"number list": "number list",
"personal data usage and email notifications": "to process personal data and receive email notifications",
"post": "post",
@ -336,7 +338,5 @@
"user already exist": "user already exists",
"video": "video",
"view": "view",
"zine": "zine",
"Insert video link": "Insert video link",
"Looks like you forgot to upload the video": "Looks like you forgot to upload the video"
"zine": "zine"
}

View File

@ -3,6 +3,7 @@
"A short introduction to keep the reader interested": "Небольшое вступление, чтобы заинтересовать читателя",
"About myself": "О себе",
"About the project": "О проекте",
"Accomplices": "Соучастники",
"Add another image": "Добавить другое изображение",
"Add comment": "Комментировать",
"Add image": "Добавить изображение",
@ -58,11 +59,11 @@
"Create Chat": "Создать чат",
"Create Group": "Создать группу",
"Create account": "Создать аккаунт",
"Create account from subscribe": "Создайте аккаунт для подписки на новые публикации",
"Create account from discussions": "Создайте аккаунт для участия в дискуссиях",
"Create account from vote": "Создайте аккаунт, чтобы голосовать",
"Create account from bookmark": "Создайте аккаунт, чтобы добавить в закладки",
"Create account from discussions": "Создайте аккаунт для участия в дискуссиях",
"Create account from follow": "Создайте аккаунт, чтобы подписаться",
"Create account from subscribe": "Создайте аккаунт для подписки на новые публикации",
"Create account from vote": "Создайте аккаунт, чтобы голосовать",
"Create post": "Создать публикацию",
"Date of Birth": "Дата рождения",
"Delete": "Удалить",
@ -71,6 +72,7 @@
"Discours is created with our common effort": "Дискурс существует благодаря нашему общему вкладу",
"Discussing": "Обсуждаемое",
"Discussion rules": "Правила сообществ самиздата в соцсетях",
"Discussions": "Дискуссии",
"Dogma": "Догма",
"Drafts": "Черновики",
"Drag the image to this area": "Перетащите изображение в эту область",
@ -82,11 +84,11 @@
"Enter URL address": "Введите адрес ссылки",
"Enter text": "Введите текст",
"Enter the Discours": "Войти в Дискурс",
"Enter the Discours from subscribe": "Войдите для подписки на новые публикации",
"Enter the Discours from discussions": "Войдите для участия в дискуссиях",
"Enter the Discours from vote": "Войдите, чтобы голосовать",
"Enter the Discours from bookmark": "Войдите, чтобы добавить в закладки",
"Enter the Discours from discussions": "Войдите для участия в дискуссиях",
"Enter the Discours from follow": "Войдите, чтобы подписаться",
"Enter the Discours from subscribe": "Войдите для подписки на новые публикации",
"Enter the Discours from vote": "Войдите, чтобы голосовать",
"Enter the code or click the link from email to confirm": "Введите код из письма или пройдите по ссылке в письме для подтверждения регистрации",
"Enter your new password": "Введите новый пароль",
"Error": "Ошибка",
@ -120,6 +122,7 @@
"Highlight": "Подсветка",
"Hooray! Welcome!": "Ура! Добро пожаловать!",
"Horizontal collaborative journalistic platform": "Горизонтальная платформа для коллаборативной журналистики",
"Hot topics": "Горячие темы",
"Hotkeys": "Горячие клавиши",
"How can I help/skills": "Чем могу помочь/навыки",
"How it works": "Как это работает",
@ -132,6 +135,7 @@
"Incut": "Подверстка",
"Independant magazine with an open horizontal cooperation about culture, science and society": "Независимый журнал с открытой горизонтальной редакцией о культуре, науке и обществе",
"Insert footnote": "Вставить сноску",
"Insert video link": "Вставить ссылку на видео",
"Introduce": "Представление",
"Invalid email": "Проверьте правильность ввода почты",
"Invalid image URL": "Некорректная ссылка на изображение",
@ -156,6 +160,7 @@
"Load more": "Показать ещё",
"Loading": "Загрузка",
"Logout": "Выход",
"Looks like you forgot to upload the video": "Похоже, что вы забыли загрузить видео",
"Manifest": "Манифест",
"Many files, choose only one": "Много файлов, выберете один",
"Material card": "Карточка материала",
@ -172,6 +177,7 @@
"No such account, please try to register": "Такой адрес не найден, попробуйте зарегистрироваться",
"Nothing here yet": "Здесь пока ничего нет",
"Nothing is here": "Здесь ничего нет",
"Notifications": "Уведомления",
"Or continue with social network": "Или войдите через соцсеть",
"Or paste a link to an image": "Или вставьте ссылку на изображение",
"Ordered list": "Нумерованный список",
@ -255,7 +261,7 @@
"Thank you": "Благодарности",
"This comment has not yet been rated": "Этот комментарий еще пока никто не оценил",
"This email is already taken. If it's you": "Такой email уже зарегистрирован. Если это вы",
"This functionality is currently not available, we would like to work on this issue. Use the download link.": "В данный момент этот функционал не доступен, бы работаем над этой проблемой. Воспользуйтесь загрузкой по ссылке.",
"This functionality is currently not available, we would like to work on this issue. Use the download link.": "В данный момент этот функционал недоступен, мы работаем над этой проблемой. Воспользуйтесь загрузкой по ссылке.",
"This post has not been rated yet": "Эту публикацию еще пока никто не оценил",
"To leave a comment please": "Чтобы оставить комментарий, необходимо",
"To write a comment, you must": "Чтобы написать комментарий, необходимо",
@ -269,7 +275,6 @@
"Top viewed": "Самое читаемое",
"Topic is supported by": "Тему поддерживают",
"Topics": "Темы",
"Hot topics": "Горячие темы",
"Topics which supported by author": "Автор поддерживает темы",
"Try to find another way": "Попробуйте найти по-другому",
"Unfollow": "Отписаться",
@ -304,7 +309,6 @@
"You've reached a non-existed page": "Вы попали на несуществующую страницу",
"You've successfully logged out": "Вы успешно вышли из аккаунта",
"Your name will appear on your profile page and as your signature in publications, comments and responses.": "Ваше имя появится на странице вашего профиля и как ваша подпись в публикациях, комментариях и откликах",
"Accomplices": "Соучастники",
"actions": "действия",
"add link": "добавить ссылку",
"all topics": "все темы",
@ -323,7 +327,6 @@
"delimiter": "разделитель",
"discourse_theme": "Тема дискурса",
"discussion": "дискурс",
"Discussions": "Дискуссии",
"drafts": "черновики",
"email not confirmed": "email не подтвержден",
"enter": "войдите",
@ -340,7 +343,6 @@
"marker list": "маркир. список",
"music": "музыка",
"my feed": "моя лента",
"Notifications": "Уведомления",
"number list": "нумер. список",
"or": "или",
"personal data usage and email notifications": "на обработку персональных данных и на получение почтовых уведомлений",
@ -358,7 +360,5 @@
"user already exist": "пользователь уже существует",
"video": "видео",
"view": "просмотр",
"zine": "журнал",
"Insert video link": "Вставить ссылку на видео",
"Looks like you forgot to upload the video": "Похоже, что вы забыли загрузить видео"
"zine": "журнал"
}

View File

@ -1,5 +1,6 @@
h1 {
@include font-size(4rem);
line-height: 1.1;
margin-top: 0.5em;
}
@ -154,6 +155,7 @@ img {
.shoutStatsItem {
@include font-size(1.5rem);
font-weight: 500;
display: inline-block;
margin: 0 6% 1em 0;

View File

@ -170,8 +170,9 @@
}
.articleLink {
flex: 0 0 50%;
@include font-size(1.2rem);
flex: 0 0 50%;
margin-right: 2em;
@include media-breakpoint-down(md) {

View File

@ -5,7 +5,6 @@ import { Show, createMemo, createSignal, For, lazy, Suspense } from 'solid-js'
import { clsx } from 'clsx'
import type { Author, Reaction } from '../../graphql/types.gen'
import MD from './MD'
import { formatDate } from '../../utils'
import Userpic from '../Author/Userpic'
import { useSession } from '../../context/session'
import { ReactionKind } from '../../graphql/types.gen'
@ -78,9 +77,6 @@ export const Comment = (props: Props) => {
}
}
const formattedDate = (date) =>
createMemo(() => formatDate(new Date(date), { hour: 'numeric', minute: 'numeric' }))
const toggleEditMode = () => {
setEditMode((oldEditMode) => !oldEditMode)
}

View File

@ -1,4 +1,6 @@
.commentDates {
@include font-size(1.2rem);
flex: 1;
display: flex;
gap: 1rem;
@ -7,7 +9,6 @@
font-size: 1.2rem;
margin: 0 1em 4px 0;
color: rgb(0 0 0 / 30%);
@include font-size(1.2rem);
.date {
.icon {

View File

@ -1,6 +1,6 @@
import styles from './CommentDate.module.scss'
import { Icon } from '../_shared/Icon'
import { Show, createMemo } from 'solid-js'
import { Show } from 'solid-js'
import type { Reaction } from '../../graphql/types.gen'
import { formatDate } from '../../utils'
import { useLocalize } from '../../context/localize'
@ -15,10 +15,13 @@ type Props = {
export const CommentDate = (props: Props) => {
const { t } = useLocalize()
const formattedDate = (date) =>
props.isShort
? formatDate(new Date(date), { month: 'long', day: 'numeric', year: 'numeric' })
: createMemo(() => formatDate(new Date(date), { hour: 'numeric', minute: 'numeric' }))
const formattedDate = (date) => {
const formatDateOptions: Intl.DateTimeFormatOptions = props.isShort
? { month: 'long', day: 'numeric', year: 'numeric' }
: { hour: 'numeric', minute: 'numeric' }
return formatDate(new Date(date), formatDateOptions)
}
return (
<div class={clsx(styles.commentDates, { [styles.commentDatesLastInRow]: props.isLastInRow })}>

View File

@ -13,7 +13,6 @@ import { FollowingEntity } from '../../graphql/types.gen'
import { router, useRouter } from '../../stores/router'
import { openPage } from '@nanostores/router'
import { useLocalize } from '../../context/localize'
import { init } from 'i18next'
interface AuthorCardProps {
caption?: string

View File

@ -1,5 +1,6 @@
.discoursFooter {
@include font-size(1.7rem);
background: #000;
color: rgb(255 255 255 / 64%);
padding: 2.4rem 0 4.2rem;

View File

@ -1,10 +1,10 @@
@mixin input-placeholder-overflow($direction: 'down') {
@if $direction == 'down' {
@media (max-width: 1410px) {
@media (width <= 1410px) {
@content;
}
} @else if $direction == 'up' {
@media (min-width: 1411px) {
@media (width > 1410px) {
@content;
}
} @else {
@ -38,7 +38,7 @@
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
padding: 0.2em 0.5em 0.2em 0.5em;
padding: 0.2em 0.5em;
width: 100%;
outline: none;
border: 1px solid #fff;

View File

@ -1,6 +1,5 @@
import type { Editor } from '@tiptap/core'
import styles from './BubbleMenu.module.scss'
import { clsx } from 'clsx'
import { Icon } from '../../_shared/Icon'
import { useLocalize } from '../../../context/localize'
import { Popover } from '../../_shared/Popover'

View File

@ -73,22 +73,23 @@
&.yellow {
background: #f6e3a1;
}
&.white {
background: #fff;
box-shadow: inset 0 0 0 1px #000;
border-color: #fff;
}
&.yellow {
background: #f6e3a1;
}
&.pink {
background: #f1b5bc;
}
&.green {
background: #bfe9cb;
box-shadow: inset 0 0 0 1px #000;
border-color: #fff;
}
&.black {
background: #000;
}

View File

@ -1,6 +1,5 @@
import type { Editor } from '@tiptap/core'
import styles from './BubbleMenu.module.scss'
import { clsx } from 'clsx'
import { Icon } from '../../_shared/Icon'
import { useLocalize } from '../../../context/localize'
import { Popover } from '../../_shared/Popover'

View File

@ -112,7 +112,7 @@
}
.backToMenuControl {
color: rgb(255 255 255 / 0.7);
color: rgb(255 255 255 / 70%);
}
.shortcutList {

View File

@ -76,11 +76,13 @@ mark.highlight {
[data-float] {
max-width: 50%;
}
[data-float='left'] {
max-width: 30%;
float: left;
margin: 1rem 1rem 0 0;
}
[data-float='right'] {
max-width: 30%;
float: right;
@ -93,11 +95,12 @@ mark.highlight {
float: left;
margin: 1rem 1rem 0;
}
[data-float='half-right'] {
max-width: 50%;
min-width: 30%;
float: right;
margin: 1rem 0 1rem;
margin: 1rem 0;
}
.ProseMirror blockquote {
@ -162,16 +165,20 @@ mark.highlight {
background: #000;
color: #fff;
}
&[data-bg='yellow'] {
background: #f6e3a1;
}
&[data-bg='pink'] {
background: #f1b5bc;
}
&[data-bg='green'] {
background: #bfe9cb;
box-shadow: 0 0 0 1px #000;
}
&[data-bg='white'] {
background: #fff;
box-shadow: 0 0 0 1px #000;

View File

@ -2,7 +2,7 @@
margin: 2rem 0;
.dropArea {
border: 2px dashed rgba(38, 56, 217, 0.3);
border: 2px dashed rgb(38 56 217 / 30%);
border-radius: 16px;
color: #2638d9;
display: flex;

View File

@ -1,5 +1,4 @@
import { Blockquote } from '@tiptap/extension-blockquote'
import { Command } from '@tiptap/core'
export type QuoteTypes = 'quote' | 'punchline'

View File

@ -42,7 +42,7 @@
a:link {
border: none;
&:before {
&::before {
content: '';
height: 100%;
left: 0;
@ -118,6 +118,7 @@
.shoutCardTitle {
@include font-size(2.2rem);
font-weight: 700;
line-height: 1.1;
margin-bottom: 0.8rem;
@ -138,8 +139,9 @@
}
.shoutCardSubtitle {
color: #141414;
@include font-size(1.8rem);
color: #141414;
font-weight: 400;
line-height: 1.3;
margin-bottom: 1.4rem;
@ -269,6 +271,7 @@
.shoutCardTitle,
.shoutCardSubtitle {
@include font-size(2.6rem);
display: inline;
line-height: 1.2;
}
@ -324,11 +327,11 @@
}
.shoutCardSubtitle {
color: rgb(255 255 255 / 0.5);
color: rgb(255 255 255 / 50%);
}
&:global(.swiper-slide-active) .shoutCardCover {
&:after {
&::after {
background: linear-gradient(to bottom, rgb(0 0 0 / 0%) 40%, rgb(0 0 0 / 70%) 100%);
}
}
@ -336,7 +339,7 @@
.shoutCardWithCover {
aspect-ratio: 16/9;
padding: 0 2.4rem 0;
padding: 0 2.4rem;
width: 100%;
@include media-breakpoint-down(sm) {
@ -561,7 +564,7 @@
}
.shoutDate {
color: rgb(255 255 255 / 0.5);
color: rgb(255 255 255 / 50%);
}
}
@ -596,6 +599,7 @@
.shoutCardBigTitle {
.shoutCardTitle {
@include font-size(3.2rem);
display: block;
padding-right: 0;
}
@ -609,6 +613,7 @@
.shoutCardTitle,
.shoutCardSubtitle {
@include font-size(2.2rem);
display: inline;
line-height: 1.2;
}
@ -634,8 +639,9 @@
.shoutCardTitle,
.shoutCardSubtitle {
display: inline;
@include font-size(1.8rem);
display: inline;
}
.shoutCardSubtitle {
@ -705,12 +711,14 @@
.shoutCardTitle {
@include font-size(4rem);
font-weight: 900;
line-height: 1.1;
}
.shoutCardSubtitle {
@include font-size(2.4rem);
flex: 1;
}
}

View File

@ -68,8 +68,9 @@
}
a:link {
border: none;
@include font-size(1.4rem);
border: none;
font-weight: bold;
padding-right: 0.3em;
white-space: nowrap;
@ -87,6 +88,7 @@
h4 {
@include font-size(2.6rem);
font-weight: bold;
padding-right: 1em;
}

View File

@ -18,6 +18,7 @@
.counter {
@include font-size(1.2rem);
align-items: center;
align-self: flex-start;
background: #f6f6f6;
@ -89,6 +90,7 @@
h4 {
@include font-size(1.2rem);
font-weight: bold;
color: #9fa1a7;
cursor: pointer;

View File

@ -87,6 +87,7 @@
.disclaimer {
@include font-size(1.2rem);
color: #9fa1a7;
margin-bottom: 0;
}
@ -127,13 +128,15 @@
}
.authLink {
cursor: pointer;
@include font-size(1.6rem);
cursor: pointer;
font-weight: 500;
}
.authSubtitle {
@include font-size(1.5rem);
margin-bottom: 1em;
}

View File

@ -7,6 +7,7 @@
.text {
@include font-size(1.5rem);
font-weight: 500;
margin-bottom: 1em;
text-align: center;

View File

@ -1,5 +1,6 @@
.subnavigation {
@include font-size(1.4rem);
height: 6rem;
line-height: 6rem;
margin-bottom: 5rem !important;

View File

@ -35,6 +35,7 @@
.topicTitle {
@include font-size(2.2rem);
font-weight: bold;
margin-bottom: 1.2rem;
margin-top: 0.5rem !important;
@ -59,6 +60,7 @@
.topicDescription {
@include font-size(1.4rem);
font-weight: 500;
color: #696969;
line-height: 1.3;
@ -74,6 +76,7 @@
.topicDetails {
@include font-size(1.6rem);
color: #9fa1a7;
display: flex;
margin-bottom: 1em;
@ -85,6 +88,7 @@
.topicDetailsItem {
@include font-size(1.4rem);
margin-right: 1.6rem;
white-space: nowrap;

View File

@ -5,8 +5,9 @@
text-align: center;
h1 {
color: #2638d9;
@include font-size(2rem);
color: #2638d9;
text-transform: uppercase;
}
}

View File

@ -1,4 +1,4 @@
import { createMemo, createSignal, For, onCleanup, onMount, Show } from 'solid-js'
import { createSignal, For, onCleanup, onMount, Show } from 'solid-js'
import { useLocalize } from '../../context/localize'
import { clsx } from 'clsx'
import { Title } from '@solidjs/meta'

View File

@ -4,6 +4,7 @@
.feedNavigation {
@include font-size(1.6rem);
font-weight: 500;
h4 {
@ -39,6 +40,7 @@
.feedAside {
h4 {
@include font-size(2.2rem);
font-weight: bold;
margin-bottom: 2.4rem;
}
@ -51,9 +53,10 @@
}
.topic {
@include font-size(1.2rem);
background: transparentize(#2638d9, 0.95);
display: inline-block;
@include font-size(1.2rem);
font-weight: bold;
line-height: 3.4rem;
margin: 0 0.6rem 0.6rem 0;
@ -88,6 +91,7 @@
ul {
@include font-size(1.4rem);
font-weight: bold;
margin: 1rem 0 0;
line-height: 1.3;
@ -97,7 +101,7 @@
padding-left: 2.6rem;
position: relative;
&:before {
&::before {
background: url(/public/icons/knowledge-base-bullet.svg) no-repeat;
content: '';
height: 1.6rem;
@ -140,6 +144,7 @@
.commentBody {
@include font-size(1.4rem);
margin-bottom: 1.2rem;
line-clamp: 3;
-webkit-line-clamp: 3;
@ -155,7 +160,7 @@
-webkit-line-clamp: 1;
a {
color: rgb(0 0 0 / 0.65);
color: rgb(0 0 0 / 65%);
&:hover {
color: #fff;
@ -166,5 +171,6 @@
.commentArticleTitle,
.commentAuthor {
@include font-size(1.2rem);
font-weight: 500;
}

View File

@ -6,7 +6,7 @@
position: relative;
width: 4.6rem;
&:before {
&::before {
background: #fff;
border-radius: 100%;
content: '';
@ -41,14 +41,14 @@
padding: 0;
position: relative;
&:before {
&::before {
display: none;
}
}
&:checked + label {
.switcher {
&:before {
&::before {
left: 2.4rem;
}
}

View File

@ -2,7 +2,7 @@ import { clsx } from 'clsx'
import styles from './DarkModeToggle.module.scss'
import { Icon } from '../Icon'
import { useLocalize } from '../../../context/localize'
import { createEffect, createSignal, onCleanup, onMount } from 'solid-js'
import { createSignal, onCleanup, onMount } from 'solid-js'
import { createPrefersDark } from '@solid-primitives/media'
type Props = {

View File

@ -59,7 +59,7 @@
line-height: 1;
user-select: none;
transition: opacity 0.3s ease-in-out;
background: rgba(255, 255, 255, 0.8);
background: rgb(255 255 255 / 80%);
&.visible {
opacity: 1;

View File

@ -1,5 +1,6 @@
.statMetrics {
@include font-size(1.7rem);
color: #9fa1a7;
display: flex;
margin: 0 0 1em;

View File

@ -11,6 +11,7 @@
flex-direction: row;
margin-top: auto;
}
.deleteAction {
position: absolute;
top: -15px;

View File

@ -1,5 +1,13 @@
import { Accessor, JSX, Resource, createEffect } from 'solid-js'
import { createContext, createMemo, createResource, createSignal, onMount, useContext } from 'solid-js'
import type { Accessor, JSX, Resource } from 'solid-js'
import {
createEffect,
createContext,
createMemo,
createResource,
createSignal,
onMount,
useContext
} from 'solid-js'
import type { AuthResult, User } from '../graphql/types.gen'
import { apiClient } from '../utils/apiClient'
import { resetToken, setToken } from '../graphql/privateGraphQLClient'

View File

@ -1,4 +1,4 @@
import { createEffect, createMemo, createSignal, lazy, onMount, Show, Suspense } from 'solid-js'
import { createMemo, createSignal, lazy, onMount, Show, Suspense } from 'solid-js'
import { PageLayout } from '../components/_shared/PageLayout'
import { Loading } from '../components/_shared/Loading'
import { useSession } from '../context/session'

View File

@ -1,11 +1,12 @@
import type { PageContext } from '../renderer/types'
import { apiClient } from '../utils/apiClient'
import type { PageProps } from './types'
import { PRERENDERED_ARTICLES_COUNT } from './layoutShouts.page'
export const onBeforeRender = async (pageContext: PageContext) => {
const { layout } = pageContext.routeParams
const layoutShouts = await apiClient.getShouts({ filters: { layout }, limit: 50 })
const layoutShouts = await apiClient.getShouts({ filters: { layout }, limit: PRERENDERED_ARTICLES_COUNT })
const pageProps: PageProps = { layoutShouts }

View File

@ -1,9 +1,8 @@
import { PageLayout } from '../components/_shared/PageLayout'
import type { PageProps } from './types'
import { createMemo, createSignal, For, onCleanup, onMount, Show } from 'solid-js'
import { loadShouts, resetSortedArticles } from '../stores/zine/articles'
import { useRouter } from '../stores/router'
import { LayoutType, useLayoutsStore } from '../stores/zine/layouts'
import type { LayoutType, PageProps } from './types'
import { createEffect, createMemo, createSignal, For, onCleanup, onMount, Show } from 'solid-js'
import { loadShouts, resetSortedArticles, useArticlesStore } from '../stores/zine/articles'
import { router, useRouter } from '../stores/router'
import { Loading } from '../components/_shared/Loading'
import { restoreScrollPosition, saveScrollPosition } from '../utils/scroll'
import type { Shout } from '../graphql/types.gen'
@ -18,42 +17,38 @@ import { Row1 } from '../components/Feed/Row1'
import styles from '../styles/Topic.module.scss'
import { ArticleCard } from '../components/Feed/ArticleCard'
import { useLocalize } from '../context/localize'
import { getPagePath } from '@nanostores/router'
import { Title } from '@solidjs/meta'
export const PRERENDERED_ARTICLES_COUNT = 21
export const PRERENDERED_ARTICLES_COUNT = 27
const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3
export const LayoutShoutsPage = (props: PageProps) => {
const { t } = useLocalize()
const getLayout = createMemo<LayoutType>(() => {
const { page: getPage } = useRouter()
const page = getPage()
if (page.route !== 'expo') {
throw new Error('ts guard')
}
const { layout } = page.params
const getLayout = createMemo<LayoutType>(() => {
const layout = getPage().params['layout']
return layout as LayoutType
})
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
const { sortedLayoutShouts, loadLayoutShoutsBy } = useLayoutsStore(getLayout(), props.layoutShouts)
const sortedArticles = createMemo<Shout[]>(() => sortedLayoutShouts().get(getLayout()) || [])
const loadMoreLayout = async (_kind: LayoutType) => {
saveScrollPosition()
const { hasMore } = await loadLayoutShoutsBy({
// filters: { layout: kind },
limit: LOAD_MORE_PAGE_SIZE,
const { sortedArticles } = useArticlesStore({
shouts: props.layoutShouts
})
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
const loadMore = async (count) => {
saveScrollPosition()
const { hasMore } = await loadShouts({
filters: { layout: getLayout() },
limit: count,
offset: sortedArticles().length
})
setIsLoadMoreButtonVisible(hasMore)
restoreScrollPosition()
}
onMount(async () => {
if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) {
loadMoreLayout(getLayout())
}
})
const title = createMemo(() => {
const l = getLayout()
if (l === 'audio') return t('Audio')
@ -65,61 +60,79 @@ export const LayoutShoutsPage = (props: PageProps) => {
const pages = createMemo<Shout[][]>(() =>
splitToPages(sortedArticles(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE)
)
const isLoaded = createMemo(() => Boolean(sortedArticles()))
onMount(async () => {
if (!isLoaded()) {
await loadShouts({ filters: { layout: getLayout() }, limit: PRERENDERED_ARTICLES_COUNT, offset: 0 })
const isLoaded = createMemo(() => Boolean(props.layoutShouts))
onMount(() => {
if (isLoaded()) {
return
}
loadMore(PRERENDERED_ARTICLES_COUNT + LOAD_MORE_PAGE_SIZE)
})
onMount(() => {
if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) {
loadMore(LOAD_MORE_PAGE_SIZE)
}
})
onCleanup(() => resetSortedArticles())
createEffect((prevLayout) => {
if (prevLayout !== getLayout()) {
resetSortedArticles()
loadMore(PRERENDERED_ARTICLES_COUNT + LOAD_MORE_PAGE_SIZE)
}
return getLayout()
}, getLayout())
onCleanup(() => {
resetSortedArticles()
})
const handleLoadMoreClick = () => {
loadMore(LOAD_MORE_PAGE_SIZE)
}
return (
<PageLayout>
<Title>{title()}</Title>
<Show when={isLoaded()} fallback={<Loading />}>
<div class={styles.topicPage}>
<Show when={getLayout()}>
<div class="wide-container">
<h1>{title()}</h1>
</div>
const ModeSwitcher = () => (
<div class="wide-container">
<div class={clsx(styles.groupControls, 'row group__controls')}>
<div class="col-md-16">
<ul class="view-switcher">
<li classList={{ 'view-switcher__item--selected': getLayout() === 'audio' }}>
<a href="/expo/audio">{t('Audio')}</a>
<a href={getPagePath(router, 'expo', { layout: 'audio' })}>{t('Audio')}</a>
</li>
<li classList={{ 'view-switcher__item--selected': getLayout() === 'video' }}>
<a href="/expo/video">{t('Video')}</a>
<a href={getPagePath(router, 'expo', { layout: 'video' })}>{t('Video')}</a>
</li>
<li classList={{ 'view-switcher__item--selected': getLayout() === 'image' }}>
<a href="/expo/image">{t('Artworks')}</a>
<a href={getPagePath(router, 'expo', { layout: 'image' })}>{t('Artworks')}</a>
</li>
<li classList={{ 'view-switcher__item--selected': getLayout() === 'literature' }}>
<a href="/expo/literature">{t('Literature')}</a>
<a href={getPagePath(router, 'expo', { layout: 'literature' })}>{t('Literature')}</a>
</li>
</ul>
</div>
<div class="col-md-8">
<div class="mode-switcher">
{`${t('Show')} `}
<span class="mode-switcher__control">{t('All posts')}</span>
</div>
</div>
</div>
</div>
)
return (
<PageLayout>
<Show when={isLoaded()} fallback={<Loading />}>
<div class={styles.topicPage}>
<Show when={getLayout() && Boolean(sortedArticles())}>
<div class="wide-container">
<h1>{title()}</h1>
</div>
<ModeSwitcher />
<Show when={sortedArticles().length > 0} fallback={<Loading />}>
<Row1 article={sortedArticles()[0]} />
<Row2 articles={sortedArticles().slice(1, 3)} />
<Slider title={title()}>
<For each={sortedArticles().slice(5, 11)}>
{(a: Shout) => (
{(article) => (
<ArticleCard
article={a}
article={article}
settings={{
additionalClass: 'swiper-slide',
isFloorImportant: true,
@ -156,12 +169,13 @@ export const LayoutShoutsPage = (props: PageProps) => {
<Show when={isLoadMoreButtonVisible()}>
<p class="load-more-container">
<button class="button" onClick={() => loadMoreLayout(getLayout())}>
<button class="button" onClick={handleLoadMoreClick}>
{t('Load more')}
</button>
</p>
</Show>
</Show>
</Show>
</div>
</Show>
</PageLayout>

View File

@ -1,6 +1,5 @@
// in a separate file to avoid circular dependencies
import type { Author, Chat, Shout, Topic } from '../graphql/types.gen'
import type { LayoutType } from '../stores/zine/layouts'
// all the things (she said) that could be passed from the server
export type PageProps = {
@ -15,7 +14,7 @@ export type PageProps = {
topic?: Topic
allTopics?: Topic[]
searchQuery?: string
layout?: LayoutType
layout?: string // LayoutType
// other types?
searchResults?: Shout[]
chats?: Chat[]
@ -32,3 +31,5 @@ export type UploadFile = {
size: number
file: File
}
export type LayoutType = 'article' | 'audio' | 'video' | 'image' | 'literature'

View File

@ -1,48 +0,0 @@
import type { Shout, LoadShoutsOptions } from '../../graphql/types.gen'
import { apiClient } from '../../utils/apiClient'
import { createSignal } from 'solid-js'
export type LayoutType = 'article' | 'audio' | 'video' | 'image' | 'literature'
const [sortedLayoutShouts, setSortedLayoutShouts] = createSignal<Map<LayoutType, Shout[]>>(new Map())
const addLayoutShouts = (layout: LayoutType, shouts: Shout[]) => {
setSortedLayoutShouts((prevSorted: Map<LayoutType, Shout[]>) => {
const siblings = prevSorted.get(layout)
if (siblings) {
const uniqued = [...new Set([...siblings, ...shouts])]
prevSorted.set(layout, uniqued)
}
return prevSorted
})
}
export const resetSortedLayoutShouts = () => {
setSortedLayoutShouts(new Map())
}
export const loadLayoutShoutsBy = async (options: LoadShoutsOptions): Promise<{ hasMore: boolean }> => {
const newLayoutShouts = await apiClient.getShouts({
...options,
limit: options.limit + 1
})
const hasMore = newLayoutShouts.length === options.limit + 1
if (hasMore) {
newLayoutShouts.splice(-1)
}
addLayoutShouts(options.filters.layout as LayoutType, newLayoutShouts)
return { hasMore }
}
export const useLayoutsStore = (layout: LayoutType, initialData: Shout[]) => {
addLayoutShouts(layout, initialData || [])
return {
addLayoutShouts,
sortedLayoutShouts,
loadLayoutShoutsBy
}
}

View File

@ -1,6 +1,7 @@
.allTopicsPage {
.group {
@include font-size(1.6rem);
margin: 3em 0 9.6rem;
@include media-breakpoint-down(sm) {
@ -50,11 +51,12 @@
}
.alphabet {
@include font-size(1.5rem);
color: rgba(0 0 0 / 20%);
display: flex;
flex-wrap: wrap;
font-weight: 700;
@include font-size(1.5rem);
margin: 1.5em -3% 0 0;
li {
@ -66,6 +68,7 @@
.articlesCounter {
@include font-size(1.2rem);
margin-left: 0.5em;
vertical-align: super;
}

View File

@ -545,12 +545,14 @@ figure {
figcaption {
@include font-size(1.2rem);
color: #9fa1a7;
}
}
.view-switcher {
@include font-size(1.4rem);
display: flex;
flex-wrap: wrap;
font-weight: 500;
@ -828,6 +830,7 @@ figure {
.content-index {
@include font-size(1.4rem);
line-height: 1.4;
margin: 0 3.6rem 2em 0;