diff --git a/public/icons/copy.svg b/public/icons/copy.svg new file mode 100644 index 00000000..0665732f --- /dev/null +++ b/public/icons/copy.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 8090e2f2..a8bf5807 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -72,6 +72,7 @@ "Choose a post type": "Choose a post type", "Choose a title image for the article. You can immediately see how the publication card will look like.": "Choose a title image for the article. You can immediately see how the publication card will look like.", "Choose who you want to write to": "Choose who you want to write to", + "Close": "Close", "Co-author": "Co-author", "Collaborate": "Help Edit", "Collaborators": "Collaborators", @@ -217,6 +218,7 @@ "Last rev.": "Посл. изм.", "Let's log in": "Let's log in", "Link copied": "Link copied", + "Link copied to clipboard": "Link copied to clipboard", "Link sent, check your email": "Link sent, check your email", "List of authors of the open editorial community": "List of authors of the open editorial community", "Lists": "Lists", @@ -320,6 +322,7 @@ "Send link again": "Send link again", "Settings": "Settings", "Share": "Share", + "Share publication": "Share publication", "Show": "Show", "Show lyrics": "Show lyrics", "Show more": "Show more", @@ -356,6 +359,7 @@ "Suggest an idea": "Suggest an idea", "Support Discours": "Support Discours", "Support the project": "Support the project", + "Support us": "Support us", "Terms of use": "Site rules", "Text checking": "Text checking", "Thank you": "Thank you", diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index 2732e4f8..6638d0de 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -76,6 +76,7 @@ "Choose a post type": "Выберите тип публикации", "Choose a title image for the article. You can immediately see how the publication card will look like.": "Выберите заглавное изображение для статьи. Тут же сразу можно увидеть как будет выглядеть карточка публикации.", "Choose who you want to write to": "Выберите кому хотите написать", + "Close": "Закрыть", "Co-author": "Соавтор", "Collaborate": "Помочь редактировать", "Collaborators": "Соавторы", @@ -229,6 +230,7 @@ "Last rev.": "Посл. изм.", "Let's log in": "Давайте авторизуемся", "Link copied": "Ссылка скопирована", + "Link copied to clipboard": "Ссылка скопирована в буфер обмена", "Link sent, check your email": "Ссылка отправлена, проверьте почту", "List of authors of the open editorial community": "Список авторов сообщества открытой редакции", "Lists": "Списки", @@ -340,6 +342,7 @@ "Send link again": "Прислать ссылку ещё раз", "Settings": "Настройки", "Share": "Поделиться", + "Share publication": "Поделиться публикацией", "Short opening": "Расскажите вашу историю...", "Show": "Показать", "Show lyrics": "Текст песни", @@ -378,6 +381,7 @@ "Suggest an idea": "Предложить идею", "Support Discours": "Поддержите Дискурс", "Support the project": "Поддержать проект", + "Support us": "Помочь журналу", "Terms of use": "Правила сайта", "Text checking": "Проверка текста", "Thank you": "Благодарности", diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx index 1fe89808..cc1b672b 100644 --- a/src/components/Article/FullArticle.tsx +++ b/src/components/Article/FullArticle.tsx @@ -14,12 +14,15 @@ import { MediaItem } from '../../pages/types' import { DEFAULT_HEADER_OFFSET, router, useRouter } from '../../stores/router' import { capitalize } from '../../utils/capitalize' import { isCyrillic } from '../../utils/cyrillic' -import { getImageUrl } from '../../utils/getImageUrl' +import { showModal } from '../../stores/ui' +import { getImageUrl, getOpenGraphImageUrl } from '../../utils/getImageUrl' import { getDescription, getKeywords } from '../../utils/meta' import { Icon } from '../_shared/Icon' import { Image } from '../_shared/Image' +import { InviteCoAuthorsModal } from '../_shared/InviteCoAuthorsModal' import { Lightbox } from '../_shared/Lightbox' import { Popover } from '../_shared/Popover' +import { ShareModal } from '../_shared/ShareModal' import { ImageSwiper } from '../_shared/SolidSwiper' import { VideoPlayer } from '../_shared/VideoPlayer' import { AuthorBadge } from '../Author/AuthorBadge' @@ -60,6 +63,8 @@ const imgSrcRegExp = /]+src\s*=\s*["']([^"']+)["']/gi export const FullArticle = (props: Props) => { const [selectedImage, setSelectedImage] = createSignal('') + const [isReactionsLoaded, setIsReactionsLoaded] = createSignal(false) + const [isActionPopupActive, setIsActionPopupActive] = createSignal(false) const { t, formatDate, lang } = useLocalize() const { @@ -68,8 +73,6 @@ export const FullArticle = (props: Props) => { actions: { requireAuthentication }, } = useSession() - const [isReactionsLoaded, setIsReactionsLoaded] = createSignal(false) - const formattedDate = createMemo(() => formatDate(new Date(props.article.created_at * 1000))) const mainTopic = createMemo(() => { @@ -292,12 +295,19 @@ export const FullArticle = (props: Props) => { } } - const ogImage = props.article.cover - ? getImageUrl(props.article.cover, { width: 1200 }) - : getImageUrl('production/image/logo_image.png') + const cover = props.article.cover ?? 'production/image/logo_image.png' + + const ogImage = getOpenGraphImageUrl(cover, { + title: props.article.title, + topic: mainTopic().title, + author: props.article.authors[0].name, + width: 1200, + }) + const description = getDescription(props.article.description || body()) const ogTitle = props.article.title const keywords = getKeywords(props.article) + const shareUrl = getShareUrl({ pathname: `/${props.article.slug}` }) const getAuthorName = (a: Author) => { return lang() === 'en' && isCyrillic(a.name) ? capitalize(a.slug.replace(/-/, ' ')) : a.name } @@ -426,7 +436,7 @@ export const FullArticle = (props: Props) => { - + {(triggerRef: (el) => void) => (
@@ -453,7 +463,7 @@ export const FullArticle = (props: Props) => {
- + {(triggerRef: (el) => void) => (
{ )} - + {(triggerRef: (el) => void) => (
setIsActionPopupActive(isVisible)} trigger={
@@ -506,9 +518,9 @@ export const FullArticle = (props: Props) => { showModal('share')} + onInviteClick={() => showModal('inviteCoAuthors')} + onVisibilityChange={(isVisible) => setIsActionPopupActive(isVisible)} trigger={ - -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • - + ) } diff --git a/src/components/Feed/ArticleCard/ArticleCard.module.scss b/src/components/Feed/ArticleCard/ArticleCard.module.scss index 9775243c..d3f82554 100644 --- a/src/components/Feed/ArticleCard/ArticleCard.module.scss +++ b/src/components/Feed/ArticleCard/ArticleCard.module.scss @@ -107,7 +107,7 @@ height: 0; margin-bottom: 1.6rem; overflow: hidden; - padding-bottom: 56.2%; //16:9 + padding-bottom: 56.2%; // 16:9 position: relative; transform-origin: 50% 50%; transition: transform 1s ease-in-out; diff --git a/src/components/Feed/ArticleCard/ArticleCard.tsx b/src/components/Feed/ArticleCard/ArticleCard.tsx index 89a80b74..2b4879aa 100644 --- a/src/components/Feed/ArticleCard/ArticleCard.tsx +++ b/src/components/Feed/ArticleCard/ArticleCard.tsx @@ -7,11 +7,14 @@ import { createMemo, createSignal, For, Show } from 'solid-js' import { useLocalize } from '../../../context/localize' import { useSession } from '../../../context/session' import { router, useRouter } from '../../../stores/router' +import { showModal } from '../../../stores/ui' import { capitalize } from '../../../utils/capitalize' import { getDescription } from '../../../utils/meta' import { Icon } from '../../_shared/Icon' import { Image } from '../../_shared/Image' +import { InviteCoAuthorsModal } from '../../_shared/InviteCoAuthorsModal' import { Popover } from '../../_shared/Popover' +import { ShareModal } from '../../_shared/ShareModal' import { CoverImage } from '../../Article/CoverImage' import { getShareUrl, SharePopup } from '../../Article/SharePopup' import { ShoutRatingControl } from '../../Article/ShoutRatingControl' @@ -310,7 +313,7 @@ export const ArticleCard = (props: ArticleCardProps) => {
    - + {(triggerRef: (el) => void) => (
    @@ -325,7 +328,7 @@ export const ArticleCard = (props: ArticleCardProps) => { - + {(triggerRef: (el) => void) => (
    + + ) } diff --git a/src/components/Feed/FeedArticlePopup/FeedArticlePopup.module.scss b/src/components/Feed/FeedArticlePopup/FeedArticlePopup.module.scss index c983fe14..54b1df3a 100644 --- a/src/components/Feed/FeedArticlePopup/FeedArticlePopup.module.scss +++ b/src/components/Feed/FeedArticlePopup/FeedArticlePopup.module.scss @@ -5,6 +5,7 @@ padding: 0 !important; text-align: left; overflow: hidden; + margin-top: -14px; @include media-breakpoint-down(md) { left: auto !important; @@ -30,6 +31,10 @@ &.soon { color: var(--black-300); + display: flex; + gap: 0.6rem; + width: 100%; + justify-content: space-between; } &:hover { @@ -41,6 +46,7 @@ li:first-child .action { padding-top: 16px; } + li:last-child .action { padding-bottom: 16px; } diff --git a/src/components/Feed/FeedArticlePopup/FeedArticlePopup.tsx b/src/components/Feed/FeedArticlePopup/FeedArticlePopup.tsx index 3e237307..0c5db941 100644 --- a/src/components/Feed/FeedArticlePopup/FeedArticlePopup.tsx +++ b/src/components/Feed/FeedArticlePopup/FeedArticlePopup.tsx @@ -1,29 +1,31 @@ import type { PopupProps } from '../../_shared/Popup' import { clsx } from 'clsx' -import { createEffect, createSignal, Show } from 'solid-js' +import { Show } from 'solid-js' import { useLocalize } from '../../../context/localize' -import { showModal } from '../../../stores/ui' -import { InviteCoAuthorsModal } from '../../_shared/InviteCoAuthorsModal' import { Popup } from '../../_shared/Popup' import { SoonChip } from '../../_shared/SoonChip' import styles from './FeedArticlePopup.module.scss' type FeedArticlePopupProps = { - title: string - imageUrl: string isOwner: boolean - description: string + onInviteClick: () => void + onShareClick: () => void } & Omit export const FeedArticlePopup = (props: FeedArticlePopupProps) => { const { t } = useLocalize() return ( <> - +
      +
    • + +
    • -
    • @@ -86,7 +82,6 @@ export const FeedArticlePopup = (props: FeedArticlePopupProps) => { {/**/}
    - ) } diff --git a/src/components/Nav/AuthModal/PasswordField/PasswordField.tsx b/src/components/Nav/AuthModal/PasswordField/PasswordField.tsx index 9abf237b..b81001f4 100644 --- a/src/components/Nav/AuthModal/PasswordField/PasswordField.tsx +++ b/src/components/Nav/AuthModal/PasswordField/PasswordField.tsx @@ -2,7 +2,6 @@ import { clsx } from 'clsx' import { createEffect, createSignal, on, Show } from 'solid-js' import { useLocalize } from '../../../../context/localize' -// import { resetSortedArticles } from '../../../../stores/zine/articles' import { Icon } from '../../../_shared/Icon' import styles from './PasswordField.module.scss' diff --git a/src/components/Nav/Modal/Modal.module.scss b/src/components/Nav/Modal/Modal.module.scss index 17ae7940..8229d5f0 100644 --- a/src/components/Nav/Modal/Modal.module.scss +++ b/src/components/Nav/Modal/Modal.module.scss @@ -1,7 +1,7 @@ .backdrop { align-items: center; - background: rgb(20 20 20 / 70%); display: flex; + background: rgb(20 20 20 / 7%); justify-content: center; height: 100%; left: 0; @@ -17,6 +17,7 @@ background: var(--background-color); max-width: 1000px; position: relative; + z-index: 1; &:not([class*='col-']) { width: 100%; @@ -124,11 +125,13 @@ .maxHeight { height: 100%; } + .container { padding: 0; height: 100%; min-height: 100%; } + .modalInner { padding: 1rem 1rem 0; height: 100%; diff --git a/src/components/TableOfContents/TableOfContents.module.scss b/src/components/TableOfContents/TableOfContents.module.scss index 84785a04..2e5fe4ac 100644 --- a/src/components/TableOfContents/TableOfContents.module.scss +++ b/src/components/TableOfContents/TableOfContents.module.scss @@ -1,6 +1,7 @@ .TableOfContentsFixedWrapper { min-height: 100%; position: relative; + z-index: 1; top: 0; @include media-breakpoint-down(xl) { diff --git a/src/components/Topic/TopicBadge/TopicBadge.module.scss b/src/components/Topic/TopicBadge/TopicBadge.module.scss index 3ca2a2d1..e5166ef1 100644 --- a/src/components/Topic/TopicBadge/TopicBadge.module.scss +++ b/src/components/Topic/TopicBadge/TopicBadge.module.scss @@ -7,9 +7,8 @@ .basicInfo { display: flex; - flex-direction: row; + flex-flow: row nowrap; align-items: flex-start; - flex-wrap: nowrap; flex: 1; gap: 1rem; } diff --git a/src/components/Views/Expo/Expo.module.scss b/src/components/Views/Expo/Expo.module.scss index bb32f0b4..190b4243 100644 --- a/src/components/Views/Expo/Expo.module.scss +++ b/src/components/Views/Expo/Expo.module.scss @@ -4,10 +4,6 @@ padding: 0 0 4rem; min-height: 100vh; - .navigation { - padding: 0; - } - .showMore { display: flex; width: 100%; diff --git a/src/components/Views/Expo/Expo.tsx b/src/components/Views/Expo/Expo.tsx index 12bf38e1..f50f3ed0 100644 --- a/src/components/Views/Expo/Expo.tsx +++ b/src/components/Views/Expo/Expo.tsx @@ -147,7 +147,7 @@ export const Expo = (props: Props) => {
    0} fallback={}>
    -
      +
      • li { margin-bottom: 0; @@ -213,8 +215,7 @@ .dropdowns { display: flex; - flex-direction: row; - flex-wrap: nowrap; + flex-flow: row nowrap; gap: 1rem; justify-content: center; } diff --git a/src/components/Views/Feed/Feed.tsx b/src/components/Views/Feed/Feed.tsx index ddc26304..57c5d9c8 100644 --- a/src/components/Views/Feed/Feed.tsx +++ b/src/components/Views/Feed/Feed.tsx @@ -269,6 +269,7 @@ export const FeedView = (props: Props) => {
        { /> = { class?: string - popupProps?: PopupProps + popupProps?: Partial options: TOption[] currentOption: TOption triggerCssClass?: string @@ -56,9 +56,12 @@ export const DropDown = (props: Props) onVisibilityChange={(isVisible) => setIsPopupVisible(isVisible)} {...props.popupProps} > - p.value !== props.currentOption.value)}> + {(option) => ( -