Merge remote-tracking branch 'hub/fix/topic-header' into hotfix/following
This commit is contained in:
commit
e6a4db2eb5
5
public/icons/arrow-right-2.svg
Normal file
5
public/icons/arrow-right-2.svg
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M19.125 12.75H4.5C4.08854 12.75 3.75 12.4115 3.75 12C3.75 11.5885 4.08854 11.25 4.5 11.25H19.125C19.5365 11.25 19.875 11.5885 19.875 12C19.875 12.4115 19.5365 12.75 19.125 12.75Z" fill="currentColor"/>
|
||||||
|
<path
|
||||||
|
d="M14.0678 18.3593C13.8803 18.3593 13.6928 18.2916 13.547 18.151C13.2501 17.8593 13.2397 17.3853 13.5314 17.0885L18.4584 11.9999L13.5314 6.91137C13.2397 6.6145 13.2501 6.14054 13.547 5.84887C13.8439 5.56241 14.3178 5.57283 14.6043 5.8697L20.0366 11.4791C20.3178 11.7707 20.3178 12.2291 20.0366 12.5207L14.6043 18.1301C14.4584 18.2864 14.2657 18.3593 14.0678 18.3593Z" fill="currentColor"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 713 B |
|
@ -55,6 +55,7 @@
|
||||||
"Be the first to rate": "Be the first to rate",
|
"Be the first to rate": "Be the first to rate",
|
||||||
"Become an author": "Become an author",
|
"Become an author": "Become an author",
|
||||||
"bold": "bold",
|
"bold": "bold",
|
||||||
|
"Block rules": "За что можно получить бан",
|
||||||
"Bold": "Bold",
|
"Bold": "Bold",
|
||||||
"Bookmarked": "Saved",
|
"Bookmarked": "Saved",
|
||||||
"bookmarks": "bookmarks",
|
"bookmarks": "bookmarks",
|
||||||
|
@ -98,6 +99,7 @@
|
||||||
"Commenting": "Commenting",
|
"Commenting": "Commenting",
|
||||||
"Comments": "Comments",
|
"Comments": "Comments",
|
||||||
"CommentsWithCount": "{count, plural, =0 {{count} comments} one {{count} comment} few {{count} comments} other {{count} comments}}",
|
"CommentsWithCount": "{count, plural, =0 {{count} comments} one {{count} comment} few {{count} comments} other {{count} comments}}",
|
||||||
|
"Common feed": "All",
|
||||||
"Communities": "Communities",
|
"Communities": "Communities",
|
||||||
"community": "community",
|
"community": "community",
|
||||||
"Community Discussion Rules": "Community Discussion Rules",
|
"Community Discussion Rules": "Community Discussion Rules",
|
||||||
|
@ -125,6 +127,7 @@
|
||||||
"Create post": "Create post",
|
"Create post": "Create post",
|
||||||
"Create video": "Create video",
|
"Create video": "Create video",
|
||||||
"Crop image": "Crop image",
|
"Crop image": "Crop image",
|
||||||
|
"Current discussions": "Актуальные дискуссии",
|
||||||
"Culture": "Culture",
|
"Culture": "Culture",
|
||||||
"Current password": "Current password",
|
"Current password": "Current password",
|
||||||
"Date of Birth": "Date of Birth",
|
"Date of Birth": "Date of Birth",
|
||||||
|
@ -180,6 +183,8 @@
|
||||||
"Feed settings": "Feed settings",
|
"Feed settings": "Feed settings",
|
||||||
"Feedback": "Feedback",
|
"Feedback": "Feedback",
|
||||||
"Fill email": "Fill email",
|
"Fill email": "Fill email",
|
||||||
|
"Find co-authors": "Найти соавторов",
|
||||||
|
"Find collaborators": "Найдите соавторов и экспертов",
|
||||||
"Fixed": "Fixed",
|
"Fixed": "Fixed",
|
||||||
"Follow": "Follow",
|
"Follow": "Follow",
|
||||||
"Follow the topic": "Follow the topic",
|
"Follow the topic": "Follow the topic",
|
||||||
|
@ -197,6 +202,7 @@
|
||||||
"Gallery name": "Gallery name",
|
"Gallery name": "Gallery name",
|
||||||
"Get to know the most intelligent people of our time, edit and discuss the articles, share your expertise, rate and decide what to publish in the magazine": "Get to know the most intelligent people of our time, edit and discuss the articles, share your expertise, rate and decide what to publish in the magazine",
|
"Get to know the most intelligent people of our time, edit and discuss the articles, share your expertise, rate and decide what to publish in the magazine": "Get to know the most intelligent people of our time, edit and discuss the articles, share your expertise, rate and decide what to publish in the magazine",
|
||||||
"Go to main page": "Go to main page",
|
"Go to main page": "Go to main page",
|
||||||
|
"Go to discussions": "Перейти к обсуждениям",
|
||||||
"Group Chat": "Group Chat",
|
"Group Chat": "Group Chat",
|
||||||
"Groups": "Groups",
|
"Groups": "Groups",
|
||||||
"header 1": "header 1",
|
"header 1": "header 1",
|
||||||
|
@ -254,10 +260,15 @@
|
||||||
"Italic": "Italic",
|
"Italic": "Italic",
|
||||||
"Join": "Join",
|
"Join": "Join",
|
||||||
"Join our maillist": "To receive the best postings, just enter your email",
|
"Join our maillist": "To receive the best postings, just enter your email",
|
||||||
|
"Join our team of authors": "Join our team of authors",
|
||||||
|
"Join our team of authors text": "Каждый месяц на Дискурсе публикуются десятки новых авторов. Станьте одним из них — предложите свой материал в журнал и присоединитесь к горизонтальной редакции",
|
||||||
"Join the community": "Join the community",
|
"Join the community": "Join the community",
|
||||||
"Join the global community of authors!": "Join the global community of authors from all over the world!",
|
"Join the global community of authors!": "Join the global community of authors from all over the world!",
|
||||||
"journal": "journal",
|
"journal": "journal",
|
||||||
"jpg, .png, max. 10 mb.": "jpg, .png, макс. 10 мб.",
|
"jpg, .png, max. 10 mb.": "jpg, .png, макс. 10 мб.",
|
||||||
|
"Join": "Join",
|
||||||
|
"Join discussions": "Присоединяйтесь к дискуссиям",
|
||||||
|
"Join discussions text": "Дискурс — свободная платформа для осмысленного общения.<br/>Здесь появятся ваши реплики, чтобы в любой момент вернуться к диалогу.",
|
||||||
"Just start typing...": "Just start typing...",
|
"Just start typing...": "Just start typing...",
|
||||||
"keywords": "Discours.io, Discours magazine, Discours, culture, science, art, society, independent journalism, literature, music, cinema, video, photography",
|
"keywords": "Discours.io, Discours magazine, Discours, culture, science, art, society, independent journalism, literature, music, cinema, video, photography",
|
||||||
"Knowledge base": "Knowledge base",
|
"Knowledge base": "Knowledge base",
|
||||||
|
@ -313,6 +324,7 @@
|
||||||
"Our regular contributor": "Our regular contributor",
|
"Our regular contributor": "Our regular contributor",
|
||||||
"Paragraphs": "Абзацев",
|
"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": "Participating",
|
"Participating": "Participating",
|
||||||
"Participation": "Participation",
|
"Participation": "Participation",
|
||||||
"Partners": "Partners",
|
"Partners": "Partners",
|
||||||
|
@ -327,6 +339,9 @@
|
||||||
"Personal": "Personal",
|
"Personal": "Personal",
|
||||||
"personal data usage and email notifications": "to process personal data and receive email notifications",
|
"personal data usage and email notifications": "to process personal data and receive email notifications",
|
||||||
"Pin": "Pin",
|
"Pin": "Pin",
|
||||||
|
"Placeholder feed": "Подпишитесь на любимые темы, авторов и сообщества — моментально узнавайте о новых публикациях и обсуждениях",
|
||||||
|
"Placeholder feedCollaborations": "На платформе можно писать материалы вместе. Здесь появятся публикации, в которые вы внесли вклад",
|
||||||
|
"Placeholder feedDiscussions": "Дискурс — свободная платформа для осмысленного общения. Здесь появятся все ваши реплики, чтобы в любой момент вернуться к диалогу",
|
||||||
"Platform Guide": "Platform Guide",
|
"Platform Guide": "Platform Guide",
|
||||||
"Please check your email address": "Please check your email address",
|
"Please check your email address": "Please check your email address",
|
||||||
"Please confirm your email to finish": "Confirm your email and the action will complete",
|
"Please confirm your email to finish": "Confirm your email and the action will complete",
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
"All posts rating": "Рейтинг всех постов",
|
"All posts rating": "Рейтинг всех постов",
|
||||||
"all topics": "все темы",
|
"all topics": "все темы",
|
||||||
"All topics": "Все темы",
|
"All topics": "Все темы",
|
||||||
|
"All": "Все",
|
||||||
"Almost done! Check your email.": "Почти готово! Осталось подтвердить вашу почту.",
|
"Almost done! Check your email.": "Почти готово! Осталось подтвердить вашу почту.",
|
||||||
"and some more authors": "{restUsersCount, plural, =0 {} one { и ещё 1 пользователя} few { и ещё {restUsersCount} пользователей} other { и ещё {restUsersCount} пользователей}}",
|
"and some more authors": "{restUsersCount, plural, =0 {} one { и ещё 1 пользователя} few { и ещё {restUsersCount} пользователей} other { и ещё {restUsersCount} пользователей}}",
|
||||||
"Are you sure you want to delete this comment?": "Уверены, что хотите удалить этот комментарий?",
|
"Are you sure you want to delete this comment?": "Уверены, что хотите удалить этот комментарий?",
|
||||||
|
@ -59,6 +60,7 @@
|
||||||
"Be the first to rate": "Оцените первым",
|
"Be the first to rate": "Оцените первым",
|
||||||
"Become an author": "Стать автором",
|
"Become an author": "Стать автором",
|
||||||
"bold": "жирный",
|
"bold": "жирный",
|
||||||
|
"Block rules": "За что можно получить бан",
|
||||||
"Bold": "Жирный",
|
"Bold": "Жирный",
|
||||||
"Bookmarked": "Сохранено",
|
"Bookmarked": "Сохранено",
|
||||||
"bookmarks": "закладки",
|
"bookmarks": "закладки",
|
||||||
|
@ -103,6 +105,7 @@
|
||||||
"Commenting": "Комментирование",
|
"Commenting": "Комментирование",
|
||||||
"Comments": "Комментарии",
|
"Comments": "Комментарии",
|
||||||
"CommentsWithCount": "{count, plural, =0 {{count} комментариев} one {{count} комментарий} few {{count} комментария} other {{count} комментариев}}",
|
"CommentsWithCount": "{count, plural, =0 {{count} комментариев} one {{count} комментарий} few {{count} комментария} other {{count} комментариев}}",
|
||||||
|
"Common feed": "Общая лента",
|
||||||
"Communities": "Сообщества",
|
"Communities": "Сообщества",
|
||||||
"community": "сообщество",
|
"community": "сообщество",
|
||||||
"Community Discussion Rules": "Правила дискуссий в сообществе",
|
"Community Discussion Rules": "Правила дискуссий в сообществе",
|
||||||
|
@ -126,14 +129,14 @@
|
||||||
"Create an account to vote": "Создайте аккаунт, чтобы голосовать",
|
"Create an account to vote": "Создайте аккаунт, чтобы голосовать",
|
||||||
"Create Chat": "Создать чат",
|
"Create Chat": "Создать чат",
|
||||||
"Create gallery": "Создать галерею",
|
"Create gallery": "Создать галерею",
|
||||||
"Create Group": "Создать группу",
|
"Create own feed": "Создать свою ленту",
|
||||||
"Create post": "Создать публикацию",
|
"Create post": "Создать публикацию",
|
||||||
"Create video": "Создать видео",
|
"Create video": "Создать видео",
|
||||||
"create_chat": "Создать чат",
|
"create_chat": "Создать чат",
|
||||||
"create_group": "Создать группу",
|
"create_group": "Создать группу",
|
||||||
"Crop image": "Кадрировать изображение",
|
"Crop image": "Кадрировать изображение",
|
||||||
"Culture": "Культура",
|
"Culture": "Культура",
|
||||||
"Current password": "Текущий пароль",
|
"Current discussions": "Актуальные дискуссии",
|
||||||
"Date of Birth": "Дата рождения",
|
"Date of Birth": "Дата рождения",
|
||||||
"Decline": "Отмена",
|
"Decline": "Отмена",
|
||||||
"Delete": "Удалить",
|
"Delete": "Удалить",
|
||||||
|
@ -188,6 +191,8 @@
|
||||||
"Feed settings": "Настроить ленту",
|
"Feed settings": "Настроить ленту",
|
||||||
"Feedback": "Обратная связь",
|
"Feedback": "Обратная связь",
|
||||||
"Fill email": "Введите почту",
|
"Fill email": "Введите почту",
|
||||||
|
"Find co-authors": "Найти соавторов",
|
||||||
|
"Find collaborators": "Найдите соавторов и экспертов",
|
||||||
"Fixed": "Все поправлено",
|
"Fixed": "Все поправлено",
|
||||||
"Follow": "Подписаться",
|
"Follow": "Подписаться",
|
||||||
"Follow the topic": "Подписаться на тему",
|
"Follow the topic": "Подписаться на тему",
|
||||||
|
@ -207,6 +212,7 @@
|
||||||
"Get notifications": "Получать уведомления",
|
"Get notifications": "Получать уведомления",
|
||||||
"Get to know the most intelligent people of our time, edit and discuss the articles, share your expertise, rate and decide what to publish in the magazine": "Познакомитесь с выдающимися людьми нашего времени, участвуйте в редактировании и обсуждении статей, выступайте экспертом, оценивайте материалы других авторов со всего мира и определяйте, какие статьи будут опубликованы в журнале",
|
"Get to know the most intelligent people of our time, edit and discuss the articles, share your expertise, rate and decide what to publish in the magazine": "Познакомитесь с выдающимися людьми нашего времени, участвуйте в редактировании и обсуждении статей, выступайте экспертом, оценивайте материалы других авторов со всего мира и определяйте, какие статьи будут опубликованы в журнале",
|
||||||
"Go to main page": "Перейти на главную",
|
"Go to main page": "Перейти на главную",
|
||||||
|
"Go to discussions": "Перейти к обсуждениям",
|
||||||
"Group Chat": "Общий чат",
|
"Group Chat": "Общий чат",
|
||||||
"Groups": "Группы",
|
"Groups": "Группы",
|
||||||
"Header": "Заголовок",
|
"Header": "Заголовок",
|
||||||
|
@ -266,8 +272,13 @@
|
||||||
"Italic": "Курсив",
|
"Italic": "Курсив",
|
||||||
"Join": "Присоединиться",
|
"Join": "Присоединиться",
|
||||||
"Join our maillist": "Чтобы получать рассылку лучших публикаций, просто укажите свою почту",
|
"Join our maillist": "Чтобы получать рассылку лучших публикаций, просто укажите свою почту",
|
||||||
|
"Join our team of authors": "Станьте автором",
|
||||||
|
"Join our team of authors text": "Каждый месяц на Дискурсе публикуются десятки новых авторов.<br/>Станьте одним из них — предложите свой материал в журнал и присоединитесь к горизонтальной редакции",
|
||||||
"Join the community": "Присоединиться к сообществу",
|
"Join the community": "Присоединиться к сообществу",
|
||||||
"Join the global community of authors!": "Присоединятесь к глобальному сообществу авторов со всего мира!",
|
"Join the global community of authors!": "Присоединятесь к глобальному сообществу авторов со всего мира!",
|
||||||
|
"Join": "Присоединиться",
|
||||||
|
"Join discussions": "Присоединяйтесь к дискуссиям",
|
||||||
|
"Join discussions text": "Дискурс — свободная платформа для осмысленного общения.<br/>Здесь появятся ваши реплики, чтобы в любой момент вернуться к диалогу.",
|
||||||
"journal": "журнал",
|
"journal": "журнал",
|
||||||
"jpg, .png, max. 10 mb.": "jpg, .png, макс. 10 мб.",
|
"jpg, .png, max. 10 mb.": "jpg, .png, макс. 10 мб.",
|
||||||
"Just start typing...": "Просто начните печатать...",
|
"Just start typing...": "Просто начните печатать...",
|
||||||
|
@ -328,6 +339,7 @@
|
||||||
"Our regular contributor": "Наш постоянный автор",
|
"Our regular contributor": "Наш постоянный автор",
|
||||||
"Paragraphs": "Абзацев",
|
"Paragraphs": "Абзацев",
|
||||||
"Participate in the Discours: share information, join the editorial team": "Participate in the Discours: share information, join the editorial team",
|
"Participate in the Discours: share information, join the editorial team": "Participate in the Discours: share information, join the editorial team",
|
||||||
|
"Participate in discussions": "Участвуйте в дискуссиях",
|
||||||
"Participating": "Участвовать",
|
"Participating": "Участвовать",
|
||||||
"Participation": "Соучастие",
|
"Participation": "Соучастие",
|
||||||
"Partners": "Партнёры",
|
"Partners": "Партнёры",
|
||||||
|
@ -342,6 +354,9 @@
|
||||||
"Personal": "Личные",
|
"Personal": "Личные",
|
||||||
"personal data usage and email notifications": "на обработку персональных данных и на получение почтовых уведомлений",
|
"personal data usage and email notifications": "на обработку персональных данных и на получение почтовых уведомлений",
|
||||||
"Pin": "Закрепить",
|
"Pin": "Закрепить",
|
||||||
|
"Placeholder feed": "Подпишитесь на любимые темы, авторов и сообщества — моментально узнавайте о новых публикациях и обсуждениях",
|
||||||
|
"Placeholder feedCollaborations": "На платформе можно писать материалы вместе. Здесь появятся публикации, в которые вы внесли вклад",
|
||||||
|
"Placeholder feedDiscussions": "Дискурс — свободная платформа для осмысленного общения. Здесь появятся все ваши реплики, чтобы в любой момент вернуться к диалогу",
|
||||||
"Platform Guide": "Гид по дискурсу",
|
"Platform Guide": "Гид по дискурсу",
|
||||||
"Please check your email address": "Пожалуйста, проверьте введенный адрес почты",
|
"Please check your email address": "Пожалуйста, проверьте введенный адрес почты",
|
||||||
"Please check your inbox! We have sent a password reset link.": "Пожалуйста, проверьте свою почту, мы отправили вам письмо со ссылкой для сброса пароля",
|
"Please check your inbox! We have sent a password reset link.": "Пожалуйста, проверьте свою почту, мы отправили вам письмо со ссылкой для сброса пароля",
|
||||||
|
|
BIN
public/placeholder-discussions.webp
Normal file
BIN
public/placeholder-discussions.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 379 KiB |
BIN
public/placeholder-experts.webp
Normal file
BIN
public/placeholder-experts.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 157 KiB |
BIN
public/placeholder-feed.webp
Normal file
BIN
public/placeholder-feed.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 220 KiB |
BIN
public/placeholder-join.webp
Normal file
BIN
public/placeholder-join.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 192 KiB |
|
@ -18,9 +18,8 @@
|
||||||
|
|
||||||
.authorName {
|
.authorName {
|
||||||
@include font-size(4rem);
|
@include font-size(4rem);
|
||||||
|
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
margin-bottom: 0.2em;
|
margin-bottom: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.authorAbout {
|
.authorAbout {
|
||||||
|
@ -429,64 +428,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.followersContainer {
|
.listWrapper {
|
||||||
|
max-height: 70vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribersContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
margin-top: 1.5rem;
|
gap: 1rem;
|
||||||
|
margin-top: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
@include media-breakpoint-down(md) {
|
@include media-breakpoint-down(md) {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.followers {
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-flex;
|
|
||||||
margin: 0 2% 1rem;
|
|
||||||
vertical-align: top;
|
|
||||||
border-bottom: unset !important;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.followersItem {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&:nth-child(1) {
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(2) {
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(:last-child) {
|
|
||||||
margin-right: -4px;
|
|
||||||
box-shadow: 0 0 0 1px var(--background-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.followsCounter {
|
|
||||||
font-weight: 500;
|
|
||||||
margin-left: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: none !important;
|
|
||||||
|
|
||||||
.followsCounter {
|
|
||||||
background: var(--background-color-invert);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.listWrapper {
|
|
||||||
max-height: 70vh;
|
|
||||||
}
|
|
|
@ -18,6 +18,7 @@ import { Modal } from '../../Nav/Modal'
|
||||||
import { TopicBadge } from '../../Topic/TopicBadge'
|
import { TopicBadge } from '../../Topic/TopicBadge'
|
||||||
import { Button } from '../../_shared/Button'
|
import { Button } from '../../_shared/Button'
|
||||||
import { ShowOnlyOnClient } from '../../_shared/ShowOnlyOnClient'
|
import { ShowOnlyOnClient } from '../../_shared/ShowOnlyOnClient'
|
||||||
|
import { Subscribers } from '../../_shared/Subscribers'
|
||||||
import { AuthorBadge } from '../AuthorBadge'
|
import { AuthorBadge } from '../AuthorBadge'
|
||||||
import { Userpic } from '../Userpic'
|
import { Userpic } from '../Userpic'
|
||||||
|
|
||||||
|
@ -192,61 +193,14 @@ export const AuthorCard = (props: Props) => {
|
||||||
<Show when={props.author.bio}>
|
<Show when={props.author.bio}>
|
||||||
<div class={styles.authorAbout} innerHTML={props.author.bio} />
|
<div class={styles.authorAbout} innerHTML={props.author.bio} />
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={props.followers?.length > 0 || props.flatFollows?.length > 0}>
|
<Show when={props.followers?.length > 0 || props.following?.length > 0}>
|
||||||
<div class={styles.followersContainer}>
|
<div class={styles.subscribersContainer}>
|
||||||
<Show when={props.followers && props.followers.length > 0}>
|
<Subscribers
|
||||||
<a href="?m=followers" class={styles.followers}>
|
followers={props.followers}
|
||||||
<For each={props.followers.slice(0, 3)}>
|
followersAmount={props.author?.stat?.followers}
|
||||||
{(f: Author) => (
|
following={props.following}
|
||||||
<Show when={f?.name}>
|
followingAmount={props.author?.stat?.authors}
|
||||||
<Userpic
|
|
||||||
size={'XS'}
|
|
||||||
name={f?.name || ''}
|
|
||||||
userpic={f?.pic || ''}
|
|
||||||
class={styles.followersItem}
|
|
||||||
/>
|
/>
|
||||||
</Show>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
<div class={styles.followsCounter}>
|
|
||||||
{t('FollowersWithCount', {
|
|
||||||
count: props.followers.length ?? 0,
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<Show when={props.flatFollows?.length > 0}>
|
|
||||||
<a href="?m=following" class={styles.followers}>
|
|
||||||
<For each={props.flatFollows.slice(0, 3)}>
|
|
||||||
{(f) => {
|
|
||||||
if ('name' in f) {
|
|
||||||
return (
|
|
||||||
<Userpic size={'XS'} name={f.name} userpic={f.pic} class={styles.followersItem} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('title' in f) {
|
|
||||||
return (
|
|
||||||
<Userpic
|
|
||||||
size={'XS'}
|
|
||||||
name={f.title}
|
|
||||||
userpic={f.pic}
|
|
||||||
class={styles.followersItem}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}}
|
|
||||||
</For>
|
|
||||||
<div class={styles.followsCounter}>
|
|
||||||
{t('FollowsWithCount', {
|
|
||||||
count: props?.flatFollows.length ?? 0,
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</Show>
|
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|
213
src/components/Feed/Placeholder/Placeholder.module.scss
Normal file
213
src/components/Feed/Placeholder/Placeholder.module.scss
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
.placeholder {
|
||||||
|
border-radius: 2.2rem;
|
||||||
|
display: flex;
|
||||||
|
@include font-size(1.4rem);
|
||||||
|
font-weight: 500;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
@include font-size(2.4rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
.button {
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 1.2rem;
|
||||||
|
display: flex;
|
||||||
|
@include font-size(1.5rem);
|
||||||
|
gap: 0.6rem;
|
||||||
|
margin-top: 3rem;
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
height: 2.4rem;
|
||||||
|
width: 2.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder--feed-mode {
|
||||||
|
aspect-ratio: 1 / 0.8;
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&: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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholderCover {
|
||||||
|
flex: 0 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
img {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder--profile-mode {
|
||||||
|
min-height: 28rem;
|
||||||
|
|
||||||
|
.placeholderCover {
|
||||||
|
flex: 0 45rem;
|
||||||
|
min-width: 45rem;
|
||||||
|
order: 2;
|
||||||
|
padding: 1.6rem;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholderContent {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
@include font-size(2rem);
|
||||||
|
line-height: 1.2;
|
||||||
|
padding: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
@include font-size(3.8rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
background: var(--background-color-invert);
|
||||||
|
color: var(--default-color-invert);
|
||||||
|
bottom: 2rem;
|
||||||
|
position: absolute;
|
||||||
|
right: 2rem;
|
||||||
|
width: auto;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholderCover {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
img {
|
||||||
|
left: 0;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholderContent {
|
||||||
|
padding: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.placeholder--author {
|
||||||
|
background: #E58B72;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder--authorComments {
|
||||||
|
background: #E9E9EE;
|
||||||
|
|
||||||
|
.placeholderCover {
|
||||||
|
img {
|
||||||
|
mix-blend-mode: multiply;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottomLinks {
|
||||||
|
display: flex;
|
||||||
|
@include font-size(1.6rem);
|
||||||
|
gap: 4rem;
|
||||||
|
|
||||||
|
a {
|
||||||
|
border: none !important;
|
||||||
|
padding-left: 2.6rem;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.icon {
|
||||||
|
filter: invert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
filter: invert(1);
|
||||||
|
height: 1.8rem;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
transition: filter 0.2s;
|
||||||
|
width: 1.8rem;
|
||||||
|
}
|
||||||
|
}
|
120
src/components/Feed/Placeholder/Placeholder.tsx
Normal file
120
src/components/Feed/Placeholder/Placeholder.tsx
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
import { clsx } from 'clsx'
|
||||||
|
import { For, Show } from 'solid-js'
|
||||||
|
|
||||||
|
import { useLocalize } from '../../../context/localize'
|
||||||
|
import { useSession } from '../../../context/session'
|
||||||
|
import { Icon } from '../../_shared/Icon'
|
||||||
|
import styles from './Placeholder.module.scss'
|
||||||
|
|
||||||
|
export type PlaceholderProps = {
|
||||||
|
type: string
|
||||||
|
mode: 'feed' | 'profile'
|
||||||
|
}
|
||||||
|
|
||||||
|
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'),
|
||||||
|
href: '/authors?by=followers',
|
||||||
|
},
|
||||||
|
feedCollaborations: {
|
||||||
|
image: 'placeholder-experts.webp',
|
||||||
|
header: t('Find collaborators'),
|
||||||
|
text: t('Placeholder feedCollaborations'),
|
||||||
|
buttonLabel: t('Find co-authors'),
|
||||||
|
href: '/authors?by=name',
|
||||||
|
},
|
||||||
|
feedDiscussions: {
|
||||||
|
image: 'placeholder-discussions.webp',
|
||||||
|
header: t('Participate in discussions'),
|
||||||
|
text: t('Placeholder feedDiscussions'),
|
||||||
|
buttonLabel: author() ? t('Current discussions') : t('Enter'),
|
||||||
|
href: '/feed?by=last_comment',
|
||||||
|
},
|
||||||
|
author: {
|
||||||
|
image: 'placeholder-join.webp',
|
||||||
|
header: t('Join our team of authors'),
|
||||||
|
text: t('Join our team of authors text'),
|
||||||
|
buttonLabel: t('Create post'),
|
||||||
|
href: '/create',
|
||||||
|
profileLinks: [
|
||||||
|
{
|
||||||
|
href: '/how-to-write-a-good-article',
|
||||||
|
label: t('How to write a good article'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
authorComments: {
|
||||||
|
image: 'placeholder-discussions.webp',
|
||||||
|
header: t('Join discussions'),
|
||||||
|
text: t('Placeholder feedDiscussions'),
|
||||||
|
buttonLabel: t('Go to discussions'),
|
||||||
|
href: '/feed?by=last_comment',
|
||||||
|
profileLinks: [
|
||||||
|
{
|
||||||
|
href: '/about/discussion-rules',
|
||||||
|
label: t('Discussion rules'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
href: '/about/discussion-rules#ban',
|
||||||
|
label: t('Block rules'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class={clsx(
|
||||||
|
styles.placeholder,
|
||||||
|
styles[`placeholder--${props.type}`],
|
||||||
|
styles[`placeholder--${props.mode}-mode`],
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div class={styles.placeholderCover}>
|
||||||
|
<img src={`/${data[props.type].image}`} />
|
||||||
|
</div>
|
||||||
|
<div class={styles.placeholderContent}>
|
||||||
|
<div>
|
||||||
|
<h3 innerHTML={data[props.type].header} />
|
||||||
|
<p innerHTML={data[props.type].text} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Show when={data[props.type].profileLinks}>
|
||||||
|
<div class={styles.bottomLinks}>
|
||||||
|
<For each={data[props.type].profileLinks}>
|
||||||
|
{(link) => (
|
||||||
|
<a href={link.href}>
|
||||||
|
<Icon name="link-white" class={styles.icon} />
|
||||||
|
{link.label}
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Show
|
||||||
|
when={author()}
|
||||||
|
fallback={
|
||||||
|
<a class={styles.button} href="?m=auth&mode=login">
|
||||||
|
{data[props.type].buttonLabel}
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<a class={styles.button} href={data[props.type].href}>
|
||||||
|
{data[props.type].buttonLabel}
|
||||||
|
<Show when={props.mode === 'profile'}>
|
||||||
|
<Icon name="arrow-right-2" class={styles.icon} />
|
||||||
|
</Show>
|
||||||
|
</a>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
1
src/components/Feed/Placeholder/index.ts
Normal file
1
src/components/Feed/Placeholder/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export { Placeholder } from './Placeholder'
|
|
@ -83,32 +83,6 @@ export const Sidebar = () => {
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href={getPagePath(router, 'feedBookmarks')}
|
|
||||||
class={clsx({
|
|
||||||
[styles.selected]: page().route === 'feedBookmarks',
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<span class={styles.sidebarItemName}>
|
|
||||||
<Icon name="bookmark" class={styles.icon} />
|
|
||||||
{t('Bookmarks')}
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href={getPagePath(router, 'feedNotifications')}
|
|
||||||
class={clsx({
|
|
||||||
[styles.selected]: page().route === 'feedNotifications',
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<span class={styles.sidebarItemName}>
|
|
||||||
<Icon name="feed-notifications" class={styles.icon} />
|
|
||||||
{t('Notifications')}
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<Show when={follows?.authors?.length > 0 || follows?.topics?.length > 0}>
|
<Show when={follows?.authors?.length > 0 || follows?.topics?.length > 0}>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
.topicHeader {
|
.topicHeader {
|
||||||
@include font-size(1.7rem);
|
font-weight: 500;
|
||||||
|
|
||||||
padding: 2.8rem $container-padding-x 0;
|
padding: 2.8rem $container-padding-x 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
@ -12,10 +11,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.topicDescription {
|
||||||
|
@include font-size(1.8rem);
|
||||||
|
line-height: 1.4;
|
||||||
|
margin: 1rem 0 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.topicActions {
|
.topicActions {
|
||||||
margin-top: 2.8rem;
|
margin-top: 2.8rem;
|
||||||
|
|
||||||
.write {
|
.writeControl {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -23,13 +28,38 @@
|
||||||
min-width: 64px;
|
min-width: 64px;
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
background: var(--background-color-invert);
|
border: 1px solid #f7f7f7;
|
||||||
color: var(--default-color-invert);
|
background: #f7f7f7;
|
||||||
border: none;
|
color: var(--default-color);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
border-radius: 2px;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin: 0 1.2rem 1em;
|
margin: 0 1.2rem 1em;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.followControl,
|
||||||
|
.writeControl {
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.topicDetails {
|
||||||
|
align-items: flex-start;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topicDetailsItem {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
margin-right: 1rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topicDetailsIcon {
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Topic } from '../../graphql/schema/core.gen'
|
import type { Author, Topic } from '../../graphql/schema/core.gen'
|
||||||
|
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Show, createEffect, createSignal } from 'solid-js'
|
import { Show, createEffect, createSignal } from 'solid-js'
|
||||||
|
@ -9,10 +9,14 @@ import { useSession } from '../../context/session'
|
||||||
import { FollowingEntity } from '../../graphql/schema/core.gen'
|
import { FollowingEntity } from '../../graphql/schema/core.gen'
|
||||||
import { Button } from '../_shared/Button'
|
import { Button } from '../_shared/Button'
|
||||||
|
|
||||||
|
import { Icon } from '../_shared/Icon'
|
||||||
|
import { Subscribers } from '../_shared/Subscribers'
|
||||||
import styles from './Full.module.scss'
|
import styles from './Full.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
topic: Topic
|
topic: Topic
|
||||||
|
followers?: Author[]
|
||||||
|
authors?: Author[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FullTopic = (props: Props) => {
|
export const FullTopic = (props: Props) => {
|
||||||
|
@ -39,19 +43,39 @@ export const FullTopic = (props: Props) => {
|
||||||
return (
|
return (
|
||||||
<div class={clsx(styles.topicHeader, 'col-md-16 col-lg-12 offset-md-4 offset-lg-6')}>
|
<div class={clsx(styles.topicHeader, 'col-md-16 col-lg-12 offset-md-4 offset-lg-6')}>
|
||||||
<h1>#{props.topic?.title}</h1>
|
<h1>#{props.topic?.title}</h1>
|
||||||
<p innerHTML={props.topic?.body} />
|
<p class={styles.topicDescription} innerHTML={props.topic?.body} />
|
||||||
|
|
||||||
|
<div class={styles.topicDetails}>
|
||||||
|
<Show when={props.topic?.stat}>
|
||||||
|
<div class={styles.topicDetailsItem}>
|
||||||
|
<Icon name="feed-all" class={styles.topicDetailsIcon} />
|
||||||
|
{t('PublicationsWithCount', {
|
||||||
|
count: props.topic?.stat.shouts ?? 0,
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Subscribers
|
||||||
|
followers={props.followers}
|
||||||
|
followersAmount={props.topic?.stat?.followers}
|
||||||
|
following={props.authors}
|
||||||
|
followingAmount={props.topic?.stat?.authors}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class={clsx(styles.topicActions)}>
|
<div class={clsx(styles.topicActions)}>
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={handleFollowClick}
|
onClick={handleFollowClick}
|
||||||
value={followed() ? t('Unfollow the topic') : t('Follow the topic')}
|
value={followed() ? t('Unfollow the topic') : t('Follow the topic')}
|
||||||
|
class={styles.followControl}
|
||||||
/>
|
/>
|
||||||
<a class={styles.write} href={`/create/?topicId=${props.topic?.id}`}>
|
<a class={styles.writeControl} href={`/create/?topicId=${props.topic?.id}`}>
|
||||||
{t('Write about the topic')}
|
{t('Write about the topic')}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<Show when={props.topic?.pic}>
|
<Show when={props.topic?.pic}>
|
||||||
<img src={props.topic.pic} alt={props.topic?.title} />
|
<img src={props.topic?.pic} alt={props.topic?.title} />
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -27,6 +27,7 @@ import { Loading } from '../../_shared/Loading'
|
||||||
import { MODALS, hideModal } from '../../../stores/ui'
|
import { MODALS, hideModal } from '../../../stores/ui'
|
||||||
import { byCreated } from '../../../utils/sortby'
|
import { byCreated } from '../../../utils/sortby'
|
||||||
import stylesArticle from '../../Article/Article.module.scss'
|
import stylesArticle from '../../Article/Article.module.scss'
|
||||||
|
import { Placeholder } from '../../Feed/Placeholder'
|
||||||
import styles from './Author.module.scss'
|
import styles from './Author.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -250,6 +251,10 @@ export const AuthorView = (props: Props) => {
|
||||||
</div>
|
</div>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={getPage().route === 'authorComments'}>
|
<Match when={getPage().route === 'authorComments'}>
|
||||||
|
<div class="wide-container">
|
||||||
|
<Placeholder type={getPage().route} mode="profile" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-20 col-lg-18">
|
<div class="col-md-20 col-lg-18">
|
||||||
|
@ -270,6 +275,15 @@ export const AuthorView = (props: Props) => {
|
||||||
</div>
|
</div>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={getPage().route === 'author'}>
|
<Match when={getPage().route === 'author'}>
|
||||||
|
<Show
|
||||||
|
when={session()?.user?.app_data?.profile?.slug === props.authorSlug && !sortedArticles().length}
|
||||||
|
>
|
||||||
|
<div class="wide-container">
|
||||||
|
<Placeholder type={getPage().route} mode="profile" />
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Show when={sortedArticles().length > 0}>
|
||||||
<Show when={sortedArticles().length === 1}>
|
<Show when={sortedArticles().length === 1}>
|
||||||
<Row1 article={sortedArticles()[0]} noauthor={true} nodate={true} />
|
<Row1 article={sortedArticles()[0]} noauthor={true} nodate={true} />
|
||||||
</Show>
|
</Show>
|
||||||
|
@ -311,6 +325,7 @@ export const AuthorView = (props: Props) => {
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
</Show>
|
</Show>
|
||||||
|
</Show>
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -175,6 +175,7 @@
|
||||||
-webkit-line-clamp: 1;
|
-webkit-line-clamp: 1;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
border: none;
|
||||||
color: rgb(0 0 0 / 65%);
|
color: rgb(0 0 0 / 65%);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { getShareUrl } from '../../Article/SharePopup'
|
||||||
import { AuthorBadge } from '../../Author/AuthorBadge'
|
import { AuthorBadge } from '../../Author/AuthorBadge'
|
||||||
import { AuthorLink } from '../../Author/AuthorLink'
|
import { AuthorLink } from '../../Author/AuthorLink'
|
||||||
import { ArticleCard } from '../../Feed/ArticleCard'
|
import { ArticleCard } from '../../Feed/ArticleCard'
|
||||||
|
import { Placeholder } from '../../Feed/Placeholder'
|
||||||
import { Sidebar } from '../../Feed/Sidebar'
|
import { Sidebar } from '../../Feed/Sidebar'
|
||||||
import { Modal } from '../../Nav/Modal'
|
import { Modal } from '../../Nav/Modal'
|
||||||
import { DropDown } from '../../_shared/DropDown'
|
import { DropDown } from '../../_shared/DropDown'
|
||||||
|
@ -100,7 +101,7 @@ export const FeedView = (props: Props) => {
|
||||||
const { page, searchParams, changeSearchParams } = useRouter<FeedSearchParams>()
|
const { page, searchParams, changeSearchParams } = useRouter<FeedSearchParams>()
|
||||||
const [isLoading, setIsLoading] = createSignal(false)
|
const [isLoading, setIsLoading] = createSignal(false)
|
||||||
const [isRightColumnLoaded, setIsRightColumnLoaded] = createSignal(false)
|
const [isRightColumnLoaded, setIsRightColumnLoaded] = createSignal(false)
|
||||||
const { session } = useSession()
|
const { author, session } = useSession()
|
||||||
const { loadReactionsBy } = useReactions()
|
const { loadReactionsBy } = useReactions()
|
||||||
const { sortedArticles } = useArticlesStore()
|
const { sortedArticles } = useArticlesStore()
|
||||||
const { topTopics } = useTopics()
|
const { topTopics } = useTopics()
|
||||||
|
@ -238,6 +239,10 @@ export const FeedView = (props: Props) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-12 offset-xl-1">
|
<div class="col-md-12 offset-xl-1">
|
||||||
|
<Show
|
||||||
|
when={author() || !sortedArticles().length}
|
||||||
|
fallback={<Placeholder type={page().route} mode="feed" />}
|
||||||
|
>
|
||||||
<div class={styles.filtersContainer}>
|
<div class={styles.filtersContainer}>
|
||||||
<ul class={clsx('view-switcher', styles.feedFilter)}>
|
<ul class={clsx('view-switcher', styles.feedFilter)}>
|
||||||
<li
|
<li
|
||||||
|
@ -341,6 +346,7 @@ export const FeedView = (props: Props) => {
|
||||||
</p>
|
</p>
|
||||||
</Show>
|
</Show>
|
||||||
</Show>
|
</Show>
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside class={clsx('col-md-7 col-xl-6 offset-xl-1', styles.feedAside)}>
|
<aside class={clsx('col-md-7 col-xl-6 offset-xl-1', styles.feedAside)}>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { LoadShoutsOptions, Shout, Topic } from '../../graphql/schema/core.gen'
|
import { Author, AuthorsBy, LoadShoutsOptions, Shout, Topic } from '../../graphql/schema/core.gen'
|
||||||
|
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Show, createEffect, createMemo, createSignal, on, onMount } from 'solid-js'
|
import { For, Show, createEffect, createMemo, createSignal, on, onMount } from 'solid-js'
|
||||||
|
@ -33,6 +33,7 @@ interface Props {
|
||||||
topic: Topic
|
topic: Topic
|
||||||
shouts: Shout[]
|
shouts: Shout[]
|
||||||
topicSlug: string
|
topicSlug: string
|
||||||
|
followers?: Author[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PRERENDERED_ARTICLES_COUNT = 28
|
export const PRERENDERED_ARTICLES_COUNT = 28
|
||||||
|
@ -56,6 +57,11 @@ export const TopicView = (props: Props) => {
|
||||||
setTopic(topics[props.topicSlug])
|
setTopic(topics[props.topicSlug])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const [followers, setFollowers] = createSignal<Author[]>(props.followers || [])
|
||||||
|
const loadTopicFollowers = async () => {
|
||||||
|
const result = await apiClient.getTopicFollowers({ slug: props.topicSlug })
|
||||||
|
setFollowers(result)
|
||||||
|
}
|
||||||
|
|
||||||
const loadFavoriteTopArticles = async (topic: string) => {
|
const loadFavoriteTopArticles = async (topic: string) => {
|
||||||
const options: LoadShoutsOptions = {
|
const options: LoadShoutsOptions = {
|
||||||
|
@ -81,13 +87,29 @@ export const TopicView = (props: Props) => {
|
||||||
|
|
||||||
setReactedTopMonthArticles(result)
|
setReactedTopMonthArticles(result)
|
||||||
}
|
}
|
||||||
|
const [topicAuthors, setTopicAuthors] = createSignal<Author[]>([])
|
||||||
|
const loadTopicAuthors = async () => {
|
||||||
|
const by: AuthorsBy = { topic: props.topicSlug }
|
||||||
|
const result = await apiClient.loadAuthorsBy({ by })
|
||||||
|
setTopicAuthors(result)
|
||||||
|
}
|
||||||
|
|
||||||
const loadRandom = () => {
|
const loadRandom = () => {
|
||||||
loadFavoriteTopArticles(topic()?.slug)
|
loadFavoriteTopArticles(topic()?.slug)
|
||||||
loadReactedTopMonthArticles(topic()?.slug)
|
loadReactedTopMonthArticles(topic()?.slug)
|
||||||
}
|
}
|
||||||
|
|
||||||
createEffect(on(topic, loadRandom, { defer: true }))
|
createEffect(
|
||||||
|
on(
|
||||||
|
() => topic()?.id,
|
||||||
|
(_) => {
|
||||||
|
loadTopicFollowers()
|
||||||
|
loadTopicAuthors()
|
||||||
|
loadRandom()
|
||||||
|
},
|
||||||
|
{ defer: true },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
const title = createMemo(
|
const title = createMemo(
|
||||||
() =>
|
() =>
|
||||||
|
@ -152,7 +174,7 @@ export const TopicView = (props: Props) => {
|
||||||
<Meta name="twitter:card" content="summary_large_image" />
|
<Meta name="twitter:card" content="summary_large_image" />
|
||||||
<Meta name="twitter:title" content={title()} />
|
<Meta name="twitter:title" content={title()} />
|
||||||
<Meta name="twitter:description" content={description()} />
|
<Meta name="twitter:description" content={description()} />
|
||||||
<FullTopic topic={topic()} />
|
<FullTopic topic={topic()} followers={followers()} authors={topicAuthors()} />
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<div class={clsx(styles.groupControls, 'row group__controls')}>
|
<div class={clsx(styles.groupControls, 'row group__controls')}>
|
||||||
<div class="col-md-16">
|
<div class="col-md-16">
|
||||||
|
|
50
src/components/_shared/Subscribers/Subscribers.module.scss
Normal file
50
src/components/_shared/Subscribers/Subscribers.module.scss
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
.subscribers {
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-flex;
|
||||||
|
margin: 0 1rem 0 0;
|
||||||
|
vertical-align: top;
|
||||||
|
border-bottom: unset !important;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribersItem {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:nth-child(1) {
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(2) {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: -4px;
|
||||||
|
box-shadow: 0 0 0 1px var(--background-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribersCounter {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: none !important;
|
||||||
|
|
||||||
|
.subscribersCounter {
|
||||||
|
background: var(--background-color-invert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribersList {
|
||||||
|
display: flex;
|
||||||
|
margin-right: 0.6rem;
|
||||||
|
}
|
67
src/components/_shared/Subscribers/Subscribers.tsx
Normal file
67
src/components/_shared/Subscribers/Subscribers.tsx
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import { For, Show } from 'solid-js'
|
||||||
|
|
||||||
|
import { useLocalize } from '../../../context/localize'
|
||||||
|
|
||||||
|
import { Author, Topic } from '../../../graphql/schema/core.gen'
|
||||||
|
import { Userpic } from '../../Author/Userpic'
|
||||||
|
|
||||||
|
import styles from './Subscribers.module.scss'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
followers?: Author[]
|
||||||
|
followersAmount?: number
|
||||||
|
following?: Array<Author | Topic>
|
||||||
|
followingAmount?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Subscribers = (props: Props) => {
|
||||||
|
const { t } = useLocalize()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<a href="?m=followers" class={styles.subscribers}>
|
||||||
|
<Show when={props.followers && props.followers.length > 0}>
|
||||||
|
<div class={styles.subscribersList}>
|
||||||
|
<For each={props.followers.slice(0, 3)}>
|
||||||
|
{(f) => <Userpic size={'XS'} name={f.name} userpic={f.pic} class={styles.subscribersItem} />}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
<div class={styles.subscribersCounter}>
|
||||||
|
{t('SubscriberWithCount', {
|
||||||
|
count: props.followersAmount || props.followers.length || 0,
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="?m=following" class={styles.subscribers}>
|
||||||
|
<Show when={props.following && props.following.length > 0}>
|
||||||
|
<div class={styles.subscribersList}>
|
||||||
|
<For each={props.following.slice(0, 3)}>
|
||||||
|
{(f) => {
|
||||||
|
if ('name' in f) {
|
||||||
|
return (
|
||||||
|
<Userpic size={'XS'} name={f.name} userpic={f.pic} class={styles.subscribersItem} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('title' in f) {
|
||||||
|
return (
|
||||||
|
<Userpic size={'XS'} name={f.title} userpic={f.pic} class={styles.subscribersItem} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
<div class={styles.subscribersCounter}>
|
||||||
|
{t('SubscriptionWithCount', {
|
||||||
|
count: props.followingAmount || props.following?.length || 0,
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
1
src/components/_shared/Subscribers/index.ts
Normal file
1
src/components/_shared/Subscribers/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export { Subscribers } from './Subscribers'
|
|
@ -5,6 +5,7 @@ import type {
|
||||||
LoadShoutsOptions,
|
LoadShoutsOptions,
|
||||||
MutationDelete_ShoutArgs,
|
MutationDelete_ShoutArgs,
|
||||||
ProfileInput,
|
ProfileInput,
|
||||||
|
QueryGet_Topic_FollowersArgs,
|
||||||
QueryLoad_Authors_ByArgs,
|
QueryLoad_Authors_ByArgs,
|
||||||
QueryLoad_Shouts_Random_TopArgs,
|
QueryLoad_Shouts_Random_TopArgs,
|
||||||
QueryLoad_Shouts_SearchArgs,
|
QueryLoad_Shouts_SearchArgs,
|
||||||
|
@ -44,6 +45,7 @@ import authorsAll from '../query/core/authors-all'
|
||||||
import authorsLoadBy from '../query/core/authors-load-by'
|
import authorsLoadBy from '../query/core/authors-load-by'
|
||||||
import reactionsLoadBy from '../query/core/reactions-load-by'
|
import reactionsLoadBy from '../query/core/reactions-load-by'
|
||||||
import topicBySlug from '../query/core/topic-by-slug'
|
import topicBySlug from '../query/core/topic-by-slug'
|
||||||
|
import topicFollowers from '../query/core/topic-followers'
|
||||||
import topicsAll from '../query/core/topics-all'
|
import topicsAll from '../query/core/topics-all'
|
||||||
import topicsRandomQuery from '../query/core/topics-random'
|
import topicsRandomQuery from '../query/core/topics-random'
|
||||||
|
|
||||||
|
@ -129,6 +131,11 @@ export const apiClient = {
|
||||||
return response.data.get_author_followers
|
return response.data.get_author_followers
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getTopicFollowers: async ({ slug }: QueryGet_Topic_FollowersArgs): Promise<Author[]> => {
|
||||||
|
const response = await publicGraphQLClient.query(topicFollowers, { slug }).toPromise()
|
||||||
|
return response.data.get_topic_followers
|
||||||
|
},
|
||||||
|
|
||||||
getAuthorFollows: async (params: {
|
getAuthorFollows: async (params: {
|
||||||
slug?: string
|
slug?: string
|
||||||
author_id?: number
|
author_id?: number
|
||||||
|
|
25
src/graphql/query/core/topic-followers.ts
Normal file
25
src/graphql/query/core/topic-followers.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { gql } from '@urql/core'
|
||||||
|
|
||||||
|
export default gql`
|
||||||
|
query TopicFollowersQuery($slug: String) {
|
||||||
|
get_topic_followers(slug: $slug) {
|
||||||
|
id
|
||||||
|
slug
|
||||||
|
name
|
||||||
|
bio
|
||||||
|
about
|
||||||
|
pic
|
||||||
|
# communities
|
||||||
|
links
|
||||||
|
created_at
|
||||||
|
last_seen
|
||||||
|
stat {
|
||||||
|
shouts
|
||||||
|
authors
|
||||||
|
followers
|
||||||
|
rating
|
||||||
|
comments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
|
@ -40,7 +40,7 @@ export const DiscussionRulesPage = () => {
|
||||||
людей рождается истина.
|
людей рождается истина.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3>За что можно получить дырку в карме и выиграть бан в сообществе</h3>
|
<h3 id="ban">За что можно получить дырку в карме и выиграть бан в сообществе</h3>
|
||||||
<ol>
|
<ol>
|
||||||
<li>
|
<li>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { Match, Switch, createEffect, on, onCleanup } from 'solid-js'
|
import { createEffect, on, onCleanup } from 'solid-js'
|
||||||
|
|
||||||
import { AuthGuard } from '../components/AuthGuard'
|
|
||||||
import { Feed } from '../components/Views/Feed'
|
import { Feed } from '../components/Views/Feed'
|
||||||
import { PageLayout } from '../components/_shared/PageLayout'
|
import { PageLayout } from '../components/_shared/PageLayout'
|
||||||
import { useLocalize } from '../context/localize'
|
import { useLocalize } from '../context/localize'
|
||||||
|
@ -32,16 +31,7 @@ export const FeedPage = () => {
|
||||||
return (
|
return (
|
||||||
<PageLayout title={t('Feed')}>
|
<PageLayout title={t('Feed')}>
|
||||||
<ReactionsProvider>
|
<ReactionsProvider>
|
||||||
<Switch fallback={<Feed loadShouts={handleFeedLoadShouts} />}>
|
<Feed loadShouts={page().route === 'feedMy' ? handleMyFeedLoadShouts : handleFeedLoadShouts} />
|
||||||
<Match when={page().route === 'feed'}>
|
|
||||||
<Feed loadShouts={handleFeedLoadShouts} />
|
|
||||||
</Match>
|
|
||||||
<Match when={page().route === 'feedMy'}>
|
|
||||||
<AuthGuard>
|
|
||||||
<Feed loadShouts={handleMyFeedLoadShouts} />
|
|
||||||
</AuthGuard>
|
|
||||||
</Match>
|
|
||||||
</Switch>
|
|
||||||
</ReactionsProvider>
|
</ReactionsProvider>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user