From cf7aec3e1c4f66699adbfb0368f73b957a3e9ffd Mon Sep 17 00:00:00 2001 From: dog Date: Tue, 19 Dec 2023 16:12:11 +0300 Subject: [PATCH 01/88] prepare search modal, refactor search fetch, handle intersection, etc. --- public/locales/en/translation.json | 1 + public/locales/ru/translation.json | 1 + .../Feed/ArticleCard/ArticleCard.tsx | 4 +- .../Nav/SearchModal/SearchModal.module.scss | 61 ++-- .../Nav/SearchModal/SearchModal.tsx | 276 ++++++++++-------- src/styles/app.scss | 5 + 6 files changed, 206 insertions(+), 142 deletions(-) diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 8cfdc076..61dfd54f 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -335,6 +335,7 @@ "This post has not been rated yet": "This post has not been rated yet", "This way we ll realize that you re a real person and ll take your vote into account. And you ll see how others voted": "This way we ll realize that you re a real person and ll take your vote into account. And you ll see how others voted", "This way you ll be able to subscribe to authors, interesting topics and customize your feed": "This way you ll be able to subscribe to authors, interesting topics and customize your feed", + "To find publications, art, comments, authors and topics of interest to you, just start typing your query": "To find publications, art, comments, authors and topics of interest to you, just start typing your query", "To leave a comment please": "To leave a comment please", "To write a comment, you must": "To write a comment, you must", "Top authors": "Authors rating", diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index 1c379fac..9075a05e 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -353,6 +353,7 @@ "This post has not been rated yet": "Эту публикацию еще пока никто не оценил", "This way we ll realize that you re a real person and ll take your vote into account. And you ll see how others voted": "Так мы поймем, что вы реальный человек, и учтем ваш голос. А вы увидите, как проголосовали другие", "This way you ll be able to subscribe to authors, interesting topics and customize your feed": "Так вы сможете подписаться на авторов, интересные темы и настроить свою ленту", + "To find publications, art, comments, authors and topics of interest to you, just start typing your query": "Для поиска публикаций, искусства, комментариев, интересных вам авторов и тем, просто начните вводить ваш запрос", "To leave a comment please": "Чтобы оставить комментарий, необходимо", "To write a comment, you must": "Чтобы написать комментарий, необходимо", "Top authors": "Рейтинг авторов", diff --git a/src/components/Feed/ArticleCard/ArticleCard.tsx b/src/components/Feed/ArticleCard/ArticleCard.tsx index 97f1b8ee..9c0eda98 100644 --- a/src/components/Feed/ArticleCard/ArticleCard.tsx +++ b/src/components/Feed/ArticleCard/ArticleCard.tsx @@ -161,13 +161,13 @@ export const ArticleCard = (props: ArticleCardProps) => {
- {title} +
- {subtitle} +
diff --git a/src/components/Nav/SearchModal/SearchModal.module.scss b/src/components/Nav/SearchModal/SearchModal.module.scss index 54c4114b..e0dc9801 100644 --- a/src/components/Nav/SearchModal/SearchModal.module.scss +++ b/src/components/Nav/SearchModal/SearchModal.module.scss @@ -1,11 +1,14 @@ @mixin searchFilterControl { + @include font-size(1.4rem); + + height: 4rem; + + padding: 0 2rem; + background: rgb(64 64 64 / 0.5); border-radius: 10rem; color: #fff; - @include font-size(1.4rem); font-weight: 500; - height: 4rem; - padding: 0 2rem; white-space: nowrap; &:hover { @@ -17,42 +20,50 @@ } } -.searchForm { +.searchContainer { position: relative; +} - .searchField { - background: none; - border: none; - border-bottom: 2px solid #fff; - color: #fff; - @include font-size(4.8rem); - font-weight: bold; - outline: none; - padding: 0 0 0.5rem; +.searchInput { + @include font-size(4.8rem); - &::placeholder { - color: rgb(255 255 255 / 0.32); - } + width: 100%; - &:not(:placeholder-shown) + .submitControl { - display: block; - } + padding: 0 0 0.5rem; + + background: none; + border: none; + border-bottom: 2px solid #fff; + color: #fff; + font-weight: bold; + outline: none; + + &::placeholder { + color: rgb(255 255 255 / 0.32); + } + + &:not(:placeholder-shown) + .searchButton img { + filter: invert(1); } } -.submitControl { - display: none; - filter: invert(1); - height: 3.2rem; +.searchButton { position: absolute; right: 0; top: 2rem; + width: 3.2rem; + height: 3.2rem; + + & img { + filter: invert(0.4); + } } .searchDescription { - color: rgb(255 255 255 / 0.64); @include font-size(1.6rem); + + color: rgb(255 255 255 / 0.64); } .topicsList { @@ -60,6 +71,7 @@ flex-wrap: wrap; justify-content: center; gap: 1rem; + margin-top: 9.6rem !important; } @@ -90,6 +102,7 @@ display: flex; flex-wrap: wrap; gap: 1rem; + margin: 6.4rem 0; } diff --git a/src/components/Nav/SearchModal/SearchModal.tsx b/src/components/Nav/SearchModal/SearchModal.tsx index 6c2e1c7e..456a88d3 100644 --- a/src/components/Nav/SearchModal/SearchModal.tsx +++ b/src/components/Nav/SearchModal/SearchModal.tsx @@ -1,47 +1,103 @@ -import { hideModal } from '../../../stores/ui' -import { useLocalize } from '../../../context/localize' -import { Button } from '../../_shared/Button' -import styles from './SearchModal.module.scss' -import { Icon } from '../../_shared/Icon' import clsx from 'clsx' +import { createSignal, Show, For } from 'solid-js' + +import { ArticleCard } from '../../Feed/ArticleCard' +import { Button } from '../../_shared/Button' +import { Icon } from '../../_shared/Icon' + +// import { PRERENDERED_ARTICLES_COUNT } from '../../Views/Home' + +// import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll' + +import type { Shout } from '../../../graphql/types.gen' +import { useLocalize } from '../../../context/localize' + +import styles from './SearchModal.module.scss' + +// @@TODO implement search +// @@TODO implement throttling + +// @@TODO implement load more (await ...({ filters: { .. }, limit: .., offset: .. })) +// @@TODO implement modal hiding on article click +// @@TODO search url as const +// @@TODO refactor switcher, filters, topics + +const getSearchCoincidences = ({ str, intersection }) => + `${str.replace( + new RegExp(intersection, 'g'), + `${intersection}` + )}` export const SearchModal = () => { const { t } = useLocalize() - const action = '/search' - const method = 'get' - let msgElement: HTMLTextAreaElement | undefined - let contactElement: HTMLInputElement | undefined - const submit = async () => { - await fetch(action, { - method, - headers: { - accept: 'application/json', - 'content-type': 'application/json; charset=utf-8' - }, - body: JSON.stringify({ contact: contactElement?.value, message: msgElement?.textContent }) - }) - // hideModal() + const searchInputRef: { current: HTMLInputElement } = { current: null } + + const [isSearching, setIsSearching] = createSignal(false) + const [searchResultsList, setSearchResultsList] = createSignal([]) + // const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) + + const handleSearch = async () => { + const searchValue = searchInputRef.current?.value || '' + + if (Boolean(searchValue)) { + await fetch(`https://search.discours.io/search?q=${searchValue}`, { + method: 'GET', + headers: { + accept: 'application/json', + 'content-type': 'application/json; charset=utf-8' + } + }) + .then((data) => data.json()) + .then((data) => { + console.log(data) + + // if (data.length) { + // const preparedSearchResultsList = [].map((article) => ({ + // ...article, + // title: getSearchCoincidences({ + // str: article.title, + // intersection: searchInputRef.current?.value || '' + // }), + // subtitle: getSearchCoincidences({ + // str: article.subtitle, + // intersection: searchInputRef.current?.value || '' + // }) + // })) + // setSearchResultsList(preparedSearchResultsList) + // } else { + // // @@TODO handle no search results notice + // } + }) + .catch((error) => { + console.log('search request failed', error) + }) + } } return ( -
+
(searchInputRef.current = el)} + class={styles.searchInput} + onInput={handleSearch} + onFocusIn={() => setIsSearching(true)} + onFocusOut={() => setIsSearching(false)} /> - -

- Для поиска публикаций, искусства, комментариев, интересных вам авторов и тем, просто начните - вводить ваш запрос -

-
    + @@ -51,95 +107,83 @@ export const SearchModal = () => {
  • -
+ */} -
- - - - - - -
+ {/* @@TODO handle filter */} + {/* +
+ + {(filter) => ( + + )} + +
+
*/} -
+ {/* */} + + {/* */} + + {(article: Shout) => ( + + )} + + + {/* @@TODO handle load more */} + {/* +

+ +

+
*/} +
+ + {/* @@TODO handle topics */} + {/*
- - - - - - - - - - - - - - - - - - - - + {topics.map((topic) => ( + + ))}
-
- +
*/} +
) } diff --git a/src/styles/app.scss b/src/styles/app.scss index 44b7e5a0..c861b448 100644 --- a/src/styles/app.scss +++ b/src/styles/app.scss @@ -1036,3 +1036,8 @@ iframe { .cursorPointer { cursor: pointer; } + +.blackModeIntersection { + color: var(--default-color); + background: #fef2f2; +} From f520de9d52dcaf4593567d1d57a9d171b2f55571 Mon Sep 17 00:00:00 2001 From: dog Date: Wed, 20 Dec 2023 16:19:31 +0300 Subject: [PATCH 02/88] add search loader & refactor results rendering --- public/locales/en/translation.json | 1 + public/locales/ru/translation.json | 1 + .../Nav/SearchModal/SearchModal.module.scss | 21 ++ .../Nav/SearchModal/SearchModal.tsx | 182 +++++++++--------- src/utils/config.ts | 3 + 5 files changed, 117 insertions(+), 91 deletions(-) diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 61dfd54f..5ed8ca8d 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -363,6 +363,7 @@ "Video": "Video", "Video format not supported": "Video format not supported", "Views": "Views", + "We couldn't find anything for your request": "We couldn’t find anything for your request", "We can't find you, check email or": "We can't find you, check email or", "We know you, please try to login": "This email address is already registered, please try to login", "We've sent you a message with a link to enter our website.": "We've sent you an email with a link to your email. Follow the link in the email to enter our website.", diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index 9075a05e..c5d4348c 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -381,6 +381,7 @@ "Video": "Видео", "Video format not supported": "Тип видео не поддерживается", "Views": "Просмотры", + "We couldn't find anything for your request": "Мы не смогли ничего найти по вашему запросу", "We can't find you, check email or": "Не можем вас найти, проверьте адрес электронной почты или", "We know you, please try to login": "Такой адрес почты уже зарегистрирован, попробуйте залогиниться", "We've sent you a message with a link to enter our website.": "Мы выслали вам письмо с ссылкой на почту. Перейдите по ссылке в письме, чтобы войти на сайт.", diff --git a/src/components/Nav/SearchModal/SearchModal.module.scss b/src/components/Nav/SearchModal/SearchModal.module.scss index e0dc9801..0a7e40ec 100644 --- a/src/components/Nav/SearchModal/SearchModal.module.scss +++ b/src/components/Nav/SearchModal/SearchModal.module.scss @@ -109,3 +109,24 @@ .filterResultsControl { @include searchFilterControl; } + +.searchLoader { + width: 28px; + height: 28px; + + border: 5px solid #fff; + border-bottom-color: transparent; + border-radius: 50%; + + animation: rotation 1s linear infinite; +} + +@keyframes rotation { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} diff --git a/src/components/Nav/SearchModal/SearchModal.tsx b/src/components/Nav/SearchModal/SearchModal.tsx index 456a88d3..e756edef 100644 --- a/src/components/Nav/SearchModal/SearchModal.tsx +++ b/src/components/Nav/SearchModal/SearchModal.tsx @@ -5,22 +5,16 @@ import { ArticleCard } from '../../Feed/ArticleCard' import { Button } from '../../_shared/Button' import { Icon } from '../../_shared/Icon' -// import { PRERENDERED_ARTICLES_COUNT } from '../../Views/Home' - -// import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll' - import type { Shout } from '../../../graphql/types.gen' + +import { searchUrl } from '../../../utils/config' + import { useLocalize } from '../../../context/localize' import styles from './SearchModal.module.scss' -// @@TODO implement search -// @@TODO implement throttling - +// @@TODO handle founded shouts rendering (cors) // @@TODO implement load more (await ...({ filters: { .. }, limit: .., offset: .. })) -// @@TODO implement modal hiding on article click -// @@TODO search url as const -// @@TODO refactor switcher, filters, topics const getSearchCoincidences = ({ str, intersection }) => `${str.replace( @@ -33,15 +27,17 @@ export const SearchModal = () => { const searchInputRef: { current: HTMLInputElement } = { current: null } - const [isSearching, setIsSearching] = createSignal(false) - const [searchResultsList, setSearchResultsList] = createSignal([]) - // const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) + const [searchResultsList, setSearchResultsList] = createSignal<[] | null>([]) + const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) + const [isLoading, setIsLoading] = createSignal(false) const handleSearch = async () => { const searchValue = searchInputRef.current?.value || '' if (Boolean(searchValue)) { - await fetch(`https://search.discours.io/search?q=${searchValue}`, { + setIsLoading(true) + + await fetch(`${searchUrl}=${searchValue}`, { method: 'GET', headers: { accept: 'application/json', @@ -50,10 +46,8 @@ export const SearchModal = () => { }) .then((data) => data.json()) .then((data) => { - console.log(data) - - // if (data.length) { - // const preparedSearchResultsList = [].map((article) => ({ + // if (data.what) { + // const preparedSearchResultsList = data.what.map((article) => ({ // ...article, // title: getSearchCoincidences({ // str: article.title, @@ -62,19 +56,27 @@ export const SearchModal = () => { // subtitle: getSearchCoincidences({ // str: article.subtitle, // intersection: searchInputRef.current?.value || '' - // }) + // }), // })) + // // setSearchResultsList(preparedSearchResultsList) + // + // @@TODO handle setIsLoadMoreButtonVisible() // } else { - // // @@TODO handle no search results notice + // setSearchResultsList(null) // } }) .catch((error) => { console.log('search request failed', error) }) + .finally(() => { + setIsLoading(false) + }) } } + const loadMore = () => {} + return (
{ ref={(el) => (searchInputRef.current = el)} class={styles.searchInput} onInput={handleSearch} - onFocusIn={() => setIsSearching(true)} - onFocusOut={() => setIsSearching(false)} /> - - -
  • - -
  • -
  • - -
  • - */} + {/* */} + + + {/* */} + + {(article: Shout) => ( + + )} + + + +

    + +

    +
    +
    + + +

    + + {/* @@TODO handle filter */} {/* @@ -119,71 +161,29 @@ export const SearchModal = () => { class={styles.filterResultsControl} onClick={() => setActiveFilter(filter)} > - Период времени + {filter.name} )}

    */} - {/* */} - - {/* */} - - {(article: Shout) => ( - - )} - - - {/* @@TODO handle load more */} - {/* -

    - -

    -
    */} -
    - {/* @@TODO handle topics */} - {/*
    -
    -
    - {topics.map((topic) => ( - - ))} + {/* +
    +
    +
    + + {(topic) => ( + + )} + +
    -
    */} + */}
    ) } diff --git a/src/utils/config.ts b/src/utils/config.ts index 3039e213..e83e9735 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -7,3 +7,6 @@ const defaultThumborUrl = 'https://images.discours.io' export const thumborUrl = import.meta.env.PUBLIC_THUMBOR_URL || defaultThumborUrl export const SENTRY_DSN = import.meta.env.PUBLIC_SENTRY_DSN || '' + +const defaultSearchUrl = 'https://search.discours.io/search?q' +export const searchUrl = import.meta.env.PUBLIC_SEARCH_URL || defaultSearchUrl From c78d5b33374d94ab7aa1b288f3f111f35f9d81bd Mon Sep 17 00:00:00 2001 From: dog Date: Tue, 9 Jan 2024 16:37:35 +0300 Subject: [PATCH 03/88] render search results & refactor search modal --- src/components/Nav/Modal/Modal.module.scss | 7 ++ .../Nav/SearchModal/SearchModal.module.scss | 6 + .../Nav/SearchModal/SearchModal.tsx | 117 ++++++++---------- 3 files changed, 68 insertions(+), 62 deletions(-) diff --git a/src/components/Nav/Modal/Modal.module.scss b/src/components/Nav/Modal/Modal.module.scss index 8e99ddc6..3b34b8e3 100644 --- a/src/components/Nav/Modal/Modal.module.scss +++ b/src/components/Nav/Modal/Modal.module.scss @@ -88,6 +88,13 @@ position: relative; text-align: left; + &::-webkit-scrollbar { + display: none; + } + + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + @include media-breakpoint-up(sm) { padding: 5rem; } diff --git a/src/components/Nav/SearchModal/SearchModal.module.scss b/src/components/Nav/SearchModal/SearchModal.module.scss index 0a7e40ec..1dbc5039 100644 --- a/src/components/Nav/SearchModal/SearchModal.module.scss +++ b/src/components/Nav/SearchModal/SearchModal.module.scss @@ -45,6 +45,11 @@ &:not(:placeholder-shown) + .searchButton img { filter: invert(1); } + + &::-moz-selection, + &::selection { + color: #2638d9; + } } .searchButton { @@ -61,6 +66,7 @@ } .searchDescription { + margin-bottom: 44px; @include font-size(1.6rem); color: rgb(255 255 255 / 0.64); diff --git a/src/components/Nav/SearchModal/SearchModal.tsx b/src/components/Nav/SearchModal/SearchModal.tsx index e756edef..d31ce669 100644 --- a/src/components/Nav/SearchModal/SearchModal.tsx +++ b/src/components/Nav/SearchModal/SearchModal.tsx @@ -1,4 +1,3 @@ -import clsx from 'clsx' import { createSignal, Show, For } from 'solid-js' import { ArticleCard } from '../../Feed/ArticleCard' @@ -10,16 +9,18 @@ import type { Shout } from '../../../graphql/types.gen' import { searchUrl } from '../../../utils/config' import { useLocalize } from '../../../context/localize' +import { hideModal } from '../../../stores/ui' import styles from './SearchModal.module.scss' -// @@TODO handle founded shouts rendering (cors) -// @@TODO implement load more (await ...({ filters: { .. }, limit: .., offset: .. })) +// @@TODO handle empty article options after backend support (subtitle, cover, etc.) +// @@TODO implement load more +// @@TODO implement FILTERS & TOPICS -const getSearchCoincidences = ({ str, intersection }) => +const getSearchCoincidences = ({ str, intersection }: { str: string; intersection: string }) => `${str.replace( - new RegExp(intersection, 'g'), - `${intersection}` + new RegExp(intersection, 'gi'), + (casePreservedMatch) => `${casePreservedMatch}` )}` export const SearchModal = () => { @@ -28,8 +29,8 @@ export const SearchModal = () => { const searchInputRef: { current: HTMLInputElement } = { current: null } const [searchResultsList, setSearchResultsList] = createSignal<[] | null>([]) - const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) const [isLoading, setIsLoading] = createSignal(false) + // const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) const handleSearch = async () => { const searchValue = searchInputRef.current?.value || '' @@ -46,25 +47,34 @@ export const SearchModal = () => { }) .then((data) => data.json()) .then((data) => { - // if (data.what) { - // const preparedSearchResultsList = data.what.map((article) => ({ - // ...article, - // title: getSearchCoincidences({ - // str: article.title, - // intersection: searchInputRef.current?.value || '' - // }), - // subtitle: getSearchCoincidences({ - // str: article.subtitle, - // intersection: searchInputRef.current?.value || '' - // }), - // })) - // - // setSearchResultsList(preparedSearchResultsList) - // - // @@TODO handle setIsLoadMoreButtonVisible() - // } else { - // setSearchResultsList(null) - // } + if (data.length) { + const preparedSearchResultsList = data.map((article, index) => ({ + ...article, + body: '', + cover: '', + createdAt: '', + id: index, + slug: article.slug, + authors: [], + topics: [], + title: article.title + ? getSearchCoincidences({ + str: article.title, + intersection: searchInputRef.current?.value || '' + }) + : '', + subtitle: article.subtitle + ? getSearchCoincidences({ + str: article.subtitle, + intersection: searchInputRef.current?.value || '' + }) + : '' + })) + + setSearchResultsList(preparedSearchResultsList) + } else { + setSearchResultsList(null) + } }) .catch((error) => { console.log('search request failed', error) @@ -75,7 +85,9 @@ export const SearchModal = () => { } } - const loadMore = () => {} + const handleArticleClick = () => { + hideModal() + } return (
    @@ -100,50 +112,31 @@ export const SearchModal = () => { )} /> - {/* */} - - - {/* */} - + + + {(article: Shout) => ( - +
    + +
    )}
    - + {/*

    -
    +
    */}
    From 6752d35491368e9d8182e1b9c9f52a25d962902c Mon Sep 17 00:00:00 2001 From: dog Date: Sun, 21 Jan 2024 15:57:03 +0300 Subject: [PATCH 04/88] refactor by review comments --- package.json | 3 +- .../Feed/ArticleCard/ArticleCard.tsx | 19 ++- src/components/Nav/HeaderAuth.tsx | 4 +- .../Nav/SearchModal/SearchModal.tsx | 109 ++++++++---------- .../Nav/SearchModal/SearchResultItem.tsx | 33 ++++++ src/utils/apiClient.ts | 15 +++ src/utils/config.ts | 2 +- 7 files changed, 118 insertions(+), 67 deletions(-) create mode 100644 src/components/Nav/SearchModal/SearchResultItem.tsx diff --git a/package.json b/package.json index 988290eb..7d39da8d 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "i18next-icu": "2.3.0", "intl-messageformat": "10.5.3", "just-throttle": "4.2.0", - "mailgun.js": "8.2.1" + "mailgun.js": "8.2.1", + "sanitize-html": "2.11.0" }, "devDependencies": { "@babel/core": "7.21.8", diff --git a/src/components/Feed/ArticleCard/ArticleCard.tsx b/src/components/Feed/ArticleCard/ArticleCard.tsx index 9c0eda98..7c381e96 100644 --- a/src/components/Feed/ArticleCard/ArticleCard.tsx +++ b/src/components/Feed/ArticleCard/ArticleCard.tsx @@ -1,4 +1,6 @@ import { createMemo, createSignal, For, Show } from 'solid-js' +import sanitizeHtml from 'sanitize-html' + import type { Shout } from '../../../graphql/types.gen' import { capitalize } from '../../../utils/capitalize' import { Icon } from '../../_shared/Icon' @@ -70,6 +72,14 @@ const getTitleAndSubtitle = ( return { title, subtitle } } +const sanitizeString = (html) => + sanitizeHtml(html, { + allowedTags: ['span'], + allowedAttributes: { + span: ['class'] + } + }) + export const ArticleCard = (props: ArticleCardProps) => { const { t, lang, formatDate } = useLocalize() const { user } = useSession() @@ -161,13 +171,13 @@ export const ArticleCard = (props: ArticleCardProps) => {
    - +
    - +
    @@ -191,7 +201,10 @@ export const ArticleCard = (props: ArticleCardProps) => {
    -
    +
    diff --git a/src/components/Nav/HeaderAuth.tsx b/src/components/Nav/HeaderAuth.tsx index 1678391e..49542fb9 100644 --- a/src/components/Nav/HeaderAuth.tsx +++ b/src/components/Nav/HeaderAuth.tsx @@ -124,10 +124,10 @@ export const HeaderAuth = (props: Props) => {
    - +
    diff --git a/src/components/Nav/SearchModal/SearchModal.tsx b/src/components/Nav/SearchModal/SearchModal.tsx index d31ce669..d118dcc0 100644 --- a/src/components/Nav/SearchModal/SearchModal.tsx +++ b/src/components/Nav/SearchModal/SearchModal.tsx @@ -1,15 +1,13 @@ -import { createSignal, Show, For } from 'solid-js' +import { createSignal, Show, For, JSX } from 'solid-js' -import { ArticleCard } from '../../Feed/ArticleCard' import { Button } from '../../_shared/Button' import { Icon } from '../../_shared/Icon' +import { SearchResultItem } from './SearchResultItem' +import { apiClient } from '../../../utils/apiClient' import type { Shout } from '../../../graphql/types.gen' -import { searchUrl } from '../../../utils/config' - import { useLocalize } from '../../../context/localize' -import { hideModal } from '../../../stores/ui' import styles from './SearchModal.module.scss' @@ -26,77 +24,68 @@ const getSearchCoincidences = ({ str, intersection }: { str: string; intersectio export const SearchModal = () => { const { t } = useLocalize() - const searchInputRef: { current: HTMLInputElement } = { current: null } - + const [inputValue, setInputValue] = createSignal('') const [searchResultsList, setSearchResultsList] = createSignal<[] | null>([]) const [isLoading, setIsLoading] = createSignal(false) // const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) const handleSearch = async () => { - const searchValue = searchInputRef.current?.value || '' + const searchValue = inputValue() || '' - if (Boolean(searchValue)) { + if (Boolean(searchValue) && searchValue.length > 2) { setIsLoading(true) - await fetch(`${searchUrl}=${searchValue}`, { - method: 'GET', - headers: { - accept: 'application/json', - 'content-type': 'application/json; charset=utf-8' + try { + const response = await apiClient.getSearchResults(searchValue) + const searchResult = await response.json() + + if (searchResult.length) { + const preparedSearchResultsList = searchResult.map((article, index) => ({ + ...article, + body: '', + cover: '', + createdAt: '', + id: index, + slug: article.slug, + authors: [], + topics: [], + title: article.title + ? getSearchCoincidences({ + str: article.title, + intersection: searchValue + }) + : '', + subtitle: article.subtitle + ? getSearchCoincidences({ + str: article.subtitle, + intersection: searchValue + }) + : '' + })) + + setSearchResultsList(preparedSearchResultsList) + } else { + setSearchResultsList(null) } - }) - .then((data) => data.json()) - .then((data) => { - if (data.length) { - const preparedSearchResultsList = data.map((article, index) => ({ - ...article, - body: '', - cover: '', - createdAt: '', - id: index, - slug: article.slug, - authors: [], - topics: [], - title: article.title - ? getSearchCoincidences({ - str: article.title, - intersection: searchInputRef.current?.value || '' - }) - : '', - subtitle: article.subtitle - ? getSearchCoincidences({ - str: article.subtitle, - intersection: searchInputRef.current?.value || '' - }) - : '' - })) - - setSearchResultsList(preparedSearchResultsList) - } else { - setSearchResultsList(null) - } - }) - .catch((error) => { - console.log('search request failed', error) - }) - .finally(() => { - setIsLoading(false) - }) + } catch (error) { + console.log('search request failed', error) + } finally { + setIsLoading(false) + } } } - const handleArticleClick = () => { - hideModal() - } - return (
    (searchInputRef.current = el)} class={styles.searchInput} - onInput={handleSearch} + onInput={(event) => { + setInputValue(event.target.value) + + handleSearch() + }} /> +
    +
    + +
    +
    (uploading() ? undefined : setDropZoneActive(true))} + onDragLeave={() => setDropZoneActive(false)} + onDragOver={noPropagate} + onDrop={(event) => (uploading() ? noPropagate(event) : handleFileDrop(event))} + > +
    upload
    + +
    +
    + + + + ) +} From d429f4cbdf70cabcc1e5511108feff69bef8726d Mon Sep 17 00:00:00 2001 From: dog Date: Sun, 21 Jan 2024 16:52:36 +0300 Subject: [PATCH 06/88] sync lock files --- package-lock.json | 144 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 137 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index f25bccad..332da02c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,9 @@ "i18next": "22.4.15", "i18next-icu": "2.3.0", "intl-messageformat": "10.5.3", - "mailgun.js": "8.2.1" + "just-throttle": "4.2.0", + "mailgun.js": "8.2.1", + "sanitize-html": "2.11.0" }, "devDependencies": { "@babel/core": "7.23.3", @@ -8069,7 +8071,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -8218,6 +8219,68 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dot-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", @@ -10510,6 +10573,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", @@ -13771,6 +13863,11 @@ "node": ">=4.0" } }, + "node_modules/just-throttle": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/just-throttle/-/just-throttle-4.2.0.tgz", + "integrity": "sha512-/iAZv1953JcExpvsywaPKjSzfTiCLqeguUTE6+VmK15mOcwxBx7/FHrVvS4WEErMR03TRazH8kcBSHqMagYIYg==" + }, "node_modules/kebab-case": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/kebab-case/-/kebab-case-1.0.2.tgz", @@ -15144,7 +15241,6 @@ "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, "funding": [ { "type": "github", @@ -15655,6 +15751,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" + }, "node_modules/pascal-case": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", @@ -15741,8 +15842,7 @@ "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -15854,7 +15954,6 @@ "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -16933,6 +17032,38 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "node_modules/sanitize-html": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.11.0.tgz", + "integrity": "sha512-BG68EDHRaGKqlsNjJ2xUB7gpInPA8gVx/mvjO743hZaeMCZ2DwzW7xvsqZ+KNU4QKwj86HJ3uu2liISf2qBBUA==", + "dependencies": { + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^8.0.0", + "is-plain-object": "^5.0.0", + "parse-srcset": "^1.0.2", + "postcss": "^8.3.11" + } + }, + "node_modules/sanitize-html/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sanitize-html/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sass": { "version": "1.69.5", "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.5.tgz", @@ -17374,7 +17505,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, "engines": { "node": ">=0.10.0" } From 32ee6e062b9874668f8833a8fe4bea8d76fae846 Mon Sep 17 00:00:00 2001 From: dog Date: Sun, 21 Jan 2024 16:56:36 +0300 Subject: [PATCH 07/88] fix build --- src/components/Feed/ArticleCard/ArticleCard.tsx | 5 ++--- src/components/Nav/Header/Header.tsx | 1 - src/stores/ui.ts | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/Feed/ArticleCard/ArticleCard.tsx b/src/components/Feed/ArticleCard/ArticleCard.tsx index 4e9e08f3..ae2d768f 100644 --- a/src/components/Feed/ArticleCard/ArticleCard.tsx +++ b/src/components/Feed/ArticleCard/ArticleCard.tsx @@ -5,7 +5,6 @@ import type { Shout } from '../../../graphql/types.gen' import { getPagePath, openPage } from '@nanostores/router' import { clsx } from 'clsx' -import { createMemo, createSignal, For, Show } from 'solid-js' import { useLocalize } from '../../../context/localize' import { useSession } from '../../../context/session' @@ -95,8 +94,8 @@ const sanitizeString = (html) => sanitizeHtml(html, { allowedTags: ['span'], allowedAttributes: { - span: ['class'] - } + span: ['class'], + }, }) export const ArticleCard = (props: ArticleCardProps) => { diff --git a/src/components/Nav/Header/Header.tsx b/src/components/Nav/Header/Header.tsx index 007090e0..80f5b080 100644 --- a/src/components/Nav/Header/Header.tsx +++ b/src/components/Nav/Header/Header.tsx @@ -10,7 +10,6 @@ import { useLocalize } from '../../../context/localize' import { useSession } from '../../../context/session' import { router, ROUTES, useRouter } from '../../../stores/router' import { useModalStore } from '../../../stores/ui' -import { apiClient } from '../../../utils/apiClient' import { getDescription } from '../../../utils/meta' import { Icon } from '../../_shared/Icon' import { Subscribe } from '../../_shared/Subscribe' diff --git a/src/stores/ui.ts b/src/stores/ui.ts index 20301928..14982c53 100644 --- a/src/stores/ui.ts +++ b/src/stores/ui.ts @@ -41,7 +41,7 @@ export const MODALS: Record = { editorInsertLink: 'editorInsertLink', followers: 'followers', following: 'following', - search: 'search' + search: 'search', inviteCoAuthors: 'inviteCoAuthors', share: 'share', } From d1874ea55fe1f33a7cedf8327d7fb4615ef19b34 Mon Sep 17 00:00:00 2001 From: dog Date: Sun, 21 Jan 2024 17:02:25 +0300 Subject: [PATCH 08/88] fix check errors --- .../Nav/SearchModal/SearchModal.tsx | 55 ++++++++++--------- src/utils/apiClient.ts | 10 ++-- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/src/components/Nav/SearchModal/SearchModal.tsx b/src/components/Nav/SearchModal/SearchModal.tsx index d118dcc0..227d2641 100644 --- a/src/components/Nav/SearchModal/SearchModal.tsx +++ b/src/components/Nav/SearchModal/SearchModal.tsx @@ -18,9 +18,33 @@ import styles from './SearchModal.module.scss' const getSearchCoincidences = ({ str, intersection }: { str: string; intersection: string }) => `${str.replace( new RegExp(intersection, 'gi'), - (casePreservedMatch) => `${casePreservedMatch}` + (casePreservedMatch) => `${casePreservedMatch}`, )}` +const prepareSearchResults = (list, searchValue) => + list.map((article, index) => ({ + ...article, + body: '', + cover: '', + createdAt: '', + id: index, + slug: article.slug, + authors: [], + topics: [], + title: article.title + ? getSearchCoincidences({ + str: article.title, + intersection: searchValue, + }) + : '', + subtitle: article.subtitle + ? getSearchCoincidences({ + str: article.subtitle, + intersection: searchValue, + }) + : '', + })) + export const SearchModal = () => { const { t } = useLocalize() @@ -39,29 +63,8 @@ export const SearchModal = () => { const response = await apiClient.getSearchResults(searchValue) const searchResult = await response.json() - if (searchResult.length) { - const preparedSearchResultsList = searchResult.map((article, index) => ({ - ...article, - body: '', - cover: '', - createdAt: '', - id: index, - slug: article.slug, - authors: [], - topics: [], - title: article.title - ? getSearchCoincidences({ - str: article.title, - intersection: searchValue - }) - : '', - subtitle: article.subtitle - ? getSearchCoincidences({ - str: article.subtitle, - intersection: searchValue - }) - : '' - })) + if (searchResult.length > 0) { + const preparedSearchResultsList = prepareSearchResults(searchResult, searchValue) setSearchResultsList(preparedSearchResultsList) } else { @@ -97,7 +100,7 @@ export const SearchModal = () => {

    @@ -112,7 +115,7 @@ export const SearchModal = () => { noimage: true, // @@TODO remove flag after cover support isFloorImportant: true, isSingle: true, - nodate: true + nodate: true, }} />

    diff --git a/src/utils/apiClient.ts b/src/utils/apiClient.ts index 0af55c05..362c727d 100644 --- a/src/utils/apiClient.ts +++ b/src/utils/apiClient.ts @@ -446,14 +446,12 @@ export const apiClient = { // search getSearchResults: async (searchValue: string) => { - const resp = await fetch(`${searchUrl}/search?q=${searchValue}`, { + return await fetch(`${searchUrl}/search?q=${searchValue}`, { method: 'GET', headers: { accept: 'application/json', - 'content-type': 'application/json; charset=utf-8' - } + 'content-type': 'application/json; charset=utf-8', + }, }) - - return resp - } + }, } From 6bace7d3117c5567fffce6b62b6e5f69ca76e286 Mon Sep 17 00:00:00 2001 From: Arkadzi Rakouski Date: Mon, 22 Jan 2024 13:44:56 +0300 Subject: [PATCH 09/88] fixes for lightbox (#372) * fixes for lightbox * fix run check --- .../_shared/Lightbox/Lightbox.module.scss | 2 +- src/components/_shared/Lightbox/Lightbox.tsx | 47 ++++++++++++++----- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/components/_shared/Lightbox/Lightbox.module.scss b/src/components/_shared/Lightbox/Lightbox.module.scss index 4958b65a..dd60812e 100644 --- a/src/components/_shared/Lightbox/Lightbox.module.scss +++ b/src/components/_shared/Lightbox/Lightbox.module.scss @@ -8,7 +8,7 @@ display: flex; align-items: center; justify-content: center; - z-index: 10000; + z-index: 99999; animation: 300ms fadeIn; animation-fill-mode: forwards; diff --git a/src/components/_shared/Lightbox/Lightbox.tsx b/src/components/_shared/Lightbox/Lightbox.tsx index e4ad4f5a..b4d399b8 100644 --- a/src/components/_shared/Lightbox/Lightbox.tsx +++ b/src/components/_shared/Lightbox/Lightbox.tsx @@ -30,6 +30,12 @@ export const Lightbox = (props: Props) => { current: null, } + const handleSmoothAction = (action: () => void) => { + setTransitionEnabled(true) + action() + setTimeout(() => setTransitionEnabled(false), TRANSITION_SPEED) + } + const closeLightbox = () => { lightboxRef.current?.classList.add(styles.fadeOut) @@ -40,34 +46,48 @@ export const Lightbox = (props: Props) => { const zoomIn = (event) => { event.stopPropagation() - setTransitionEnabled(true) - setZoomLevel(zoomLevel() * ZOOM_STEP) - setTimeout(() => setTransitionEnabled(false), TRANSITION_SPEED) + + handleSmoothAction(() => { + setZoomLevel(zoomLevel() * ZOOM_STEP) + }) } const zoomOut = (event) => { event.stopPropagation() - setTransitionEnabled(true) - setZoomLevel(zoomLevel() / ZOOM_STEP) - setTimeout(() => setTransitionEnabled(false), TRANSITION_SPEED) + + handleSmoothAction(() => { + setZoomLevel(zoomLevel() / ZOOM_STEP) + }) + } + + const positionReset = () => { + setTranslateX(0) + setTranslateY(0) } const zoomReset = (event) => { event.stopPropagation() - setZoomLevel(1) + + handleSmoothAction(() => { + setZoomLevel(1) + positionReset() + }) } - const handleWheelZoom = (event) => { + const handleMouseWheelZoom = (event) => { event.preventDefault() + event.stopPropagation() + + const isTrackpad = event.ctrlKey + if (isTrackpad) return let scale = zoomLevel() - scale += event.deltaY * -0.01 - scale = Math.min(Math.max(0.125, scale), 4) - setTransitionEnabled(true) - setZoomLevel(scale * ZOOM_STEP) + handleSmoothAction(() => { + setZoomLevel(scale * ZOOM_STEP) + }) } useEscKeyDownHandler(closeLightbox) @@ -130,6 +150,7 @@ export const Lightbox = (props: Props) => {
    e.preventDefault()} ref={(el) => (lightboxRef.current = el)} > @@ -154,7 +175,7 @@ export const Lightbox = (props: Props) => { src={getImageUrl(props.image, { noSizeUrlPart: true })} alt={props.imageAlt || ''} onClick={(event) => event.stopPropagation()} - onWheel={handleWheelZoom} + onWheel={handleMouseWheelZoom} style={lightboxStyle()} onMouseDown={onMouseDown} /> From 8a8abd36529941fc3d5ceee6d610bfa1267612c2 Mon Sep 17 00:00:00 2001 From: Ilya Y <75578537+ilya-bkv@users.noreply.github.com> Date: Mon, 22 Jan 2024 13:45:21 +0300 Subject: [PATCH 10/88] Add resize iframe listener (#369) Add resize container listener --- src/components/Article/FullArticle.tsx | 64 +++++++++++++++---- src/components/Editor/extensions/Iframe.ts | 2 + .../Feed/ArticleCard/ArticleCard.tsx | 2 - 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx index b1c89325..db57a586 100644 --- a/src/components/Article/FullArticle.tsx +++ b/src/components/Article/FullArticle.tsx @@ -4,7 +4,7 @@ import { getPagePath } from '@nanostores/router' import { createPopper } from '@popperjs/core' import { Link, Meta } from '@solidjs/meta' import { clsx } from 'clsx' -import { createEffect, For, createMemo, onMount, Show, createSignal, onCleanup } from 'solid-js' +import { createEffect, For, createMemo, onMount, Show, createSignal, onCleanup, on } from 'solid-js' import { isServer } from 'solid-js/web' import { useLocalize } from '../../context/localize' @@ -42,6 +42,11 @@ type Props = { scrollToComments?: boolean } +type IframeSize = { + width: number + height: number +} + export type ArticlePageSearchParams = { scrollTo: 'comments' commentId: string @@ -173,18 +178,6 @@ export const FullArticle = (props: Props) => { actions: { loadReactionsBy }, } = useReactions() - onMount(async () => { - await loadReactionsBy({ - by: { shout: props.article.slug }, - }) - - setIsReactionsLoaded(true) - }) - - onMount(() => { - document.title = props.article.title - }) - const clickHandlers = [] const documentClickHandlers = [] @@ -286,8 +279,50 @@ export const FullArticle = (props: Props) => { } } - const cover = props.article.cover ?? 'production/image/logo_image.png' + // Check iframes size + const articleContainer: { current: HTMLElement } = { current: null } + const updateIframeSizes = () => { + if (!articleContainer?.current || !props.article.body) return + const iframes = articleContainer?.current?.querySelectorAll('iframe') + if (!iframes) return + const containerWidth = articleContainer.current?.offsetWidth + iframes.forEach((iframe) => { + const style = window.getComputedStyle(iframe) + const originalWidth = iframe.getAttribute('width') || style.width.replace('px', '') + const originalHeight = iframe.getAttribute('height') || style.height.replace('px', '') + const width = Number(originalWidth) + const height = Number(originalHeight) + + if (containerWidth < width) { + const aspectRatio = width / height + iframe.style.width = `${containerWidth}px` + iframe.style.height = `${Math.round(containerWidth / aspectRatio) + 40}px` + } + }) + } + + createEffect( + on( + () => props.article, + () => { + updateIframeSizes() + }, + ), + ) + + onMount(async () => { + await loadReactionsBy({ + by: { shout: props.article.slug }, + }) + setIsReactionsLoaded(true) + document.title = props.article.title + window?.addEventListener('resize', updateIframeSizes) + + onCleanup(() => window.removeEventListener('resize', updateIframeSizes)) + }) + + const cover = props.article.cover ?? 'production/image/logo_image.png' const ogImage = getOpenGraphImageUrl(cover, { title: props.article.title, topic: mainTopic().title, @@ -316,6 +351,7 @@ export const FullArticle = (props: Props) => {
    (articleContainer.current = el)} class={clsx('col-md-16 col-lg-14 col-xl-12 offset-md-5', styles.articleContent)} onClick={handleArticleBodyClick} > diff --git a/src/components/Editor/extensions/Iframe.ts b/src/components/Editor/extensions/Iframe.ts index 63ebab2f..95cd0bd7 100644 --- a/src/components/Editor/extensions/Iframe.ts +++ b/src/components/Editor/extensions/Iframe.ts @@ -41,6 +41,8 @@ export const Iframe = Node.create({ default: this.options.allowFullscreen, parseHTML: () => this.options.allowFullscreen, }, + width: { default: null }, + height: { default: null }, } }, diff --git a/src/components/Feed/ArticleCard/ArticleCard.tsx b/src/components/Feed/ArticleCard/ArticleCard.tsx index ff275635..4770defb 100644 --- a/src/components/Feed/ArticleCard/ArticleCard.tsx +++ b/src/components/Feed/ArticleCard/ArticleCard.tsx @@ -7,12 +7,10 @@ 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 { CoverImage } from '../../Article/CoverImage' import { getShareUrl, SharePopup } from '../../Article/SharePopup' From df8ee62112f9e12473718655fd3074c15b703578 Mon Sep 17 00:00:00 2001 From: Ilya Y <75578537+ilya-bkv@users.noreply.github.com> Date: Mon, 22 Jan 2024 13:45:46 +0300 Subject: [PATCH 11/88] Update tiptap link insert (#368) Update tiptap link insert --- src/components/Editor/Editor.tsx | 13 ++++- src/components/Editor/Prosemirror.scss | 7 +++ src/components/Editor/SimplifiedEditor.tsx | 5 +- .../Editor/TextBubbleMenu/TextBubbleMenu.tsx | 14 +++++- src/components/Editor/extensions/Span.ts | 31 ++++++++++++ .../Editor/extensions/ToggleTextWrap.ts | 50 +++++++++++++++++++ 6 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 src/components/Editor/extensions/Span.ts create mode 100644 src/components/Editor/extensions/ToggleTextWrap.ts diff --git a/src/components/Editor/Editor.tsx b/src/components/Editor/Editor.tsx index 04b2e984..6118d767 100644 --- a/src/components/Editor/Editor.tsx +++ b/src/components/Editor/Editor.tsx @@ -46,6 +46,8 @@ import { Figcaption } from './extensions/Figcaption' import { Figure } from './extensions/Figure' import { Footnote } from './extensions/Footnote' import { Iframe } from './extensions/Iframe' +import { Span } from './extensions/Span' +import { ToggleTextWrap } from './extensions/ToggleTextWrap' import { TrailingNode } from './extensions/TrailingNode' import { TextBubbleMenu } from './TextBubbleMenu' @@ -201,6 +203,8 @@ export const Editor = (props: Props) => { CustomBlockquote, Bold, Italic, + Span, + ToggleTextWrap, Strike, HorizontalRule.configure({ HTMLAttributes: { @@ -208,7 +212,10 @@ export const Editor = (props: Props) => { }, }), Underline, - Link.configure({ + Link.extend({ + inclusive: false, + }).configure({ + autolink: true, openOnClick: false, }), Heading.configure({ @@ -244,6 +251,7 @@ export const Editor = (props: Props) => { Figure, Figcaption, Footnote, + ToggleTextWrap, CharacterCount.configure(), // https://github.com/ueberdosis/tiptap/issues/2589#issuecomment-1093084689 BubbleMenu.configure({ pluginKey: 'textBubbleMenu', @@ -252,6 +260,9 @@ export const Editor = (props: Props) => { const { doc, selection } = state const { empty } = selection const isEmptyTextBlock = doc.textBetween(from, to).length === 0 && isTextSelection(selection) + if (isEmptyTextBlock) { + e.chain().focus().removeTextWrap({ class: 'highlight-fake-selection' }).run() + } setIsCommonMarkup(e.isActive('figcaption')) const result = (view.hasFocus() && diff --git a/src/components/Editor/Prosemirror.scss b/src/components/Editor/Prosemirror.scss index d84e01da..ca78c9f1 100644 --- a/src/components/Editor/Prosemirror.scss +++ b/src/components/Editor/Prosemirror.scss @@ -311,3 +311,10 @@ footnote { background-color: unset; } } + +.highlight-fake-selection { + background: var(--selection-background); + color: var(--selection-color); + border: solid var(--selection-background); + border-width: 5px 0; +} diff --git a/src/components/Editor/SimplifiedEditor.tsx b/src/components/Editor/SimplifiedEditor.tsx index a4aa4d7b..a549781e 100644 --- a/src/components/Editor/SimplifiedEditor.tsx +++ b/src/components/Editor/SimplifiedEditor.tsx @@ -117,7 +117,10 @@ const SimplifiedEditor = (props: Props) => { Paragraph, Bold, Italic, - Link.configure({ + Link.extend({ + inclusive: false, + }).configure({ + autolink: true, openOnClick: false, }), CharacterCount.configure({ diff --git a/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx b/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx index c7bb2d32..7457b009 100644 --- a/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx +++ b/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx @@ -129,11 +129,21 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => { }) }) + const handleOpenLinkForm = () => { + props.editor.chain().focus().addTextWrap({ class: 'highlight-fake-selection' }).run() + setLinkEditorOpen(true) + } + + const handleCloseLinkForm = () => { + setLinkEditorOpen(false) + props.editor.chain().focus().removeTextWrap({ class: 'highlight-fake-selection' }).run() + } + return (
    - setLinkEditorOpen(false)} /> + { +
    + + +
    +
    (uploading() ? undefined : setDropZoneActive(true))} + onDragLeave={() => setDropZoneActive(false)} + onDragOver={noPropagate} + onDrop={(event) => (uploading() ? noPropagate(event) : handleFileDrop(event))} + > +
    upload
    + +
    +
    + + + + ) +} diff --git a/src/components/_shared/ImageCropper/index.tsx b/src/components/_shared/ImageCropper/index.tsx index a04b027b..08e025d1 100644 --- a/src/components/_shared/ImageCropper/index.tsx +++ b/src/components/_shared/ImageCropper/index.tsx @@ -1,105 +1 @@ -import { createSignal, Show } from 'solid-js' -import { createStore } from 'solid-js/store' -import Cropper from 'cropperjs' - -import styles from './ImageCropper.module.scss' - -export default function ImageCropper(props) { - let cropImage - const [state, setState] = createStore({ - error: null, - loading: false, - file: {}, - croppedImage: null, - }), - [dropZoneActive, setDropZoneActive] = createSignal(false), - [uploading, setUploading] = createSignal(false), - [preview, setPreview] = createSignal(null), - [cropper, setCropper] = createSignal(null), - noPropagate = (e) => { - e.preventDefault() - }, - uploadFile = async (file) => { - if (!file) return - setUploading(true) - setState('loading', true) - setState('file', file) - try { - const reader = new FileReader() - reader.onload = (e) => { - setPreview(e.target.result) - setCropper( - new Cropper(cropImage, { - aspectRatio: 1 / 1, - viewMode: 1, - rotatable: false, - }), - ) - } - reader.readAsDataURL(file) - } catch (e) { - console.error('upload failed', e) - const message = e instanceof Error ? e.message : String(e) - setState('error', message) - } - setState('loading', false) - setUploading(false) - }, - handleFileDrop = async (e) => { - e.preventDefault() - setDropZoneActive(false) - uploadFile(e.dataTransfer.files[0]) - }, - handleFileInput = async (e) => { - e.preventDefault() - uploadFile(e.currentTarget.files[0]) - } - - return ( - <> - -
    -
    - cropper -
    - -
    -
    - -
    -
    (uploading() ? undefined : setDropZoneActive(true))} - onDragLeave={() => setDropZoneActive(false)} - onDragOver={noPropagate} - onDrop={(event) => (uploading() ? noPropagate(event) : handleFileDrop(event))} - > -
    upload
    - -
    -
    - - - - ) -} +export { ImageCropper } from './ImageCropper' From f4e787a3ce223ca5aba5af9055cfe22e3b341742 Mon Sep 17 00:00:00 2001 From: Ilya Y <75578537+ilya-bkv@users.noreply.github.com> Date: Mon, 22 Jan 2024 14:07:19 +0300 Subject: [PATCH 15/88] Inital load sorted articles with layout (#373) --- src/components/Views/Expo/Expo.tsx | 6 +++++- src/stores/zine/articles.ts | 10 +++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/components/Views/Expo/Expo.tsx b/src/components/Views/Expo/Expo.tsx index 63533875..487a6c07 100644 --- a/src/components/Views/Expo/Expo.tsx +++ b/src/components/Views/Expo/Expo.tsx @@ -41,8 +41,12 @@ export const Expo = (props: Props) => { const { t } = useLocalize() + // const { sortedArticles } = useArticlesStore({ + // shouts: isLoaded() ? props.shouts : [], + // }) const { sortedArticles } = useArticlesStore({ - shouts: isLoaded() ? props.shouts : [], + shouts: props.shouts || [], + layout: props.layout, }) const getLoadShoutsFilters = (additionalFilters: LoadShoutsFilters = {}): LoadShoutsFilters => { diff --git a/src/stores/zine/articles.ts b/src/stores/zine/articles.ts index 721aca2b..c6b0de07 100644 --- a/src/stores/zine/articles.ts +++ b/src/stores/zine/articles.ts @@ -166,6 +166,7 @@ export const resetSortedArticles = () => { type InitialState = { shouts?: Shout[] + layout?: string } const TOP_MONTH_ARTICLES_COUNT = 10 @@ -203,7 +204,14 @@ export const loadTopArticles = async (): Promise => { export const useArticlesStore = (initialState: InitialState = {}) => { addArticles([...(initialState.shouts || [])]) - if (initialState.shouts) { + if (initialState.layout) { + // eslint-disable-next-line promise/catch-or-return + loadShouts({ filters: { layout: initialState.layout }, limit: 10 }).then(({ newShouts }) => { + addArticles(newShouts) + setSortedArticles(newShouts) + }) + } else if (initialState.shouts) { + addArticles([...initialState.shouts]) setSortedArticles([...initialState.shouts]) } From b053aded183f661b4e51194bb819b5ad9ec26d8f Mon Sep 17 00:00:00 2001 From: dog Date: Mon, 22 Jan 2024 14:09:21 +0300 Subject: [PATCH 16/88] remove sanitize-html --- package-lock.json | 1719 +++++------------ package.json | 2 - .../Feed/ArticleCard/ArticleCard.tsx | 18 +- .../Nav/SearchModal/SearchModal.tsx | 2 +- 4 files changed, 446 insertions(+), 1295 deletions(-) diff --git a/package-lock.json b/package-lock.json index 35180481..3adabce5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,8 +14,7 @@ "i18next-icu": "2.3.0", "intl-messageformat": "10.5.3", "just-throttle": "4.2.0", - "mailgun.js": "8.2.1", - "sanitize-html": "2.11.0" + "mailgun.js": "8.2.1" }, "devDependencies": { "@babel/core": "7.23.3", @@ -380,12 +379,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.23.4", + "@babel/highlight": "^7.22.13", "chalk": "^2.4.2" }, "engines": { @@ -393,9 +392,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", + "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -432,12 +431,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", + "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", "dev": true, "dependencies": { - "@babel/types": "^7.23.6", + "@babel/types": "^7.23.3", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -459,14 +458,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -475,17 +474,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.7.tgz", - "integrity": "sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", + "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.15", "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-replace-supers": "^7.22.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", "semver": "^6.3.1" @@ -649,9 +648,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "dev": true, "engines": { "node": ">=6.9.0" @@ -667,32 +666,32 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz", - "integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", "dev": true, "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6" + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", @@ -704,9 +703,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", - "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", + "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1031,9 +1030,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", - "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.3.tgz", + "integrity": "sha512-QPZxHrThbQia7UdvfpaRRlq/J9ciz1J4go0k+lPBXbgaNeY7IQrBj/9ceWjvMMI07/ZBzHl/F0R/2K0qH7jCVw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1046,15 +1045,16 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz", - "integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.3.tgz", + "integrity": "sha512-FGEQmugvAEu2QtgtU0uTASXevfLMFfBeVCIIdcQhn/uBQsMTjBajdnAtanQlOcuihWh10PZ7+HWvc7NtBwP74w==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-compilation-targets": "^7.22.15", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-replace-supers": "^7.22.20", "@babel/helper-split-export-declaration": "^7.22.6", @@ -1115,13 +1115,12 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", - "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.3.tgz", + "integrity": "sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1256,16 +1255,16 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", - "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz", + "integrity": "sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-module-imports": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-jsx": "^7.23.3", - "@babel/types": "^7.23.4" + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -1321,13 +1320,13 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz", - "integrity": "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.3.tgz", + "integrity": "sha512-ogV0yWnq38CFwH20l2Afz0dfKuZBx9o/Y2Rmh5vuSS0YD1hswgEgTfyTzuSrT2q9btmHRSqYoSfwFUVaC1M1Jw==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.23.6", + "@babel/helper-create-class-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-typescript": "^7.23.3" }, @@ -1358,9 +1357,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", - "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1383,20 +1382,20 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", - "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz", + "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.6", - "@babel/types": "^7.23.6", - "debug": "^4.3.1", + "@babel/parser": "^7.23.3", + "@babel/types": "^7.23.3", + "debug": "^4.1.0", "globals": "^11.1.0" }, "engines": { @@ -1404,12 +1403,12 @@ } }, "node_modules/@babel/types": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", - "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", + "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-string-parser": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, @@ -1448,18 +1447,18 @@ "dev": true }, "node_modules/@brillout/vite-plugin-import-build": { - "version": "0.2.22", - "resolved": "https://registry.npmjs.org/@brillout/vite-plugin-import-build/-/vite-plugin-import-build-0.2.22.tgz", - "integrity": "sha512-n5sv0HdCB5WC2QJSnTN6iS/F+sJsF0AmtsCCaQ+5+dRjgsoGGsa3auinJV8tuEog5WsX+3MF8RIwn3A/u0e04w==", + "version": "0.2.20", + "resolved": "https://registry.npmjs.org/@brillout/vite-plugin-import-build/-/vite-plugin-import-build-0.2.20.tgz", + "integrity": "sha512-/bdw1dg+H1nOYSy2PzYInQoZlIFP2uwyaF2GX64fyBqVAEWGopiMlnx294CbysjmP9Z+fJe48TkMzyogkyIDLw==", "dev": true, "dependencies": { "@brillout/import": "^0.2.3" } }, "node_modules/@csstools/css-parser-algorithms": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.5.0.tgz", - "integrity": "sha512-abypo6m9re3clXA00eu5syw+oaPHbJTPapu9C4pzNsJ4hdZDzushT50Zhu+iIYXgEe1CxnRMn7ngsbV+MLrlpQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.3.2.tgz", + "integrity": "sha512-sLYGdAdEY2x7TSw9FtmdaTrh2wFtRJO5VMbBrA8tEqEod7GEggFmxTSK9XqExib3yMuYNcvcTdCZIP6ukdjAIA==", "dev": true, "funding": [ { @@ -1475,13 +1474,13 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-tokenizer": "^2.2.3" + "@csstools/css-tokenizer": "^2.2.1" } }, "node_modules/@csstools/css-tokenizer": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.3.tgz", - "integrity": "sha512-pp//EvZ9dUmGuGtG1p+n17gTHEOqu9jO+FiCUjNN3BDmyhdA2Jq9QsVeR7K8/2QCK17HSsioPlTW9ZkzoWb3Lg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.1.tgz", + "integrity": "sha512-Zmsf2f/CaEPWEVgw29odOj+WEVoiJy9s9NOv5GgNY9mZ1CZ7394By6wONrONrTsnNDv6F9hR02nvFihrGVGHBg==", "dev": true, "funding": [ { @@ -1498,9 +1497,9 @@ } }, "node_modules/@csstools/media-query-list-parser": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.7.tgz", - "integrity": "sha512-lHPKJDkPUECsyAvD60joYfDmp8UERYxHGkFfyLJFTVK/ERJe0sVlIFLXU5XFxdjNDTerp5L4KeaKG+Z5S94qxQ==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.5.tgz", + "integrity": "sha512-IxVBdYzR8pYe89JiyXQuYk4aVVoCPhMJkz6ElRwlVysjwURTsTk/bmY/z4FfeRE+CRBMlykPwXEVUg8lThv7AQ==", "dev": true, "funding": [ { @@ -1516,14 +1515,14 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.5.0", - "@csstools/css-tokenizer": "^2.2.3" + "@csstools/css-parser-algorithms": "^2.3.2", + "@csstools/css-tokenizer": "^2.2.1" } }, "node_modules/@csstools/selector-specificity": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.1.tgz", - "integrity": "sha512-NPljRHkq4a14YzZ3YD406uaxh7s0g6eAq3L9aLOWywoqe8PkYamAvtsh7KNX6c++ihDrJ0RiU+/z7rGnhlZ5ww==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz", + "integrity": "sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g==", "dev": true, "funding": [ { @@ -1542,54 +1541,6 @@ "postcss-selector-parser": "^6.0.13" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/darwin-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", @@ -1606,294 +1557,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -1919,9 +1582,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -1942,9 +1605,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2156,16 +1819,16 @@ } }, "node_modules/@graphql-codegen/cli/node_modules/@graphql-tools/executor-legacy-ws": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.0.5.tgz", - "integrity": "sha512-w54AZ7zkNuvpyV09FH+eGHnnAmaxhBVHg4Yh2ICcsMfRg0brkLt77PlbjBuxZ4HY8XZnKJaYWf+tKazQZtkQtg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.0.4.tgz", + "integrity": "sha512-b7aGuRekZDS+m3af3BIvMKxu15bmVPMt5eGQVuP2v5pxmbaPTh+iv5mx9b3Plt32z5Ke5tycBnNm5urSFtW8ng==", "dev": true, "dependencies": { "@graphql-tools/utils": "^10.0.0", "@types/ws": "^8.0.0", - "isomorphic-ws": "^5.0.0", + "isomorphic-ws": "5.0.0", "tslib": "^2.4.0", - "ws": "^8.15.0" + "ws": "8.14.2" }, "engines": { "node": ">=16.0.0" @@ -2175,15 +1838,15 @@ } }, "node_modules/@graphql-codegen/cli/node_modules/@graphql-tools/url-loader": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.1.tgz", - "integrity": "sha512-B2k8KQEkEQmfV1zhurT5GLoXo8jbXP+YQHUayhCSxKYlRV7j/1Fhp1b21PDM8LXIDGlDRXaZ0FbWKOs7eYXDuQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.0.tgz", + "integrity": "sha512-rPc9oDzMnycvz+X+wrN3PLrhMBQkG4+sd8EzaFN6dypcssiefgWKToXtRKI8HHK68n2xEq1PyrOpkjHFJB+GwA==", "dev": true, "dependencies": { "@ardatan/sync-fetch": "^0.0.1", "@graphql-tools/delegate": "^10.0.0", "@graphql-tools/executor-graphql-ws": "^1.0.0", - "@graphql-tools/executor-http": "^1.0.5", + "@graphql-tools/executor-http": "^1.0.0", "@graphql-tools/executor-legacy-ws": "^1.0.0", "@graphql-tools/utils": "^10.0.0", "@graphql-tools/wrap": "^10.0.0", @@ -2202,9 +1865,9 @@ } }, "node_modules/@graphql-codegen/cli/node_modules/@graphql-tools/url-loader/node_modules/@whatwg-node/fetch": { - "version": "0.9.15", - "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.15.tgz", - "integrity": "sha512-2wIUcolUthZt0nsPRj+pT7K9h/EO3t/j09IBuq0FtITCsASc2fRCmRw2JHS6hk9fzUQrz2+YYrA1ZDpV7+vLsQ==", + "version": "0.9.14", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.14.tgz", + "integrity": "sha512-wurZC82zzZwXRDSW0OS9l141DynaJQh7Yt0FD1xZ8niX7/Et/7RoiLiltbVU1fSF1RR9z6ndEaTUQBAmddTm1w==", "dev": true, "dependencies": { "@whatwg-node/node-fetch": "^0.5.0", @@ -2243,15 +1906,15 @@ } }, "node_modules/@graphql-codegen/cli/node_modules/@whatwg-node/node-fetch": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.4.tgz", - "integrity": "sha512-5AXi4B44/6SOlQG+X3cO5lsUdRTWSXqaWLkGKnwWfeJoMgRfA53RnYVnvTV+4CoatNBStPrIoDorjgQv+ouiMQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.0.tgz", + "integrity": "sha512-q76lDAafvHNGWedNAVHrz/EyYTS8qwRLcwne8SJQdRN5P3HydxU6XROFvJfTML6KZXQX2FDdGY4/SnaNyd7M0Q==", "dev": true, "dependencies": { - "@kamilkisiela/fast-url-parser": "^1.1.4", "@whatwg-node/events": "^0.1.0", "busboy": "^1.6.0", "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", "tslib": "^2.3.1" }, "engines": { @@ -2308,9 +1971,9 @@ "dev": true }, "node_modules/@graphql-codegen/cli/node_modules/graphql-ws": { - "version": "5.14.3", - "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.14.3.tgz", - "integrity": "sha512-F/i2xNIVbaEF2xWggID0X/UZQa2V8kqKDPO8hwmu53bVOcTL7uNkxnexeEgSCVxYBQUTUNEI8+e4LO1FOhKPKQ==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.14.2.tgz", + "integrity": "sha512-LycmCwhZ+Op2GlHz4BZDsUYHKRiiUz+3r9wbhBATMETNlORQJAaFlAgTFoeRh6xQoQegwYwIylVD1Qns9/DA3w==", "dev": true, "engines": { "node": ">=10" @@ -2717,9 +2380,9 @@ } }, "node_modules/@graphql-tools/apollo-engine-loader/node_modules/@whatwg-node/fetch": { - "version": "0.9.15", - "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.15.tgz", - "integrity": "sha512-2wIUcolUthZt0nsPRj+pT7K9h/EO3t/j09IBuq0FtITCsASc2fRCmRw2JHS6hk9fzUQrz2+YYrA1ZDpV7+vLsQ==", + "version": "0.9.14", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.14.tgz", + "integrity": "sha512-wurZC82zzZwXRDSW0OS9l141DynaJQh7Yt0FD1xZ8niX7/Et/7RoiLiltbVU1fSF1RR9z6ndEaTUQBAmddTm1w==", "dev": true, "dependencies": { "@whatwg-node/node-fetch": "^0.5.0", @@ -2730,15 +2393,15 @@ } }, "node_modules/@graphql-tools/apollo-engine-loader/node_modules/@whatwg-node/node-fetch": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.4.tgz", - "integrity": "sha512-5AXi4B44/6SOlQG+X3cO5lsUdRTWSXqaWLkGKnwWfeJoMgRfA53RnYVnvTV+4CoatNBStPrIoDorjgQv+ouiMQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.0.tgz", + "integrity": "sha512-q76lDAafvHNGWedNAVHrz/EyYTS8qwRLcwne8SJQdRN5P3HydxU6XROFvJfTML6KZXQX2FDdGY4/SnaNyd7M0Q==", "dev": true, "dependencies": { - "@kamilkisiela/fast-url-parser": "^1.1.4", "@whatwg-node/events": "^0.1.0", "busboy": "^1.6.0", "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", "tslib": "^2.3.1" }, "engines": { @@ -2932,9 +2595,9 @@ } }, "node_modules/@graphql-tools/executor-http": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor-http/-/executor-http-1.0.7.tgz", - "integrity": "sha512-/MoRYzQS50Tz5mxRfq3ZmeZ2SOins9wGZAGetsJ55F3PxL0PmHdSGlCq12KzffZDbwHV5YMlwigBsSGWq4y9Iw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-http/-/executor-http-1.0.3.tgz", + "integrity": "sha512-5WZIMBevRaxMabZ8U2Ty0dTUPy/PpeYSlMNEmC/YJjKKykgSfc/AwSejx2sE4FFKZ0I2kxRKRenyoWMHRAV49Q==", "dev": true, "dependencies": { "@graphql-tools/utils": "^10.0.2", @@ -2962,9 +2625,9 @@ } }, "node_modules/@graphql-tools/executor-http/node_modules/@whatwg-node/fetch": { - "version": "0.9.15", - "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.15.tgz", - "integrity": "sha512-2wIUcolUthZt0nsPRj+pT7K9h/EO3t/j09IBuq0FtITCsASc2fRCmRw2JHS6hk9fzUQrz2+YYrA1ZDpV7+vLsQ==", + "version": "0.9.14", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.14.tgz", + "integrity": "sha512-wurZC82zzZwXRDSW0OS9l141DynaJQh7Yt0FD1xZ8niX7/Et/7RoiLiltbVU1fSF1RR9z6ndEaTUQBAmddTm1w==", "dev": true, "dependencies": { "@whatwg-node/node-fetch": "^0.5.0", @@ -2975,15 +2638,15 @@ } }, "node_modules/@graphql-tools/executor-http/node_modules/@whatwg-node/node-fetch": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.4.tgz", - "integrity": "sha512-5AXi4B44/6SOlQG+X3cO5lsUdRTWSXqaWLkGKnwWfeJoMgRfA53RnYVnvTV+4CoatNBStPrIoDorjgQv+ouiMQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.0.tgz", + "integrity": "sha512-q76lDAafvHNGWedNAVHrz/EyYTS8qwRLcwne8SJQdRN5P3HydxU6XROFvJfTML6KZXQX2FDdGY4/SnaNyd7M0Q==", "dev": true, "dependencies": { - "@kamilkisiela/fast-url-parser": "^1.1.4", "@whatwg-node/events": "^0.1.0", "busboy": "^1.6.0", "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", "tslib": "^2.3.1" }, "engines": { @@ -3110,9 +2773,9 @@ } }, "node_modules/@graphql-tools/github-loader/node_modules/@whatwg-node/fetch": { - "version": "0.9.15", - "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.15.tgz", - "integrity": "sha512-2wIUcolUthZt0nsPRj+pT7K9h/EO3t/j09IBuq0FtITCsASc2fRCmRw2JHS6hk9fzUQrz2+YYrA1ZDpV7+vLsQ==", + "version": "0.9.14", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.14.tgz", + "integrity": "sha512-wurZC82zzZwXRDSW0OS9l141DynaJQh7Yt0FD1xZ8niX7/Et/7RoiLiltbVU1fSF1RR9z6ndEaTUQBAmddTm1w==", "dev": true, "dependencies": { "@whatwg-node/node-fetch": "^0.5.0", @@ -3123,15 +2786,15 @@ } }, "node_modules/@graphql-tools/github-loader/node_modules/@whatwg-node/node-fetch": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.4.tgz", - "integrity": "sha512-5AXi4B44/6SOlQG+X3cO5lsUdRTWSXqaWLkGKnwWfeJoMgRfA53RnYVnvTV+4CoatNBStPrIoDorjgQv+ouiMQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.0.tgz", + "integrity": "sha512-q76lDAafvHNGWedNAVHrz/EyYTS8qwRLcwne8SJQdRN5P3HydxU6XROFvJfTML6KZXQX2FDdGY4/SnaNyd7M0Q==", "dev": true, "dependencies": { - "@kamilkisiela/fast-url-parser": "^1.1.4", "@whatwg-node/events": "^0.1.0", "busboy": "^1.6.0", "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", "tslib": "^2.3.1" }, "engines": { @@ -3220,13 +2883,13 @@ } }, "node_modules/@graphql-tools/load": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-8.0.1.tgz", - "integrity": "sha512-qSMsKngJhDqRbuWyo3NvakEFqFL6+eSjy8ooJ1o5qYD26N7dqXkKzIMycQsX7rBK19hOuINAUSaRcVWH6hTccw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-8.0.0.tgz", + "integrity": "sha512-Cy874bQJH0FP2Az7ELPM49iDzOljQmK1PPH6IuxsWzLSTxwTqd8dXA09dcVZrI7/LsN26heTY2R8q2aiiv0GxQ==", "dev": true, "dependencies": { "@graphql-tools/schema": "^10.0.0", - "@graphql-tools/utils": "^10.0.11", + "@graphql-tools/utils": "^10.0.0", "p-limit": "3.1.0", "tslib": "^2.4.0" }, @@ -3238,12 +2901,12 @@ } }, "node_modules/@graphql-tools/merge": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.1.tgz", - "integrity": "sha512-hIEExWO9fjA6vzsVjJ3s0cCQ+Q/BEeMVJZtMXd7nbaVefVy0YDyYlEkeoYYNV3NVVvu1G9lr6DM1Qd0DGo9Caw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.0.tgz", + "integrity": "sha512-J7/xqjkGTTwOJmaJQJ2C+VDBDOWJL3lKrHJN4yMaRLAJH3PosB7GiPRaSDZdErs0+F77sH2MKs2haMMkywzx7Q==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.10", + "@graphql-tools/utils": "^10.0.0", "tslib": "^2.4.0" }, "engines": { @@ -3378,16 +3041,16 @@ } }, "node_modules/@graphql-tools/prisma-loader/node_modules/@graphql-tools/executor-legacy-ws": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.0.5.tgz", - "integrity": "sha512-w54AZ7zkNuvpyV09FH+eGHnnAmaxhBVHg4Yh2ICcsMfRg0brkLt77PlbjBuxZ4HY8XZnKJaYWf+tKazQZtkQtg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.0.4.tgz", + "integrity": "sha512-b7aGuRekZDS+m3af3BIvMKxu15bmVPMt5eGQVuP2v5pxmbaPTh+iv5mx9b3Plt32z5Ke5tycBnNm5urSFtW8ng==", "dev": true, "dependencies": { "@graphql-tools/utils": "^10.0.0", "@types/ws": "^8.0.0", - "isomorphic-ws": "^5.0.0", + "isomorphic-ws": "5.0.0", "tslib": "^2.4.0", - "ws": "^8.15.0" + "ws": "8.14.2" }, "engines": { "node": ">=16.0.0" @@ -3397,15 +3060,15 @@ } }, "node_modules/@graphql-tools/prisma-loader/node_modules/@graphql-tools/url-loader": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.1.tgz", - "integrity": "sha512-B2k8KQEkEQmfV1zhurT5GLoXo8jbXP+YQHUayhCSxKYlRV7j/1Fhp1b21PDM8LXIDGlDRXaZ0FbWKOs7eYXDuQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.0.tgz", + "integrity": "sha512-rPc9oDzMnycvz+X+wrN3PLrhMBQkG4+sd8EzaFN6dypcssiefgWKToXtRKI8HHK68n2xEq1PyrOpkjHFJB+GwA==", "dev": true, "dependencies": { "@ardatan/sync-fetch": "^0.0.1", "@graphql-tools/delegate": "^10.0.0", "@graphql-tools/executor-graphql-ws": "^1.0.0", - "@graphql-tools/executor-http": "^1.0.5", + "@graphql-tools/executor-http": "^1.0.0", "@graphql-tools/executor-legacy-ws": "^1.0.0", "@graphql-tools/utils": "^10.0.0", "@graphql-tools/wrap": "^10.0.0", @@ -3452,9 +3115,9 @@ } }, "node_modules/@graphql-tools/prisma-loader/node_modules/@whatwg-node/fetch": { - "version": "0.9.15", - "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.15.tgz", - "integrity": "sha512-2wIUcolUthZt0nsPRj+pT7K9h/EO3t/j09IBuq0FtITCsASc2fRCmRw2JHS6hk9fzUQrz2+YYrA1ZDpV7+vLsQ==", + "version": "0.9.14", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.14.tgz", + "integrity": "sha512-wurZC82zzZwXRDSW0OS9l141DynaJQh7Yt0FD1xZ8niX7/Et/7RoiLiltbVU1fSF1RR9z6ndEaTUQBAmddTm1w==", "dev": true, "dependencies": { "@whatwg-node/node-fetch": "^0.5.0", @@ -3465,15 +3128,15 @@ } }, "node_modules/@graphql-tools/prisma-loader/node_modules/@whatwg-node/node-fetch": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.4.tgz", - "integrity": "sha512-5AXi4B44/6SOlQG+X3cO5lsUdRTWSXqaWLkGKnwWfeJoMgRfA53RnYVnvTV+4CoatNBStPrIoDorjgQv+ouiMQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.0.tgz", + "integrity": "sha512-q76lDAafvHNGWedNAVHrz/EyYTS8qwRLcwne8SJQdRN5P3HydxU6XROFvJfTML6KZXQX2FDdGY4/SnaNyd7M0Q==", "dev": true, "dependencies": { - "@kamilkisiela/fast-url-parser": "^1.1.4", "@whatwg-node/events": "^0.1.0", "busboy": "^1.6.0", "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", "tslib": "^2.3.1" }, "engines": { @@ -3530,9 +3193,9 @@ "dev": true }, "node_modules/@graphql-tools/prisma-loader/node_modules/graphql-ws": { - "version": "5.14.3", - "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.14.3.tgz", - "integrity": "sha512-F/i2xNIVbaEF2xWggID0X/UZQa2V8kqKDPO8hwmu53bVOcTL7uNkxnexeEgSCVxYBQUTUNEI8+e4LO1FOhKPKQ==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.14.2.tgz", + "integrity": "sha512-LycmCwhZ+Op2GlHz4BZDsUYHKRiiUz+3r9wbhBATMETNlORQJAaFlAgTFoeRh6xQoQegwYwIylVD1Qns9/DA3w==", "dev": true, "engines": { "node": ">=10" @@ -3586,13 +3249,13 @@ } }, "node_modules/@graphql-tools/schema": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.2.tgz", - "integrity": "sha512-TbPsIZnWyDCLhgPGnDjt4hosiNU2mF/rNtSk5BVaXWnZqvKJ6gzJV4fcHcvhRIwtscDMW2/YTnK6dLVnk8pc4w==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.0.tgz", + "integrity": "sha512-kf3qOXMFcMs2f/S8Y3A8fm/2w+GaHAkfr3Gnhh2LOug/JgpY/ywgFVxO3jOeSpSEdoYcDKLcXVjMigNbY4AdQg==", "dev": true, "dependencies": { - "@graphql-tools/merge": "^9.0.1", - "@graphql-tools/utils": "^10.0.10", + "@graphql-tools/merge": "^9.0.0", + "@graphql-tools/utils": "^10.0.0", "tslib": "^2.4.0", "value-or-promise": "^1.0.12" }, @@ -3660,9 +3323,9 @@ } }, "node_modules/@graphql-tools/utils": { - "version": "10.0.12", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.0.12.tgz", - "integrity": "sha512-+yS1qlFwXlwU3Gv8ek/h2aJ95quog4yF22haC11M0zReMSTddbGJZ5yXKkE3sXoY2BcL1utilSFjylJ9uXpSNQ==", + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.0.8.tgz", + "integrity": "sha512-yjyA8ycSa1WRlJqyX/aLqXeE5DvF/H02+zXMUFnCzIDrj0UvLMUrxhmVFnMK0Q2n3bh4uuTeY3621m5za9ovXw==", "dev": true, "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", @@ -3744,12 +3407,12 @@ } }, "node_modules/@hocuspocus/common": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/@hocuspocus/common/-/common-2.9.0.tgz", - "integrity": "sha512-VHqxf1Qov4PULmoevRV4hEyxfEGNtdCMDQTU0C1C6ZR6ImDAqnpuzzcxH5ppkZZiiSZwDWxMxxegFt2e3alDEA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@hocuspocus/common/-/common-2.7.1.tgz", + "integrity": "sha512-mnwBn7b2g23rUmYA1+X+FrIwU9aODmRMWe7ypQdjL/MgzlZWrwqFFr0b9u4AhBrwqRTg+L8KCp8SDkpkt2OTtQ==", "dev": true, "dependencies": { - "lib0": "^0.2.87" + "lib0": "^0.2.47" } }, "node_modules/@hocuspocus/provider": { @@ -3790,13 +3453,13 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", "minimatch": "^3.0.5" }, "engines": { @@ -3817,9 +3480,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { @@ -4588,21 +4251,15 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", - "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@kamilkisiela/fast-url-parser": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@kamilkisiela/fast-url-parser/-/fast-url-parser-1.1.4.tgz", - "integrity": "sha512-gbkePEBupNydxCelHCESvFSFM8XPh1Zs/OAVRW/rKpEqPAl5PbOM90Si8mv9bvnR53uPD2s/FiRxdvSejpRJew==", - "dev": true - }, "node_modules/@lifeomic/attempt": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@lifeomic/attempt/-/attempt-3.0.3.tgz", @@ -4973,15 +4630,15 @@ } }, "node_modules/@peculiar/webcrypto": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.4.tgz", - "integrity": "sha512-VETlZgJqOP3OLRC7AcEYfb6/u05evqsW0Vgs9DyCBATp3FSx7D30Z8ALuDJHsmXCsMblfyTwvB9PLR6IfdlRhg==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.3.tgz", + "integrity": "sha512-VtaY4spKTdN5LjJ04im/d/joXuvLbQdgy5Z4DXF4MFZhQ+MTrejbNMkfZBp1Bs3O5+bFqnJgyGdPuZQflvIa5A==", "dev": true, "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-schema": "^2.3.6", "@peculiar/json-schema": "^1.1.12", - "pvtsutils": "^1.3.5", - "tslib": "^2.6.2", + "pvtsutils": "^1.3.2", + "tslib": "^2.5.0", "webcrypto-core": "^1.7.7" }, "engines": { @@ -4989,9 +4646,9 @@ } }, "node_modules/@polka/url": { - "version": "1.0.0-next.24", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.24.tgz", - "integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==", + "version": "1.0.0-next.23", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.23.tgz", + "integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==", "dev": true }, "node_modules/@popperjs/core": { @@ -5186,9 +4843,9 @@ "dev": true }, "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", "dev": true, "dependencies": { "type-detect": "4.0.8" @@ -5204,12 +4861,12 @@ } }, "node_modules/@solid-primitives/event-listener": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@solid-primitives/event-listener/-/event-listener-2.3.1.tgz", - "integrity": "sha512-S1AfFYatOJ3g/ZUbGDoKplSGLTTfarQ3Mfd3F/fXb9SnzGtROtd+Y6yLkPVzK4AVw83r2wUSaS0GS6dg8izTEQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solid-primitives/event-listener/-/event-listener-2.3.0.tgz", + "integrity": "sha512-0DS7DQZvCExWSpurVZC9/wjI8RmkhuOtWOy6Pp1Woq9ElMT9/bfjNpkwXsOwisLpcTqh9eUs17kp7jtpWcC20w==", "dev": true, "dependencies": { - "@solid-primitives/utils": "^6.2.2" + "@solid-primitives/utils": "^6.2.1" }, "peerDependencies": { "solid-js": "^1.6.12" @@ -5244,33 +4901,33 @@ } }, "node_modules/@solid-primitives/refs": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@solid-primitives/refs/-/refs-1.0.6.tgz", - "integrity": "sha512-ruh4YdVMxThEVnvqbpeLXKojW442vpFU8q7dSKtElGOTa31aKOAkRb9BTbdaTwVjN4BEq79fiiYIXozJNl4dSw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@solid-primitives/refs/-/refs-1.0.5.tgz", + "integrity": "sha512-5hmYmYbm6rs43nMHHozyyUngGA7P7q2WtlaCLJEfmlUJf67GWI1PZmqAiol6m9F37XSMZRuvZLoQ7HA/0q3GYg==", "dev": true, "dependencies": { - "@solid-primitives/utils": "^6.2.2" + "@solid-primitives/utils": "^6.2.1" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "node_modules/@solid-primitives/rootless": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@solid-primitives/rootless/-/rootless-1.4.3.tgz", - "integrity": "sha512-IPsfUhKsqQOxLtRMQWK2EZAYbL9RKJMLBelLwpaXl9+oa1tl5aNvA6GHgrNrK+85oUhiYh7/OuogO18AuHepqQ==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/rootless/-/rootless-1.4.2.tgz", + "integrity": "sha512-ynI/2aEOPyc14IKCX6yDBqnsAYCoLbaP9V/jejEWMVKOT2ZdV2ZxdftaLimOpWPpvjyti5DUJIGTOfLaNb7jlg==", "dev": true, "dependencies": { - "@solid-primitives/utils": "^6.2.2" + "@solid-primitives/utils": "^6.2.1" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "node_modules/@solid-primitives/scheduled": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@solid-primitives/scheduled/-/scheduled-1.4.2.tgz", - "integrity": "sha512-duKaugDQtPk0v6MnkBuEalWk66/vA2G7zzoimQEvmUdh2+K2o8t908HIfI2NdBfwakQMQBV4epE3TFeN2Vsveg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@solid-primitives/scheduled/-/scheduled-1.4.1.tgz", + "integrity": "sha512-OLcNXwYpX7HUOEqNPcmR31dkyI1E2imkMDBRlqsGT0ZhJV1L2g0TEREpo4nm/kUhh8LVQzkfnxS+GONx9kh90A==", "dev": true, "peerDependencies": { "solid-js": "^1.6.12" @@ -5310,9 +4967,9 @@ } }, "node_modules/@solid-primitives/transition-group": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@solid-primitives/transition-group/-/transition-group-1.0.4.tgz", - "integrity": "sha512-9nPg6HYAmEi7riH0C2bSCVw/2asgGSzHuN0yFFYyK9JgmXqJgyeyA+6thZbj7GgUQMRhtBxpH8yG7N2nEh8ttA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@solid-primitives/transition-group/-/transition-group-1.0.3.tgz", + "integrity": "sha512-TnFADZhx9sibdoW5gxkU1QmLabzV2H2OBKYGS2aR5IC61Q/+7v8wlxOJEevxXNbPiRo6qlE3STLU3L9XS8hDbA==", "dev": true, "peerDependencies": { "solid-js": "^1.6.12" @@ -5340,9 +4997,9 @@ } }, "node_modules/@solid-primitives/utils": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/@solid-primitives/utils/-/utils-6.2.2.tgz", - "integrity": "sha512-11ypVbp987XxETeRqY5Y3OmmTpm8/jZqJXRvo6AyqBthzkvvjEdReuUMU2yVb+pwWGxfZpWHZ6EUCcGXUMhfwg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@solid-primitives/utils/-/utils-6.2.1.tgz", + "integrity": "sha512-TsecNzxiO5bLfzqb4OOuzfUmdOROcssuGqgh5rXMMaasoFZ3GoveUgdY1wcf17frMJM7kCNGNuK34EjErneZkg==", "dev": true, "peerDependencies": { "solid-js": "^1.6.12" @@ -5766,9 +5423,9 @@ } }, "node_modules/@tiptap/pm": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.1.16.tgz", - "integrity": "sha512-yibLkjtgbBSnWCXbDyKM5kgIGLfMvfbRfFzb8T0uz4PI/L54o0a4fiWSW5Fg10B5+o+NAXW2wMxoId8/Tw91lQ==", + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.1.12.tgz", + "integrity": "sha512-Q3MXXQABG4CZBesSp82yV84uhJh/W0Gag6KPm2HRWPimSFELM09Z9/5WK9RItAYE0aLhe4Krnyiczn9AAa1tQQ==", "dev": true, "peer": true, "dependencies": { @@ -5797,9 +5454,9 @@ } }, "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.4.tgz", + "integrity": "sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==", "dev": true, "dependencies": { "@babel/parser": "^7.20.7", @@ -5810,9 +5467,9 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", "dev": true, "dependencies": { "@babel/types": "^7.0.0" @@ -5829,9 +5486,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", - "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" @@ -5934,9 +5591,9 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz", + "integrity": "sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==", "dev": true }, "node_modules/@types/stack-utils": { @@ -5952,18 +5609,18 @@ "dev": true }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.9.tgz", + "integrity": "sha512-jbdrY0a8lxfdTp/+r7Z4CkycbOFN8WX+IOchLJr3juT/xzbJ8URyTVSJ/hvNdadTgM1mnedb47n+Y31GsFnQlg==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "version": "17.0.31", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz", + "integrity": "sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -6336,9 +5993,9 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -6685,11 +6342,11 @@ } }, "node_modules/axios": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", - "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz", + "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==", "dependencies": { - "follow-redirects": "^1.15.4", + "follow-redirects": "^1.15.0", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -6798,7 +6455,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/babel-merge/-/babel-merge-3.0.0.tgz", "integrity": "sha512-eBOBtHnzt9xvnjpYNI5HmaPp/b2vMveE5XggzqHnQeHJ8mFIBrBv6WZEVIj5jJ2uwTItkqKo9gWzEEcBxEq0yw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, "dependencies": { "deepmerge": "^2.2.1", @@ -6865,9 +6521,9 @@ } }, "node_modules/babel-plugin-jsx-dom-expressions": { - "version": "0.37.13", - "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.37.13.tgz", - "integrity": "sha512-oAEMMIgU0h1DmHn4ZDaBBFc08nsVJciLq9pF7g0ZdpeIDKfY4zXjXr8+/oBjKhXG8nyomhnTodPjeG+/ZXcWXQ==", + "version": "0.37.8", + "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.37.8.tgz", + "integrity": "sha512-nVHH6g7541aaAQJAsyWHvjH7GCXZ+8tuF3Qu4y9W9aKwonRbcJL+yyMatDJLvjC54iIuGowiiZM6Rm3AVJczGg==", "dev": true, "dependencies": { "@babel/helper-module-imports": "7.18.6", @@ -7086,9 +6742,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", "dev": true, "funding": [ { @@ -7105,9 +6761,9 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", - "node-releases": "^2.0.14", + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", "update-browserslist-db": "^1.0.13" }, "bin": { @@ -7325,9 +6981,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001579", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz", - "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==", + "version": "1.0.30001562", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001562.tgz", + "integrity": "sha512-kfte3Hym//51EdX4239i+Rmp20EsLIYGdPkERegTgU19hQWCRhsRFGKHTliUlsry53tv17K7n077Kqa0WJU4ng==", "dev": true, "funding": [ { @@ -7528,9 +7184,9 @@ } }, "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz", + "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==", "dev": true, "engines": { "node": ">=6" @@ -7962,9 +7618,9 @@ } }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", "dev": true }, "node_modules/damerau-levenshtein": { @@ -8078,6 +7734,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -8226,57 +7883,6 @@ "node": ">=6.0.0" } }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, "node_modules/dot-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", @@ -8288,9 +7894,9 @@ } }, "node_modules/dotenv": { - "version": "16.3.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.2.tgz", - "integrity": "sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ==", + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", "dev": true, "engines": { "node": ">=12" @@ -8330,9 +7936,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.640", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.640.tgz", - "integrity": "sha512-z/6oZ/Muqk4BaE7P69bXhUhpJbUM9ZJeka43ZwxsDshKtePns4mhBlh8bU5+yrnOnz3fhG82XLzGUXazOmsWnA==", + "version": "1.4.582", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.582.tgz", + "integrity": "sha512-89o0MGoocwYbzqUUjc+VNpeOFSOK9nIdC5wY4N+PVUarUK0MtjyTjks75AZS2bW4Kl8MdewdFsWaH0jLy+JNoA==", "dev": true }, "node_modules/emittery": { @@ -8380,9 +7986,11 @@ } }, "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "dev": true, + "peer": true, "engines": { "node": ">=0.12" }, @@ -8630,22 +8238,10 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-compat-utils": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz", - "integrity": "sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "eslint": ">=6.0.0" - } - }, "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -8749,14 +8345,13 @@ } }, "node_modules/eslint-plugin-es-x": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.5.0.tgz", - "integrity": "sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.3.0.tgz", + "integrity": "sha512-W9zIs+k00I/I13+Bdkl/zG1MEO07G97XjUSQuH117w620SJ6bHtLUmoMvkGA2oYnI/gNdr+G7BONLyYnFaLLEQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.1.2", - "@eslint-community/regexpp": "^4.6.0", - "eslint-compat-utils": "^0.1.2" + "@eslint-community/regexpp": "^4.6.0" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -9031,16 +8626,15 @@ } }, "node_modules/eslint-plugin-n": { - "version": "16.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz", - "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==", + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.3.1.tgz", + "integrity": "sha512-w46eDIkxQ2FaTHcey7G40eD+FhTXOdKudDXPUO2n9WNcslze/i/HT2qJ3GXjHngYSGDISIgPNhwGtgoix4zeOw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "builtins": "^5.0.1", - "eslint-plugin-es-x": "^7.5.0", + "eslint-plugin-es-x": "^7.1.0", "get-tsconfig": "^4.7.0", - "globals": "^13.24.0", "ignore": "^5.2.4", "is-builtin-module": "^3.2.1", "is-core-module": "^2.12.1", @@ -9058,21 +8652,6 @@ "eslint": ">=7.0.0" } }, - "node_modules/eslint-plugin-n/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-plugin-n/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -9100,18 +8679,6 @@ "node": ">=10" } }, - "node_modules/eslint-plugin-n/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-plugin-n/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -9350,9 +8917,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -9629,9 +9196,9 @@ } }, "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -9773,9 +9340,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", "funding": [ { "type": "individual", @@ -10285,16 +9852,16 @@ } }, "node_modules/graphql-config/node_modules/@graphql-tools/executor-legacy-ws": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.0.5.tgz", - "integrity": "sha512-w54AZ7zkNuvpyV09FH+eGHnnAmaxhBVHg4Yh2ICcsMfRg0brkLt77PlbjBuxZ4HY8XZnKJaYWf+tKazQZtkQtg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.0.4.tgz", + "integrity": "sha512-b7aGuRekZDS+m3af3BIvMKxu15bmVPMt5eGQVuP2v5pxmbaPTh+iv5mx9b3Plt32z5Ke5tycBnNm5urSFtW8ng==", "dev": true, "dependencies": { "@graphql-tools/utils": "^10.0.0", "@types/ws": "^8.0.0", - "isomorphic-ws": "^5.0.0", + "isomorphic-ws": "5.0.0", "tslib": "^2.4.0", - "ws": "^8.15.0" + "ws": "8.14.2" }, "engines": { "node": ">=16.0.0" @@ -10304,15 +9871,15 @@ } }, "node_modules/graphql-config/node_modules/@graphql-tools/url-loader": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.1.tgz", - "integrity": "sha512-B2k8KQEkEQmfV1zhurT5GLoXo8jbXP+YQHUayhCSxKYlRV7j/1Fhp1b21PDM8LXIDGlDRXaZ0FbWKOs7eYXDuQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.0.tgz", + "integrity": "sha512-rPc9oDzMnycvz+X+wrN3PLrhMBQkG4+sd8EzaFN6dypcssiefgWKToXtRKI8HHK68n2xEq1PyrOpkjHFJB+GwA==", "dev": true, "dependencies": { "@ardatan/sync-fetch": "^0.0.1", "@graphql-tools/delegate": "^10.0.0", "@graphql-tools/executor-graphql-ws": "^1.0.0", - "@graphql-tools/executor-http": "^1.0.5", + "@graphql-tools/executor-http": "^1.0.0", "@graphql-tools/executor-legacy-ws": "^1.0.0", "@graphql-tools/utils": "^10.0.0", "@graphql-tools/wrap": "^10.0.0", @@ -10359,9 +9926,9 @@ } }, "node_modules/graphql-config/node_modules/@whatwg-node/fetch": { - "version": "0.9.15", - "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.15.tgz", - "integrity": "sha512-2wIUcolUthZt0nsPRj+pT7K9h/EO3t/j09IBuq0FtITCsASc2fRCmRw2JHS6hk9fzUQrz2+YYrA1ZDpV7+vLsQ==", + "version": "0.9.14", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.14.tgz", + "integrity": "sha512-wurZC82zzZwXRDSW0OS9l141DynaJQh7Yt0FD1xZ8niX7/Et/7RoiLiltbVU1fSF1RR9z6ndEaTUQBAmddTm1w==", "dev": true, "dependencies": { "@whatwg-node/node-fetch": "^0.5.0", @@ -10372,15 +9939,15 @@ } }, "node_modules/graphql-config/node_modules/@whatwg-node/node-fetch": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.4.tgz", - "integrity": "sha512-5AXi4B44/6SOlQG+X3cO5lsUdRTWSXqaWLkGKnwWfeJoMgRfA53RnYVnvTV+4CoatNBStPrIoDorjgQv+ouiMQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.0.tgz", + "integrity": "sha512-q76lDAafvHNGWedNAVHrz/EyYTS8qwRLcwne8SJQdRN5P3HydxU6XROFvJfTML6KZXQX2FDdGY4/SnaNyd7M0Q==", "dev": true, "dependencies": { - "@kamilkisiela/fast-url-parser": "^1.1.4", "@whatwg-node/events": "^0.1.0", "busboy": "^1.6.0", "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", "tslib": "^2.3.1" }, "engines": { @@ -10388,9 +9955,9 @@ } }, "node_modules/graphql-config/node_modules/graphql-ws": { - "version": "5.14.3", - "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.14.3.tgz", - "integrity": "sha512-F/i2xNIVbaEF2xWggID0X/UZQa2V8kqKDPO8hwmu53bVOcTL7uNkxnexeEgSCVxYBQUTUNEI8+e4LO1FOhKPKQ==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.14.2.tgz", + "integrity": "sha512-LycmCwhZ+Op2GlHz4BZDsUYHKRiiUz+3r9wbhBATMETNlORQJAaFlAgTFoeRh6xQoQegwYwIylVD1Qns9/DA3w==", "dev": true, "engines": { "node": ">=10" @@ -10608,24 +10175,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, "node_modules/http-proxy-agent": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", @@ -11067,9 +10616,9 @@ ] }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" @@ -13725,9 +13274,9 @@ } }, "node_modules/jose": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/jose/-/jose-5.2.0.tgz", - "integrity": "sha512-oW3PCnvyrcm1HMvGTzqjxxfnEs9EoFOFWi2HsEGhlFVOXxTE3K9GKWVMFoFw06yPUqwpvEWic1BmtUZBI/tIjw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.1.1.tgz", + "integrity": "sha512-bfB+lNxowY49LfrBO0ITUn93JbUhxUN8I11K6oI5hJu/G6PO6fEUddVLjqdD0cQ9SXIHWXuWh7eJYwZF7Z0N/g==", "dev": true, "funding": { "url": "https://github.com/sponsors/panva" @@ -13803,9 +13352,9 @@ "dev": true }, "node_modules/json-stable-stringify": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz", - "integrity": "sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.0.tgz", + "integrity": "sha512-zfA+5SuwYN2VWqN1/5HZaDzQKLJHaBVMZIIM+wuYjdptkaQsqzDdqjqf+lZZJUuJq1aanHiY8LhH8LmH+qBYJA==", "dev": true, "dependencies": { "call-bind": "^1.0.5", @@ -13972,9 +13521,9 @@ } }, "node_modules/lib0": { - "version": "0.2.88", - "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.88.tgz", - "integrity": "sha512-KyroiEvCeZcZEMx5Ys+b4u4eEBbA1ch7XUaBhYpwa/nPMrzTjUhI4RfcytmQfYoTBPcdyx+FX6WFNIoNuJzJfQ==", + "version": "0.2.87", + "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.87.tgz", + "integrity": "sha512-TbB63XJixvNToW2IHWAFsCJj9tVnajmwjE14p69i51Rx8byOQd2IP4ourE8v4d7vhyO++nVm1sQk3ePslfbucg==", "dev": true, "dependencies": { "isomorphic.js": "^0.2.4" @@ -14007,19 +13556,19 @@ "dev": true }, "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz", + "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", "dev": true, "peer": true, "dependencies": { - "uc.micro": "^2.0.0" + "uc.micro": "^1.0.1" } }, "node_modules/linkifyjs": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.1.3.tgz", - "integrity": "sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.1.2.tgz", + "integrity": "sha512-1elJrH8MwUgr77Rgmx4JgB/nBgISYVoGossH6pAfCeHG+07TblTn6RWKx0MKozEMJU6NCFYHRih9M8ZtV3YZ+Q==", "dev": true }, "node_modules/lint-staged": { @@ -14248,9 +13797,9 @@ } }, "node_modules/lint-staged/node_modules/npm-run-path": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", - "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -14918,21 +14467,20 @@ } }, "node_modules/markdown-it": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.0.0.tgz", - "integrity": "sha512-seFjF0FIcPt4P9U39Bq1JYblX0KZCjDLFFQPHpL5AzHpqPEKtosxmdq/LTVZnjfH7tjt9BxStm+wXcDBNuYmzw==", + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz", + "integrity": "sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==", "dev": true, "peer": true, "dependencies": { "argparse": "^2.0.1", - "entities": "^4.4.0", - "linkify-it": "^5.0.0", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.0.0" + "entities": "~3.0.1", + "linkify-it": "^4.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" }, "bin": { - "markdown-it": "bin/markdown-it.mjs" + "markdown-it": "bin/markdown-it.js" } }, "node_modules/mathml-tag-names": { @@ -14952,9 +14500,9 @@ "dev": true }, "node_modules/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", "dev": true, "peer": true }, @@ -15242,9 +14790,9 @@ } }, "node_modules/mrmime": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", - "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", "dev": true, "engines": { "node": ">=10" @@ -15266,6 +14814,7 @@ "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, "funding": [ { "type": "github", @@ -15337,9 +14886,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, "node_modules/normalize-package-data": { @@ -15418,13 +14967,13 @@ } }, "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, @@ -15776,11 +15325,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-srcset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", - "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" - }, "node_modules/pascal-case": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", @@ -15867,7 +15411,8 @@ "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", @@ -15976,9 +15521,10 @@ } }, "node_modules/postcss": { - "version": "8.4.33", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", - "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -15994,7 +15540,7 @@ } ], "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -16076,9 +15622,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.15", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", - "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -16267,9 +15813,9 @@ } }, "node_modules/prosemirror-inputrules": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.3.0.tgz", - "integrity": "sha512-z1GRP2vhh5CihYMQYsJSa1cOwXb3SYxALXOIfAkX8nZserARtl9LiL+CEl+T+OFIsXc3mJIHKhbsmRzC0HDAXA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.2.1.tgz", + "integrity": "sha512-3LrWJX1+ULRh5SZvbIQlwZafOXqp1XuV21MGBu/i5xsztd+9VD15x6OtN6mdqSFI7/8Y77gYUbQ6vwwJ4mr6QQ==", "dev": true, "peer": true, "dependencies": { @@ -16289,13 +15835,13 @@ } }, "node_modules/prosemirror-markdown": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.12.0.tgz", - "integrity": "sha512-6F5HS8Z0HDYiS2VQDZzfZP6A0s/I0gbkJy8NCzzDMtcsz3qrfqyroMMeoSjAmOhDITyon11NbXSzztfKi+frSQ==", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.11.2.tgz", + "integrity": "sha512-Eu5g4WPiCdqDTGhdSsG9N6ZjACQRYrsAkrF9KYfdMaCmjIApH75aVncsWYOJvEk2i1B3i8jZppv3J/tnuHGiUQ==", "dev": true, "peer": true, "dependencies": { - "markdown-it": "^14.0.0", + "markdown-it": "^13.0.1", "prosemirror-model": "^1.0.0" } }, @@ -16313,9 +15859,9 @@ } }, "node_modules/prosemirror-model": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.19.4.tgz", - "integrity": "sha512-RPmVXxUfOhyFdayHawjuZCxiROsm9L4FCUA6pWI+l7n2yCBsWy9VpdE1hpDHUS8Vad661YLY9AzqfjLhAKQ4iQ==", + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.19.3.tgz", + "integrity": "sha512-tgSnwN7BS7/UM0sSARcW+IQryx2vODKX4MI7xpqY2X+iaepJdKBPc7I4aACIsDV/LTaTjt12Z56MhDr9LsyuZQ==", "dev": true, "dependencies": { "orderedmap": "^2.0.0" @@ -16355,9 +15901,9 @@ } }, "node_modules/prosemirror-tables": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.3.5.tgz", - "integrity": "sha512-JSZ2cCNlApu/ObAhdPyotrjBe2cimniniTpz60YXzbL0kZ+47nEYk2LWbfKU2lKpBkUNquta2PjteoNi4YCluQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.3.4.tgz", + "integrity": "sha512-z6uLSQ1BLC3rgbGwZmpfb+xkdvD7W/UOsURDfognZFYaTtc0gsk7u/t71Yijp2eLflVpffMk6X0u0+u+MMDvIw==", "dev": true, "peer": true, "dependencies": { @@ -16428,16 +15974,6 @@ "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "dev": true }, - "node_modules/punycode.js": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/pure-rand": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", @@ -16714,9 +16250,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/regexp-ast-analysis": { "version": "0.6.0", @@ -16926,9 +16462,9 @@ } }, "node_modules/rfdc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", - "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", "dev": true }, "node_modules/rimraf": { @@ -17010,13 +16546,13 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", - "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -17048,18 +16584,15 @@ ] }, "node_modules/safe-regex-test": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", - "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", "is-regex": "^1.1.4" }, - "engines": { - "node": ">= 0.4" - }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -17070,38 +16603,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "node_modules/sanitize-html": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.11.0.tgz", - "integrity": "sha512-BG68EDHRaGKqlsNjJ2xUB7gpInPA8gVx/mvjO743hZaeMCZ2DwzW7xvsqZ+KNU4QKwj86HJ3uu2liISf2qBBUA==", - "dependencies": { - "deepmerge": "^4.2.2", - "escape-string-regexp": "^4.0.0", - "htmlparser2": "^8.0.0", - "is-plain-object": "^5.0.0", - "parse-srcset": "^1.0.2", - "postcss": "^8.3.11" - } - }, - "node_modules/sanitize-html/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/sanitize-html/node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/sass": { "version": "1.69.5", "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.5.tgz", @@ -17178,16 +16679,15 @@ "dev": true }, "node_modules/set-function-length": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", - "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", "dev": true, "dependencies": { "define-data-property": "^1.1.1", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.2", + "get-intrinsic": "^1.2.1", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "has-property-descriptors": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -17270,13 +16770,13 @@ "dev": true }, "node_modules/sirv": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", - "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", + "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==", "dev": true, "dependencies": { - "@polka/url": "^1.0.0-next.24", - "mrmime": "^2.0.0", + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", "totalist": "^3.0.0" }, "engines": { @@ -17544,6 +17044,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -17972,12 +17473,12 @@ "dev": true }, "node_modules/stylelint/node_modules/file-entry-cache": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-7.0.2.tgz", - "integrity": "sha512-TfW7/1iI4Cy7Y8L6iqNdZQVvdXn0f8B4QcIXmkIbtTIe/Okm/nSlHb4IwGzRVOd3WfSieCgvf5cMzEfySAIl0g==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-7.0.1.tgz", + "integrity": "sha512-uLfFktPmRetVCbHe5UPuekWrQ6hENufnA46qEGbfACkK5drjTTdQYUragRgMjHldcbYG+nslUerqMPjbBSHXjQ==", "dev": true, "dependencies": { - "flat-cache": "^3.2.0" + "flat-cache": "^3.1.1" }, "engines": { "node": ">=12.0.0" @@ -18350,9 +17851,9 @@ "dev": true }, "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", @@ -18552,9 +18053,9 @@ } }, "node_modules/uc.micro": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.0.0.tgz", - "integrity": "sha512-DffL94LsNOccVn4hyfRe5rdKa273swqeA5DJpMOeFmEn1wCDc7nAbbB0gXlgBCL7TNzeTv6G7XVWzan7iJtfig==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true, "peer": true }, @@ -18717,9 +18218,9 @@ "dev": true }, "node_modules/v8-to-istanbul": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", - "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", + "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", @@ -18910,54 +18411,6 @@ "vite": "^3.0.0 || ^4.0.0" } }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/vite/node_modules/@esbuild/darwin-arm64": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", @@ -18974,294 +18427,6 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/vite/node_modules/esbuild": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", @@ -19330,9 +18495,9 @@ } }, "node_modules/vue-eslint-parser": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.1.tgz", - "integrity": "sha512-EmIbJ5cCI/E06SlI8K5sldVZ+Ef5vy26Ck0lNALxgY7FEAMOjNR32qcsVM3FUJUbvVWTBEiOy5lQvbhPK/ynBw==", + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.2.tgz", + "integrity": "sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==", "dev": true, "dependencies": { "debug": "^4.3.4", @@ -19412,9 +18577,9 @@ } }, "node_modules/web-streams-polyfill": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.2.tgz", - "integrity": "sha512-3pRGuxRF5gpuZc0W+EpwQRmCD7gRqcDOMt688KmdlDAgAyaB1XlN0zq2njfDNm44XVdIouE7pZ6GzbdyH47uIQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", "dev": true, "engines": { "node": ">= 8" @@ -19619,9 +18784,9 @@ } }, "node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "dev": true, "engines": { "node": ">=10.0.0" diff --git a/package.json b/package.json index f26b33d7..15dc67df 100644 --- a/package.json +++ b/package.json @@ -35,8 +35,6 @@ "i18next-icu": "2.3.0", "intl-messageformat": "10.5.3", "just-throttle": "4.2.0", - "mailgun.js": "8.2.1", - "sanitize-html": "2.11.0", "mailgun.js": "8.2.1" }, "devDependencies": { diff --git a/src/components/Feed/ArticleCard/ArticleCard.tsx b/src/components/Feed/ArticleCard/ArticleCard.tsx index ae2d768f..4374ac2b 100644 --- a/src/components/Feed/ArticleCard/ArticleCard.tsx +++ b/src/components/Feed/ArticleCard/ArticleCard.tsx @@ -1,5 +1,4 @@ import { createMemo, createSignal, For, Show } from 'solid-js' -import sanitizeHtml from 'sanitize-html' import type { Shout } from '../../../graphql/types.gen' @@ -90,14 +89,6 @@ const getTitleAndSubtitle = ( return { title, subtitle } } -const sanitizeString = (html) => - sanitizeHtml(html, { - allowedTags: ['span'], - allowedAttributes: { - span: ['class'], - }, - }) - export const ArticleCard = (props: ArticleCardProps) => { const { t, lang, formatDate } = useLocalize() const { user } = useSession() @@ -223,13 +214,13 @@ export const ArticleCard = (props: ArticleCardProps) => {
    - +
    - +
    @@ -259,10 +250,7 @@ export const ArticleCard = (props: ArticleCardProps) => {
    -
    +
    diff --git a/src/components/Nav/SearchModal/SearchModal.tsx b/src/components/Nav/SearchModal/SearchModal.tsx index 227d2641..8223171e 100644 --- a/src/components/Nav/SearchModal/SearchModal.tsx +++ b/src/components/Nav/SearchModal/SearchModal.tsx @@ -1,4 +1,4 @@ -import { createSignal, Show, For, JSX } from 'solid-js' +import { createSignal, Show, For } from 'solid-js' import { Button } from '../../_shared/Button' import { Icon } from '../../_shared/Icon' From 617969ad1515272453b830c062c0a58df5bde75b Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 22 Jan 2024 17:12:54 +0300 Subject: [PATCH 17/88] filters-type-fix --- src/stores/zine/articles.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stores/zine/articles.ts b/src/stores/zine/articles.ts index c953a17e..1fb5c731 100644 --- a/src/stores/zine/articles.ts +++ b/src/stores/zine/articles.ts @@ -222,7 +222,7 @@ export const useArticlesStore = (initialState: InitialState = {}) => { if (initialState.layout) { // eslint-disable-next-line promise/catch-or-return - loadShouts({ filters: { layout: initialState.layout }, limit: 10 }).then(({ newShouts }) => { + loadShouts({ filters: { layouts: [initialState.layout] }, limit: 10 }).then(({ newShouts }) => { addArticles(newShouts) setSortedArticles(newShouts) }) From e5d3235846b25e9f823ccb1b4ef95defa93b7318 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 22 Jan 2024 20:05:13 +0300 Subject: [PATCH 18/88] less-token-check --- src/components/AuthGuard/AuthGuard.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/AuthGuard/AuthGuard.tsx b/src/components/AuthGuard/AuthGuard.tsx index 73144eb0..5cfa404f 100644 --- a/src/components/AuthGuard/AuthGuard.tsx +++ b/src/components/AuthGuard/AuthGuard.tsx @@ -36,7 +36,8 @@ export const AuthGuard = (props: Props) => { ) } } else { - await loadSession() + // await loadSession() + console.warn('session is not loaded') } }) From 0faa9df81c8490d820cfe994ff4b1d8ca5a55653 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 22 Jan 2024 20:37:27 +0300 Subject: [PATCH 19/88] selected-topics-default --- src/components/Views/PublishSettings/PublishSettings.tsx | 1 + src/context/editor.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Views/PublishSettings/PublishSettings.tsx b/src/components/Views/PublishSettings/PublishSettings.tsx index 2cc1e3eb..90c6b289 100644 --- a/src/components/Views/PublishSettings/PublishSettings.tsx +++ b/src/components/Views/PublishSettings/PublishSettings.tsx @@ -56,6 +56,7 @@ export const PublishSettings = (props: Props) => { title: props.form.title, subtitle: props.form.subtitle, description: composeDescription(), + selectedTopics: [], } const { diff --git a/src/context/editor.tsx b/src/context/editor.tsx index cdb4022d..41975d52 100644 --- a/src/context/editor.tsx +++ b/src/context/editor.tsx @@ -23,7 +23,7 @@ export type ShoutForm = { shoutId: number slug: string title: string - subtitle: string + subtitle?: string lead?: string description?: string selectedTopics: Topic[] From 7788100dc596a89f9672fba239bc9f675af30591 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 22 Jan 2024 20:59:49 +0300 Subject: [PATCH 20/88] notifications-stability-fix --- src/context/notifications.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/context/notifications.tsx b/src/context/notifications.tsx index f104faa6..bdbc1bb2 100644 --- a/src/context/notifications.tsx +++ b/src/context/notifications.tsx @@ -47,7 +47,11 @@ export const NotificationsProvider = (props: { children: JSX.Element }) => { const loadNotificationsGrouped = async (options: { after: number; limit?: number; offset?: number }) => { if (isAuthenticated() && notifierClient?.private) { - const { notifications: groups, total, unread } = await notifierClient.getNotifications(options) + const notificationsResult = await notifierClient.getNotifications(options) + const groups = notificationsResult?.notifications || [] + const total = notificationsResult?.total || 0 + const unread = notificationsResult?.unread || 0 + const newGroupsEntries = groups.reduce((acc, group: NotificationGroup) => { acc[group.id] = group return acc From e974e43c22517c7ab84cddf9f6a69acea5eb2ad8 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 22 Jan 2024 21:53:04 +0300 Subject: [PATCH 21/88] load-topics-on-create --- src/components/Views/PublishSettings/PublishSettings.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/Views/PublishSettings/PublishSettings.tsx b/src/components/Views/PublishSettings/PublishSettings.tsx index 90c6b289..8e8429f9 100644 --- a/src/components/Views/PublishSettings/PublishSettings.tsx +++ b/src/components/Views/PublishSettings/PublishSettings.tsx @@ -1,6 +1,6 @@ import { redirectPage } from '@nanostores/router' import { clsx } from 'clsx' -import { lazy, Show } from 'solid-js' +import { createEffect, lazy, Show } from 'solid-js' import { createStore } from 'solid-js/store' import { ShoutForm, useEditorContext } from '../../../context/editor' @@ -9,7 +9,7 @@ import { useSession } from '../../../context/session' import { UploadedFile } from '../../../pages/types' import { router } from '../../../stores/router' import { hideModal, showModal } from '../../../stores/ui' -import { useTopicsStore } from '../../../stores/zine/topics' +import { loadAllTopics, useTopicsStore } from '../../../stores/zine/topics' import { Button } from '../../_shared/Button' import { Icon } from '../../_shared/Icon' import { Image } from '../../_shared/Image' @@ -40,6 +40,10 @@ export const PublishSettings = (props: Props) => { const { author } = useSession() const { sortedTopics } = useTopicsStore() + createEffect(async () => { + if (!sortedTopics()) await loadAllTopics() + }) + const composeDescription = () => { if (!props.form.description) { const cleanFootnotes = props.form.body.replaceAll(/.*?<\/footnote>/g, '') From e796fa30a4c49150d2c452c2517398f9288b4620 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 22 Jan 2024 22:39:39 +0300 Subject: [PATCH 22/88] load-topics-fix --- src/components/Views/PublishSettings/PublishSettings.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/Views/PublishSettings/PublishSettings.tsx b/src/components/Views/PublishSettings/PublishSettings.tsx index 8e8429f9..a622023d 100644 --- a/src/components/Views/PublishSettings/PublishSettings.tsx +++ b/src/components/Views/PublishSettings/PublishSettings.tsx @@ -41,7 +41,9 @@ export const PublishSettings = (props: Props) => { const { sortedTopics } = useTopicsStore() createEffect(async () => { - if (!sortedTopics()) await loadAllTopics() + if (sortedTopics()?.length < 33) { + await loadAllTopics() + } }) const composeDescription = () => { From fc601c747e3830b7d95b22c60034dd5a6954ec95 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 22 Jan 2024 23:38:31 +0300 Subject: [PATCH 23/88] get-image-url-fix --- src/utils/config.ts | 1 + src/utils/getImageUrl.ts | 23 ++++++++--------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/utils/config.ts b/src/utils/config.ts index ea2e7488..78f683e5 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -1,6 +1,7 @@ export const isDev = import.meta.env.MODE === 'development' const defaultThumborUrl = 'https://images.discours.io' +export const cdnUrl = 'https://cdn.discours.io' export const thumborUrl = import.meta.env.PUBLIC_THUMBOR_URL || defaultThumborUrl export const SENTRY_DSN = import.meta.env.PUBLIC_SENTRY_DSN || '' diff --git a/src/utils/getImageUrl.ts b/src/utils/getImageUrl.ts index 661e3951..c276027d 100644 --- a/src/utils/getImageUrl.ts +++ b/src/utils/getImageUrl.ts @@ -1,6 +1,4 @@ -import { thumborUrl } from './config' - -const thumborPrefix = `${thumborUrl}/unsafe/` +import { thumborUrl, cdnUrl } from './config' const getSizeUrlPart = (options: { width?: number; height?: number } = {}) => { const widthString = options.width ? options.width.toString() : '' @@ -17,21 +15,16 @@ export const getImageUrl = ( src: string, options: { width?: number; height?: number; noSizeUrlPart?: boolean } = {}, ) => { - const sizeUrlPart = getSizeUrlPart(options) - - let modifiedSrc = src // Используйте новую переменную вместо переназначения параметра + const isAudio = src.toLowerCase().split('.')[-1] in ['wav', 'mp3', 'ogg', 'aif', 'flac'] + const base = isAudio ? cdnUrl : thumborUrl + const sizeUrlPart = isAudio ? '' : getSizeUrlPart(options) + let modifiedSrc = src.replaceAll(thumborUrl + '/', '').replaceAll(cdnUrl + '/', '') // Используйте новую переменную вместо переназначения параметра if (options.noSizeUrlPart) { modifiedSrc = modifiedSrc.replace(/\d+x.*?\//, '') } - if (src.startsWith(thumborPrefix)) { - const thumborKey = modifiedSrc.replace(thumborPrefix, '') - - return `${thumborUrl}/unsafe/${sizeUrlPart}${thumborKey}` - } - - return `${thumborUrl}/unsafe/${sizeUrlPart}${modifiedSrc}` + return `${base}/unsafe/${sizeUrlPart}${modifiedSrc}` } export const getOpenGraphImageUrl = ( @@ -50,8 +43,8 @@ export const getOpenGraphImageUrl = ( options.author, )}','${encodeURIComponent(options.title)}')/` - if (src.startsWith(thumborPrefix)) { - const thumborKey = src.replace(thumborPrefix, '') + if (src.startsWith(thumborUrl)) { + const thumborKey = src.replace(thumborUrl + '/unsafe', '') return `${thumborUrl}/unsafe/${sizeUrlPart}${filtersPart}${thumborKey}` } From 92eae0347bd8f334edb6f01fcc933a7ad6d15dc2 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 22 Jan 2024 23:53:35 +0300 Subject: [PATCH 24/88] handle-rating-debug --- src/components/Article/ShoutRatingControl.tsx | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/src/components/Article/ShoutRatingControl.tsx b/src/components/Article/ShoutRatingControl.tsx index bdf07548..7e0f22cb 100644 --- a/src/components/Article/ShoutRatingControl.tsx +++ b/src/components/Article/ShoutRatingControl.tsx @@ -51,29 +51,12 @@ export const ShoutRatingControl = (props: ShoutRatingControlProps) => { ), ) - const deleteShoutReaction = async (reactionKind: ReactionKind) => { - const reactionToDelete = Object.values(reactionEntities).find( - (r) => - r.kind === reactionKind && - r.created_by.slug === author()?.slug && - r.shout.id === props.shout.id && - !r.reply_to, - ) - return deleteReaction(reactionToDelete.id) - } - const handleRatingChange = async (isUpvote: boolean) => { requireAuthentication(async () => { - if (isUpvoted()) { - await deleteShoutReaction(ReactionKind.Like) - } else if (isDownvoted()) { - await deleteShoutReaction(ReactionKind.Dislike) - } else { - await createReaction({ - kind: isUpvote ? ReactionKind.Like : ReactionKind.Dislike, - shout: props.shout.id, - }) - } + await createReaction({ + kind: isUpvote ? ReactionKind.Like : ReactionKind.Dislike, + shout: props.shout.id, + }) loadShout(props.shout.slug) loadReactionsBy({ From 30e143e0810525e2ee69c1101e0000df6042f12f Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 00:03:57 +0300 Subject: [PATCH 25/88] requireAuth-fix-2 --- src/context/session.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/context/session.tsx b/src/context/session.tsx index 3d7b701b..94a69ea0 100644 --- a/src/context/session.tsx +++ b/src/context/session.tsx @@ -255,13 +255,21 @@ export const SessionProvider = (props: { const requireAuthentication = async (callback: () => void, modalSource: AuthModalSource) => { setIsAuthWithCallback(() => callback) - await loadSession() - if (!session()) { - showModal('auth', modalSource) + await loadSession() + if (!session()) { + showModal('auth', modalSource) + } } } + createEffect(() => { + if (isAuthWithCallback()) { + isAuthWithCallback()() + setIsAuthWithCallback(null) + } + }) + // authorizer api proxy methods const signUp = async (params: SignupInput) => { const authResult: void | AuthToken = await authorizer().signup(params) From 4afd84a848eec30a55ec9125d4622ef384b5773b Mon Sep 17 00:00:00 2001 From: kvakazyambra Date: Tue, 23 Jan 2024 00:53:50 +0300 Subject: [PATCH 26/88] Minor style fixes --- src/components/Feed/ArticleCard/ArticleCard.module.scss | 3 +-- src/components/Nav/Topics/Topics.module.scss | 2 -- src/components/_shared/Popup/Popup.module.scss | 2 +- src/components/_shared/SolidSwiper/Swiper.module.scss | 1 - src/styles/app.scss | 1 - 5 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/components/Feed/ArticleCard/ArticleCard.module.scss b/src/components/Feed/ArticleCard/ArticleCard.module.scss index d3f82554..336d82c8 100644 --- a/src/components/Feed/ArticleCard/ArticleCard.module.scss +++ b/src/components/Feed/ArticleCard/ArticleCard.module.scss @@ -440,7 +440,6 @@ @include media-breakpoint-down(xl) { aspect-ratio: auto; height: 100%; - padding-top: 30%; } swiper-slide & { @@ -502,7 +501,7 @@ display: flex; flex-direction: column; justify-content: end; - padding: 2.4rem; + padding: 30% 2.4rem 2.4rem; z-index: 1; @include media-breakpoint-down(xl) { diff --git a/src/components/Nav/Topics/Topics.module.scss b/src/components/Nav/Topics/Topics.module.scss index c7bec984..128dc46f 100644 --- a/src/components/Nav/Topics/Topics.module.scss +++ b/src/components/Nav/Topics/Topics.module.scss @@ -6,10 +6,8 @@ overflow: hidden; position: relative; transform: translateY(-2px); - width: 100%; @include media-breakpoint-down(sm) { - overflow: auto; padding: 0 divide($container-padding-x, 2); } diff --git a/src/components/_shared/Popup/Popup.module.scss b/src/components/_shared/Popup/Popup.module.scss index 1d0c7d80..5db976f9 100644 --- a/src/components/_shared/Popup/Popup.module.scss +++ b/src/components/_shared/Popup/Popup.module.scss @@ -14,7 +14,7 @@ opacity: 1; position: absolute; text-align: left; - top: calc(100% + 8px); + top: calc(100% + 11px); z-index: 101; ul { diff --git a/src/components/_shared/SolidSwiper/Swiper.module.scss b/src/components/_shared/SolidSwiper/Swiper.module.scss index 703a3337..3e9cdf82 100644 --- a/src/components/_shared/SolidSwiper/Swiper.module.scss +++ b/src/components/_shared/SolidSwiper/Swiper.module.scss @@ -130,7 +130,6 @@ box-sizing: border-box; overflow: hidden; width: 100%; - max-height: var(--slide-height); .counter { @include font-size(1.2rem); diff --git a/src/styles/app.scss b/src/styles/app.scss index 2d3a7ac2..0977d95a 100644 --- a/src/styles/app.scss +++ b/src/styles/app.scss @@ -213,7 +213,6 @@ a:visited, a:link, .link { color: var(--link-color); - padding-bottom: 0.1em; transition: color 0.2s, background-color 0.2s; From 40ea97c46393ded169d0b017845f69a9df2a21ba Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 01:12:25 +0300 Subject: [PATCH 27/88] rating-control-fix --- src/components/Article/ShoutRatingControl.tsx | 2 +- src/context/session.tsx | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/components/Article/ShoutRatingControl.tsx b/src/components/Article/ShoutRatingControl.tsx index 7e0f22cb..0352e9db 100644 --- a/src/components/Article/ShoutRatingControl.tsx +++ b/src/components/Article/ShoutRatingControl.tsx @@ -26,7 +26,7 @@ export const ShoutRatingControl = (props: ShoutRatingControlProps) => { const { reactionEntities, - actions: { createReaction, deleteReaction, loadReactionsBy }, + actions: { createReaction, loadReactionsBy }, } = useReactions() const checkReaction = (reactionKind: ReactionKind) => diff --git a/src/context/session.tsx b/src/context/session.tsx index 94a69ea0..490b09ab 100644 --- a/src/context/session.tsx +++ b/src/context/session.tsx @@ -47,7 +47,6 @@ export type SessionContextType = { authError: Accessor isSessionLoaded: Accessor subscriptions: Accessor - isAuthWithCallback: Accessor<() => void> isAuthenticated: Accessor actions: { loadSession: () => AuthToken | Promise @@ -70,6 +69,8 @@ export type SessionContextType = { } } +const noop = () => {} + const SessionContext = createContext() export function useSession() { @@ -250,11 +251,9 @@ export const SessionProvider = (props: { ), ) - // require auth wrapper - const [isAuthWithCallback, setIsAuthWithCallback] = createSignal<() => void>() + const [authCallback, setAuthCallback] = createSignal<() => void>(() => {}) const requireAuthentication = async (callback: () => void, modalSource: AuthModalSource) => { - setIsAuthWithCallback(() => callback) - + setAuthCallback((_cb) => callback) if (!session()) { await loadSession() if (!session()) { @@ -264,9 +263,10 @@ export const SessionProvider = (props: { } createEffect(() => { - if (isAuthWithCallback()) { - isAuthWithCallback()() - setIsAuthWithCallback(null) + const handler = authCallback() + if (handler !== noop) { + handler() + setAuthCallback((_cb) => noop) } }) @@ -345,7 +345,6 @@ export const SessionProvider = (props: { isSessionLoaded, author, actions, - isAuthWithCallback, isAuthenticated, } From ac849e5376479ff80eeed9c30840f4c81f757ffa Mon Sep 17 00:00:00 2001 From: kvakazyambra Date: Tue, 23 Jan 2024 01:14:04 +0300 Subject: [PATCH 28/88] Lightbox close control style fixes --- .../_shared/Lightbox/Lightbox.module.scss | 18 +++++++++--------- src/components/_shared/Lightbox/Lightbox.tsx | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/_shared/Lightbox/Lightbox.module.scss b/src/components/_shared/Lightbox/Lightbox.module.scss index dd60812e..fe78452e 100644 --- a/src/components/_shared/Lightbox/Lightbox.module.scss +++ b/src/components/_shared/Lightbox/Lightbox.module.scss @@ -23,20 +23,20 @@ border-radius: 100%; position: fixed; z-index: 1001; - top: 20px; - right: 40px; + top: -40px; + right: -40px; font-size: 30px; color: white; cursor: pointer; - width: 36px; - height: 36px; + width: 80px; + height: 80px; .icon { - height: 20px; - left: 50%; - top: 50%; - transform: translate(-50%, -50%); - width: 20px; + bottom: 16px; + height: 15px; + left: 16px; + position: absolute; + width: 15px; } } diff --git a/src/components/_shared/Lightbox/Lightbox.tsx b/src/components/_shared/Lightbox/Lightbox.tsx index aaa2ba9f..a8a9de53 100644 --- a/src/components/_shared/Lightbox/Lightbox.tsx +++ b/src/components/_shared/Lightbox/Lightbox.tsx @@ -153,9 +153,9 @@ export const Lightbox = (props: Props) => {
    {`${pictureScalePercentage()}%`}
    - +
    - +
    {props.shout.stat.rating}} variant="tiny"> @@ -89,12 +86,9 @@ export const ShoutRatingControl = (props: ShoutRatingControlProps) => {
    ) From d38adbfc61d4d5ea3ae52b4b1d108a66652c226b Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 16:22:18 +0300 Subject: [PATCH 33/88] ratings-fix --- package-lock.json | 14 -------------- src/components/Views/Feed/Feed.tsx | 6 +++--- src/components/Views/FeedSettings.tsx | 4 ++-- src/graphql/query/core/article-load.ts | 2 +- src/graphql/query/core/articles-load-by.ts | 2 +- src/graphql/query/core/articles-load-drafts.ts | 2 +- src/graphql/query/core/articles-load-feed.ts | 2 +- src/graphql/query/core/articles-load-followed.ts | 2 +- src/graphql/query/core/articles-load-random-top.ts | 2 +- .../query/core/articles-load-random-topic.ts | 2 +- src/graphql/query/core/articles-load-unrated.ts | 2 +- src/stores/zine/articles.ts | 4 ++-- 12 files changed, 15 insertions(+), 29 deletions(-) diff --git a/package-lock.json b/package-lock.json index 424ab0fe..c6b0edb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "license": "MIT", "dependencies": { "@authorizerdev/authorizer-js": "1.2.11", - "ackee-tracker": "5.1.0", "form-data": "4.0.0", "i18next": "22.4.15", "i18next-icu": "2.3.0", @@ -6379,14 +6378,6 @@ "tslib": "^2.3.1" } }, - "node_modules/ackee-tracker": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ackee-tracker/-/ackee-tracker-5.1.0.tgz", - "integrity": "sha512-A7iKkGyUnEXuOzxultQB7hnm4bStYCo1c38MYRRihBfqUP8AImhtZOODb00t9xrXs/BTsg06bz1MKpXeMs9sYw==", - "dependencies": { - "platform": "^1.3.6" - } - }, "node_modules/acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", @@ -15953,11 +15944,6 @@ "node": ">=8" } }, - "node_modules/platform": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", - "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" - }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", diff --git a/src/components/Views/Feed/Feed.tsx b/src/components/Views/Feed/Feed.tsx index 63d6945f..b3df32b7 100644 --- a/src/components/Views/Feed/Feed.tsx +++ b/src/components/Views/Feed/Feed.tsx @@ -48,14 +48,14 @@ type VisibilityItem = { } type FeedSearchParams = { - by: 'publish_date' | 'rating' | 'last_comment' + by: 'publish_date' | 'likes_stat' | 'rating' | 'last_comment' period: FeedPeriod visibility: VisibilityMode } const getOrderBy = (by: FeedSearchParams['by']) => { - if (by === 'rating') { - return 'rating_stat' + if (by === 'likes_stat' || by === 'rating') { + return 'likes_stat' } if (by === 'last_comment') { diff --git a/src/components/Views/FeedSettings.tsx b/src/components/Views/FeedSettings.tsx index 681f6020..3adbef52 100644 --- a/src/components/Views/FeedSettings.tsx +++ b/src/components/Views/FeedSettings.tsx @@ -3,7 +3,7 @@ import { useLocalize } from '../../context/localize' import styles from '../../styles/FeedSettings.module.scss' // type FeedSettingsSearchParams = { -// by: '' | 'topics' | 'authors' | 'reacted' +// by: '' | 'topics' | 'authors' | 'shouts' // } export const FeedSettingsView = (_props) => { @@ -25,7 +25,7 @@ export const FeedSettingsView = (_props) => { {t('authors')}
  • - {t('reactions')} + {t('publications')}
  • diff --git a/src/graphql/query/core/article-load.ts b/src/graphql/query/core/article-load.ts index f99e5e7e..066b7fb5 100644 --- a/src/graphql/query/core/article-load.ts +++ b/src/graphql/query/core/article-load.ts @@ -47,7 +47,7 @@ export default gql` published_at stat { viewed - reacted + rating commented } diff --git a/src/graphql/query/core/articles-load-by.ts b/src/graphql/query/core/articles-load-by.ts index 2f8129b6..a6a117ee 100644 --- a/src/graphql/query/core/articles-load-by.ts +++ b/src/graphql/query/core/articles-load-by.ts @@ -36,7 +36,7 @@ export default gql` published_at stat { viewed - reacted + rating commented } diff --git a/src/graphql/query/core/articles-load-drafts.ts b/src/graphql/query/core/articles-load-drafts.ts index 944739d7..7b2e4c01 100644 --- a/src/graphql/query/core/articles-load-drafts.ts +++ b/src/graphql/query/core/articles-load-drafts.ts @@ -34,7 +34,7 @@ export default gql` published_at stat { viewed - reacted + rating commented } diff --git a/src/graphql/query/core/articles-load-feed.ts b/src/graphql/query/core/articles-load-feed.ts index 01789b08..bc48b7cd 100644 --- a/src/graphql/query/core/articles-load-feed.ts +++ b/src/graphql/query/core/articles-load-feed.ts @@ -28,7 +28,7 @@ export default gql` published_at stat { viewed - reacted + rating } } diff --git a/src/graphql/query/core/articles-load-followed.ts b/src/graphql/query/core/articles-load-followed.ts index 122f290b..2eb0f193 100644 --- a/src/graphql/query/core/articles-load-followed.ts +++ b/src/graphql/query/core/articles-load-followed.ts @@ -31,7 +31,7 @@ export default gql` published_at stat { viewed - reacted + rating } } diff --git a/src/graphql/query/core/articles-load-random-top.ts b/src/graphql/query/core/articles-load-random-top.ts index e103ea28..f7f9b8cc 100644 --- a/src/graphql/query/core/articles-load-random-top.ts +++ b/src/graphql/query/core/articles-load-random-top.ts @@ -36,7 +36,7 @@ export default gql` published_at stat { viewed - reacted + rating commented } diff --git a/src/graphql/query/core/articles-load-random-topic.ts b/src/graphql/query/core/articles-load-random-topic.ts index 5ae25c19..e0b820c3 100644 --- a/src/graphql/query/core/articles-load-random-topic.ts +++ b/src/graphql/query/core/articles-load-random-topic.ts @@ -52,7 +52,7 @@ export default gql` published_at stat { viewed - reacted + rating commented } diff --git a/src/graphql/query/core/articles-load-unrated.ts b/src/graphql/query/core/articles-load-unrated.ts index 29b647de..fd0a2823 100644 --- a/src/graphql/query/core/articles-load-unrated.ts +++ b/src/graphql/query/core/articles-load-unrated.ts @@ -37,7 +37,7 @@ export default gql` published_at stat { viewed - reacted + rating commented } diff --git a/src/stores/zine/articles.ts b/src/stores/zine/articles.ts index 1fb5c731..c2293a27 100644 --- a/src/stores/zine/articles.ts +++ b/src/stores/zine/articles.ts @@ -196,7 +196,7 @@ export const loadTopMonthArticles = async (): Promise => { published: true, after, }, - order_by: 'rating_stat', + order_by: 'likes_stat', limit: TOP_MONTH_ARTICLES_COUNT, } const articles = await apiClient.getShouts(options) @@ -209,7 +209,7 @@ const TOP_ARTICLES_COUNT = 10 export const loadTopArticles = async (): Promise => { const options: LoadShoutsOptions = { filters: { published: true }, - order_by: 'rating_stat', + order_by: 'likes_stat', limit: TOP_ARTICLES_COUNT, } const articles = await apiClient.getShouts(options) From 8f6de58f6d185e9af7d6afc9f267ecf278fc6dcf Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 16:42:05 +0300 Subject: [PATCH 34/88] drafts-fix --- .../Views/DraftsView/DraftsView.tsx | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/components/Views/DraftsView/DraftsView.tsx b/src/components/Views/DraftsView/DraftsView.tsx index f7da3fbf..1aed1a8e 100644 --- a/src/components/Views/DraftsView/DraftsView.tsx +++ b/src/components/Views/DraftsView/DraftsView.tsx @@ -1,6 +1,6 @@ import { openPage } from '@nanostores/router' import { clsx } from 'clsx' -import { createSignal, For, onMount, Show } from 'solid-js' +import { createSignal, createEffect, For, Show } from 'solid-js' import { useEditorContext } from '../../../context/editor' import { useSession } from '../../../context/session' @@ -13,28 +13,26 @@ import styles from './DraftsView.module.scss' export const DraftsView = () => { const { isAuthenticated, isSessionLoaded } = useSession() - const [drafts, setDrafts] = createSignal([]) const loadDrafts = async () => { - const loadedDrafts = await apiClient.getDrafts() - if (loadedDrafts) setDrafts(loadedDrafts.reverse()) - else setDrafts([]) + if (apiClient.private) { + const loadedDrafts = await apiClient.getDrafts() + setDrafts(loadedDrafts || []) + } } - onMount(() => { - loadDrafts() + createEffect(async () => { + if (isSessionLoaded()) await loadDrafts() }) const { actions: { publishShoutById, deleteShout }, } = useEditorContext() - const handleDraftDelete = (shout: Shout) => { + const handleDraftDelete = async (shout: Shout) => { const result = deleteShout(shout.id) - if (result) { - loadDrafts() - } + if (result) await loadDrafts() } const handleDraftPublish = (shout: Shout) => { From 83cb23d424f17833d7683536e2c77e06e6fc8fed Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 17:41:49 +0300 Subject: [PATCH 35/88] revert-upvote --- src/components/Article/ShoutRatingControl.tsx | 36 ++++++++++++------- src/context/reactions.tsx | 6 ++-- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/components/Article/ShoutRatingControl.tsx b/src/components/Article/ShoutRatingControl.tsx index e309ac6d..c65d02e4 100644 --- a/src/components/Article/ShoutRatingControl.tsx +++ b/src/components/Article/ShoutRatingControl.tsx @@ -26,43 +26,53 @@ export const ShoutRatingControl = (props: ShoutRatingControlProps) => { const { reactionEntities, - actions: { createReaction, loadReactionsBy }, + actions: { createReaction, deleteReaction, loadReactionsBy }, } = useReactions() + const [isLoading, setIsLoading] = createSignal(false) + const checkReaction = (reactionKind: ReactionKind) => Object.values(reactionEntities).some( (r) => r.kind === reactionKind && - r.created_by.slug === author()?.slug && + r.created_by.id === author()?.id && r.shout.id === props.shout.id && !r.reply_to, ) const isUpvoted = createMemo(() => checkReaction(ReactionKind.Like)) - const isDownvoted = createMemo(() => checkReaction(ReactionKind.Dislike)) const shoutRatingReactions = createMemo(() => Object.values(reactionEntities).filter( - (r) => - [ReactionKind.Like, ReactionKind.Dislike].includes(r.kind) && - r.shout.id === props.shout.id && - !r.reply_to, + (r) => ['LIKE', 'DISLIKE'].includes(r.kind) && r.shout.id === props.shout.id && !r.reply_to, ), ) - const [isLoading, setIsLoading] = createSignal(false) + + const deleteShoutReaction = async (reactionKind: ReactionKind) => { + const reactionToDelete = Object.values(reactionEntities).find( + (r) => + r.kind === reactionKind && + r.created_by.id === author()?.id && + r.shout.id === props.shout.id && + !r.reply_to, + ) + return deleteReaction(reactionToDelete.id) + } + const handleRatingChange = async (isUpvote: boolean) => { - setIsLoading(true) requireAuthentication(async () => { - try { + if (isUpvoted()) { + await deleteShoutReaction(ReactionKind.Like) + } else if (isDownvoted()) { + await deleteShoutReaction(ReactionKind.Dislike) + } else { await createReaction({ kind: isUpvote ? ReactionKind.Like : ReactionKind.Dislike, shout: props.shout.id, }) - } catch (error) { - console.warn(error) } - setIsLoading(false) + loadShout(props.shout.slug) loadReactionsBy({ by: { shout: props.shout.slug }, diff --git a/src/context/reactions.tsx b/src/context/reactions.tsx index 8588e413..226c408f 100644 --- a/src/context/reactions.tsx +++ b/src/context/reactions.tsx @@ -78,10 +78,10 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => { setReactionEntities(changes) } - const deleteReaction = async (id: number): Promise => { - const reaction = await apiClient.destroyReaction(id) + const deleteReaction = async (reaction_id: number): Promise => { + const _reaction = await apiClient.destroyReaction(reaction_id) setReactionEntities({ - [reaction.id]: undefined, + [reaction_id]: undefined, }) } From cc04e13be4c342f497f233c14ea1ae86c2d8da8e Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 17:43:26 +0300 Subject: [PATCH 36/88] upvote-disabling --- src/components/Article/ShoutRatingControl.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/Article/ShoutRatingControl.tsx b/src/components/Article/ShoutRatingControl.tsx index c65d02e4..7fcb2c19 100644 --- a/src/components/Article/ShoutRatingControl.tsx +++ b/src/components/Article/ShoutRatingControl.tsx @@ -62,6 +62,7 @@ export const ShoutRatingControl = (props: ShoutRatingControlProps) => { const handleRatingChange = async (isUpvote: boolean) => { requireAuthentication(async () => { + setIsLoading(true) if (isUpvoted()) { await deleteShoutReaction(ReactionKind.Like) } else if (isDownvoted()) { @@ -77,6 +78,8 @@ export const ShoutRatingControl = (props: ShoutRatingControlProps) => { loadReactionsBy({ by: { shout: props.shout.slug }, }) + + setIsLoading(false) }, 'vote') } From 2efb97a7e9cfbc1a11f5a9b3db56893248243622 Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 18:04:12 +0300 Subject: [PATCH 37/88] zoom-url-fix --- src/utils/getImageUrl.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/utils/getImageUrl.ts b/src/utils/getImageUrl.ts index c276027d..058e8ac5 100644 --- a/src/utils/getImageUrl.ts +++ b/src/utils/getImageUrl.ts @@ -18,7 +18,12 @@ export const getImageUrl = ( const isAudio = src.toLowerCase().split('.')[-1] in ['wav', 'mp3', 'ogg', 'aif', 'flac'] const base = isAudio ? cdnUrl : thumborUrl const sizeUrlPart = isAudio ? '' : getSizeUrlPart(options) - let modifiedSrc = src.replaceAll(thumborUrl + '/', '').replaceAll(cdnUrl + '/', '') // Используйте новую переменную вместо переназначения параметра + + // Используйте новую переменную вместо переназначения параметра + let modifiedSrc = src + .replaceAll(thumborUrl + '/', '') + .replaceAll(cdnUrl + '/', '') + .replaceAll('/unsafe', '') if (options.noSizeUrlPart) { modifiedSrc = modifiedSrc.replace(/\d+x.*?\//, '') From 7054dfa0fc388f92133056e230f3deff4b345c46 Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 18:10:45 +0300 Subject: [PATCH 38/88] zoom-url-fix-2 --- src/utils/getImageUrl.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/getImageUrl.ts b/src/utils/getImageUrl.ts index 058e8ac5..e2d17ada 100644 --- a/src/utils/getImageUrl.ts +++ b/src/utils/getImageUrl.ts @@ -16,14 +16,14 @@ export const getImageUrl = ( options: { width?: number; height?: number; noSizeUrlPart?: boolean } = {}, ) => { const isAudio = src.toLowerCase().split('.')[-1] in ['wav', 'mp3', 'ogg', 'aif', 'flac'] - const base = isAudio ? cdnUrl : thumborUrl + const base = (isAudio ? cdnUrl : thumborUrl).replaceAll('unsafe/', '') const sizeUrlPart = isAudio ? '' : getSizeUrlPart(options) // Используйте новую переменную вместо переназначения параметра let modifiedSrc = src .replaceAll(thumborUrl + '/', '') .replaceAll(cdnUrl + '/', '') - .replaceAll('/unsafe', '') + .replaceAll('unsafe/', '') if (options.noSizeUrlPart) { modifiedSrc = modifiedSrc.replace(/\d+x.*?\//, '') From 504d3faefca7342c880e8be77faa6d7db9759e4d Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 18:21:37 +0300 Subject: [PATCH 39/88] zoom-url-fix-3 --- src/utils/getImageUrl.ts | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/utils/getImageUrl.ts b/src/utils/getImageUrl.ts index e2d17ada..23367c47 100644 --- a/src/utils/getImageUrl.ts +++ b/src/utils/getImageUrl.ts @@ -1,10 +1,10 @@ import { thumborUrl, cdnUrl } from './config' -const getSizeUrlPart = (options: { width?: number; height?: number } = {}) => { +const getSizeUrlPart = (options: { width?: number; height?: number; noSizeUrlPart?: boolean } = {}) => { const widthString = options.width ? options.width.toString() : '' const heightString = options.height ? options.height.toString() : '' - if (!widthString && !heightString) { + if ((!widthString && !heightString) || options.noSizeUrlPart) { return '' } @@ -15,21 +15,12 @@ export const getImageUrl = ( src: string, options: { width?: number; height?: number; noSizeUrlPart?: boolean } = {}, ) => { + const filename = src.split('/')[-1] const isAudio = src.toLowerCase().split('.')[-1] in ['wav', 'mp3', 'ogg', 'aif', 'flac'] - const base = (isAudio ? cdnUrl : thumborUrl).replaceAll('unsafe/', '') + const base = isAudio ? cdnUrl : `${thumborUrl}/unsafe/` const sizeUrlPart = isAudio ? '' : getSizeUrlPart(options) - // Используйте новую переменную вместо переназначения параметра - let modifiedSrc = src - .replaceAll(thumborUrl + '/', '') - .replaceAll(cdnUrl + '/', '') - .replaceAll('unsafe/', '') - - if (options.noSizeUrlPart) { - modifiedSrc = modifiedSrc.replace(/\d+x.*?\//, '') - } - - return `${base}/unsafe/${sizeUrlPart}${modifiedSrc}` + return `${base}${sizeUrlPart}production/${isAudio ? 'audio' : 'image'}/${filename}` } export const getOpenGraphImageUrl = ( From 2db840bba5b8eebdfe91a110794ca267917f891f Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 18:27:04 +0300 Subject: [PATCH 40/88] get-image-url-debug --- src/utils/getImageUrl.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/utils/getImageUrl.ts b/src/utils/getImageUrl.ts index 23367c47..657f45bd 100644 --- a/src/utils/getImageUrl.ts +++ b/src/utils/getImageUrl.ts @@ -15,12 +15,16 @@ export const getImageUrl = ( src: string, options: { width?: number; height?: number; noSizeUrlPart?: boolean } = {}, ) => { + console.debug(src) const filename = src.split('/')[-1] const isAudio = src.toLowerCase().split('.')[-1] in ['wav', 'mp3', 'ogg', 'aif', 'flac'] const base = isAudio ? cdnUrl : `${thumborUrl}/unsafe/` const sizeUrlPart = isAudio ? '' : getSizeUrlPart(options) - return `${base}${sizeUrlPart}production/${isAudio ? 'audio' : 'image'}/${filename}` + const res = `${base}${sizeUrlPart}production/${isAudio ? 'audio' : 'image'}/${filename}` + console.debug(res) + + return res } export const getOpenGraphImageUrl = ( From 90e02675bab436b575138bd07534fe15b401c562 Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 18:31:59 +0300 Subject: [PATCH 41/88] get-image-url-fixed --- src/utils/getImageUrl.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/getImageUrl.ts b/src/utils/getImageUrl.ts index 657f45bd..319f7fa8 100644 --- a/src/utils/getImageUrl.ts +++ b/src/utils/getImageUrl.ts @@ -15,14 +15,14 @@ export const getImageUrl = ( src: string, options: { width?: number; height?: number; noSizeUrlPart?: boolean } = {}, ) => { - console.debug(src) - const filename = src.split('/')[-1] - const isAudio = src.toLowerCase().split('.')[-1] in ['wav', 'mp3', 'ogg', 'aif', 'flac'] + //console.debug(src) + const filename = src.split('/').pop() + const isAudio = src.toLowerCase().split('.').pop() in ['wav', 'mp3', 'ogg', 'aif', 'flac'] const base = isAudio ? cdnUrl : `${thumborUrl}/unsafe/` const sizeUrlPart = isAudio ? '' : getSizeUrlPart(options) const res = `${base}${sizeUrlPart}production/${isAudio ? 'audio' : 'image'}/${filename}` - console.debug(res) + //console.debug(res) return res } From e88363e450866944fef6fa7e105e774d8fb7b836 Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 18:43:18 +0300 Subject: [PATCH 42/88] sonar-suppress --- src/utils/getImageUrl.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/utils/getImageUrl.ts b/src/utils/getImageUrl.ts index 319f7fa8..ef59e6d8 100644 --- a/src/utils/getImageUrl.ts +++ b/src/utils/getImageUrl.ts @@ -15,16 +15,12 @@ export const getImageUrl = ( src: string, options: { width?: number; height?: number; noSizeUrlPart?: boolean } = {}, ) => { - //console.debug(src) const filename = src.split('/').pop() const isAudio = src.toLowerCase().split('.').pop() in ['wav', 'mp3', 'ogg', 'aif', 'flac'] const base = isAudio ? cdnUrl : `${thumborUrl}/unsafe/` const sizeUrlPart = isAudio ? '' : getSizeUrlPart(options) - const res = `${base}${sizeUrlPart}production/${isAudio ? 'audio' : 'image'}/${filename}` - //console.debug(res) - - return res + return `${base}${sizeUrlPart}production/${isAudio ? 'audio' : 'image'}/${filename}` } export const getOpenGraphImageUrl = ( From fdc721ebd0499937a87027f011fca20164176bac Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 19:32:57 +0300 Subject: [PATCH 43/88] linted --- .eslintignore | 3 +- .eslintrc.cjs | 150 +++++++++--------- .stylelintrc | 2 + src/components/Article/FullArticle.tsx | 4 +- src/components/AuthGuard/AuthGuard.tsx | 6 +- src/components/Discours/Donate.tsx | 4 +- src/components/Editor/extensions/Iframe.ts | 2 +- .../Editor/extensions/ToggleTextWrap.ts | 2 +- .../FeedArticlePopup/FeedArticlePopup.tsx | 2 +- .../Feed/Sidebar/Sidebar.module.scss | 4 - .../Nav/AuthModal/SocialProviders.module.scss | 2 + .../Nav/SearchModal/SearchModal.module.scss | 6 +- .../_shared/Lightbox/Lightbox.module.scss | 2 - .../_shared/SolidSwiper/Swiper.module.scss | 5 +- src/components/_shared/TimeAgo/TimeAgo.tsx | 2 +- src/context/connect.tsx | 3 +- src/context/reactions.tsx | 15 +- src/context/session.tsx | 2 +- src/renderer/types.ts | 3 +- src/styles/app.scss | 2 + src/utils/pageLoadManager.ts | 4 +- 21 files changed, 113 insertions(+), 112 deletions(-) diff --git a/.eslintignore b/.eslintignore index 338ea90a..9261a192 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,6 +1,7 @@ node_modules public *.cjs -src/graphql/schema/*.gen.ts dist/ .vercel/ +src/graphql/client/* +src/graphql/schema/* diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 7dfc69c2..1d64686f 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,106 +1,108 @@ module.exports = { - plugins: ["@typescript-eslint", "import", "sonarjs", "unicorn", "promise", "solid", "jest"], + plugins: ['@typescript-eslint', 'import', 'sonarjs', 'unicorn', 'promise', 'solid', 'jest'], extends: [ - "eslint:recommended", - "plugin:import/recommended", - "plugin:import/typescript", - "prettier", - "plugin:sonarjs/recommended", - "plugin:unicorn/recommended", - "plugin:promise/recommended", - "plugin:solid/recommended", - "plugin:jest/recommended" + 'eslint:recommended', + 'plugin:import/recommended', + 'plugin:import/typescript', + 'prettier', + 'plugin:sonarjs/recommended', + 'plugin:unicorn/recommended', + 'plugin:promise/recommended', + 'plugin:solid/recommended', + 'plugin:jest/recommended', ], overrides: [ { - files: ["**/*.ts", "**/*.tsx"], - parser: "@typescript-eslint/parser", + files: ['**/*.ts', '**/*.tsx'], + parser: '@typescript-eslint/parser', parserOptions: { ecmaVersion: 2021, ecmaFeatures: { jsx: true }, - sourceType: "module", - project: "./tsconfig.json" + sourceType: 'module', + project: './tsconfig.json', }, extends: [ - "plugin:@typescript-eslint/recommended" - // Maybe one day... - // 'plugin:@typescript-eslint/recommended-requiring-type-checking' + 'plugin:@typescript-eslint/recommended', + // 'plugin:@typescript-eslint/recommended-requiring-type-checking', // 23-01-2024 896 problems ], rules: { - "@typescript-eslint/no-unused-vars": [ - "warn", + '@typescript-eslint/no-unused-vars': [ + 'warn', { - argsIgnorePattern: "^_" - } + argsIgnorePattern: '^_', + }, ], - "@typescript-eslint/no-non-null-assertion": "error", - // TODO: Remove any usage and enable - "@typescript-eslint/no-explicit-any": "off" - } - } + '@typescript-eslint/no-non-null-assertion': 'error', + '@typescript-eslint/no-explicit-any': 'warn', + }, + }, ], env: { browser: true, node: true, - mocha: true + mocha: true, }, globals: {}, rules: { // Solid - "solid/reactivity": "off", // FIXME - "solid/no-innerhtml": "off", + 'solid/reactivity': 'off', // too many 'should be used within JSX' + 'solid/no-innerhtml': 'off', /** Unicorn **/ - "unicorn/no-null": "off", - "unicorn/filename-case": "off", - "unicorn/no-array-for-each": "off", - "unicorn/no-array-reduce": "off", - "unicorn/prefer-string-replace-all": "warn", - "unicorn/prevent-abbreviations": "off", - "unicorn/prefer-module": "off", - "unicorn/import-style": "off", - "unicorn/numeric-separators-style": "off", - "unicorn/prefer-node-protocol": "off", - "unicorn/prefer-dom-node-append": "off", // FIXME - "unicorn/prefer-top-level-await": "warn", - "unicorn/consistent-function-scoping": "warn", - "unicorn/no-array-callback-reference": "warn", - "unicorn/no-array-method-this-argument": "warn", - "unicorn/no-for-loop": "off", + 'unicorn/no-null': 'off', + 'unicorn/filename-case': 'off', + 'unicorn/no-array-for-each': 'off', + 'unicorn/no-array-reduce': 'off', + 'unicorn/prefer-string-replace-all': 'warn', + 'unicorn/prevent-abbreviations': 'off', + 'unicorn/prefer-module': 'off', + 'unicorn/import-style': 'off', + 'unicorn/numeric-separators-style': 'off', + 'unicorn/prefer-node-protocol': 'off', + 'unicorn/prefer-dom-node-append': 'off', // FIXME + 'unicorn/prefer-top-level-await': 'warn', + 'unicorn/consistent-function-scoping': 'warn', + 'unicorn/no-array-callback-reference': 'warn', + 'unicorn/no-array-method-this-argument': 'warn', + 'unicorn/no-for-loop': 'off', - "sonarjs/no-duplicate-string": ["warn", { threshold: 5 }], + 'sonarjs/no-duplicate-string': ['warn', { threshold: 5 }], + 'sonarjs/prefer-immediate-return': 'warn', // Promise - // 'promise/catch-or-return': 'off', // Should be enabled - "promise/always-return": "off", + 'promise/catch-or-return': 'off', + 'promise/always-return': 'off', - eqeqeq: "error", - "no-param-reassign": "error", - "no-nested-ternary": "error", - "no-shadow": "error", + eqeqeq: 'error', + 'no-param-reassign': 'error', + 'no-nested-ternary': 'error', + 'no-shadow': 'error', - "import/order": ["warn", { - groups: ["type", "builtin", "external", "internal", "parent", "sibling", "index"], - distinctGroup: false, - pathGroups: [ - { - pattern: "*.scss", - patternOptions: { matchBase: true }, - group: "index", - position: "after" - } - ], - "newlines-between": "always", - alphabetize: { - order: "asc", - caseInsensitive: true - } - }] + 'import/order': [ + 'warn', + { + groups: ['type', 'builtin', 'external', 'internal', 'parent', 'sibling', 'index'], + distinctGroup: false, + pathGroups: [ + { + pattern: '*.scss', + patternOptions: { matchBase: true }, + group: 'index', + position: 'after', + }, + ], + 'newlines-between': 'always', + alphabetize: { + order: 'asc', + caseInsensitive: true, + }, + }, + ], }, settings: { - "import/resolver": { + 'import/resolver': { typescript: true, - node: true - } - } -}; + node: true, + }, + }, +} diff --git a/.stylelintrc b/.stylelintrc index 6630d052..5923b87b 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -7,6 +7,8 @@ "stylelint-scss" ], "rules": { + "keyframes-name-pattern": null, + "declaration-block-no-redundant-longhand-properties": null, "selector-class-pattern": null, "no-descending-specificity": null, "scss/function-no-unknown": null, diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx index d956b58b..3d16c043 100644 --- a/src/components/Article/FullArticle.tsx +++ b/src/components/Article/FullArticle.tsx @@ -300,8 +300,8 @@ export const FullArticle = (props: Props) => { const originalWidth = iframe.getAttribute('width') || style.width.replace('px', '') const originalHeight = iframe.getAttribute('height') || style.height.replace('px', '') - const width = Number(originalWidth) - const height = Number(originalHeight) + const width: IframeSize['width'] = Number(originalWidth) + const height: IframeSize['height'] = Number(originalHeight) if (containerWidth < width) { const aspectRatio = width / height diff --git a/src/components/AuthGuard/AuthGuard.tsx b/src/components/AuthGuard/AuthGuard.tsx index 5cfa404f..a7ef1ff8 100644 --- a/src/components/AuthGuard/AuthGuard.tsx +++ b/src/components/AuthGuard/AuthGuard.tsx @@ -12,11 +12,7 @@ type Props = { } export const AuthGuard = (props: Props) => { - const { - isAuthenticated, - isSessionLoaded, - actions: { loadSession }, - } = useSession() + const { isAuthenticated, isSessionLoaded } = useSession() const { changeSearchParams } = useRouter() createEffect(async () => { diff --git a/src/components/Discours/Donate.tsx b/src/components/Discours/Donate.tsx index 0264fce7..6f5ea453 100644 --- a/src/components/Discours/Donate.tsx +++ b/src/components/Discours/Donate.tsx @@ -30,9 +30,7 @@ export const Donate = () => { const initiated = () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any - const { - cp: { CloudPayments }, - } = window as any // Checkout(cpOptions) + const CloudPayments = window['cp'] // Checkout(cpOptions) setWidget(new CloudPayments()) console.log('[donate] payments initiated') setCustomerReciept({ diff --git a/src/components/Editor/extensions/Iframe.ts b/src/components/Editor/extensions/Iframe.ts index 95cd0bd7..3c73371d 100644 --- a/src/components/Editor/extensions/Iframe.ts +++ b/src/components/Editor/extensions/Iframe.ts @@ -3,7 +3,7 @@ import { Node } from '@tiptap/core' export interface IframeOptions { allowFullscreen: boolean HTMLAttributes: { - [key: string]: any + [key: string]: string | number } } diff --git a/src/components/Editor/extensions/ToggleTextWrap.ts b/src/components/Editor/extensions/ToggleTextWrap.ts index 574f9321..5c8dc0f0 100644 --- a/src/components/Editor/extensions/ToggleTextWrap.ts +++ b/src/components/Editor/extensions/ToggleTextWrap.ts @@ -16,7 +16,7 @@ export const ToggleTextWrap = Extension.create({ return { addTextWrap: (attributes) => - ({ commands, state }) => { + ({ commands, state: _s }) => { return commands.setMark('span', attributes) }, diff --git a/src/components/Feed/FeedArticlePopup/FeedArticlePopup.tsx b/src/components/Feed/FeedArticlePopup/FeedArticlePopup.tsx index 6fb66509..98e8822f 100644 --- a/src/components/Feed/FeedArticlePopup/FeedArticlePopup.tsx +++ b/src/components/Feed/FeedArticlePopup/FeedArticlePopup.tsx @@ -1,7 +1,7 @@ import type { PopupProps } from '../../_shared/Popup' import { clsx } from 'clsx' -import { createEffect, createSignal, onMount, Show } from 'solid-js' +import { createSignal, Show } from 'solid-js' import { useLocalize } from '../../../context/localize' import { Popup } from '../../_shared/Popup' diff --git a/src/components/Feed/Sidebar/Sidebar.module.scss b/src/components/Feed/Sidebar/Sidebar.module.scss index 4459a7eb..e6675249 100644 --- a/src/components/Feed/Sidebar/Sidebar.module.scss +++ b/src/components/Feed/Sidebar/Sidebar.module.scss @@ -33,10 +33,6 @@ margin-right: 1.2rem; } - .userpic { - margin-right: 1.2rem; - } - .selected { font-weight: 700; } diff --git a/src/components/Nav/AuthModal/SocialProviders.module.scss b/src/components/Nav/AuthModal/SocialProviders.module.scss index 26605606..04ffa279 100644 --- a/src/components/Nav/AuthModal/SocialProviders.module.scss +++ b/src/components/Nav/AuthModal/SocialProviders.module.scss @@ -38,12 +38,14 @@ a { border: none !important; } + .facebook, .google, .vk, .telegram { border: none; } + .github:hover { img { filter: invert(1); diff --git a/src/components/Nav/SearchModal/SearchModal.module.scss b/src/components/Nav/SearchModal/SearchModal.module.scss index 8fb9acc5..0f996e24 100644 --- a/src/components/Nav/SearchModal/SearchModal.module.scss +++ b/src/components/Nav/SearchModal/SearchModal.module.scss @@ -1,4 +1,4 @@ -@mixin searchFilterControl { +@mixin search-filter-control { background: rgb(64 64 64 / 50%); border-radius: 10rem; color: #fff; @@ -69,7 +69,7 @@ } .topTopic { - @include searchFilterControl; + @include search-filter-control; } .filterSwitcher { @@ -99,5 +99,5 @@ } .filterResultsControl { - @include searchFilterControl; + @include search-filter-control; } diff --git a/src/components/_shared/Lightbox/Lightbox.module.scss b/src/components/_shared/Lightbox/Lightbox.module.scss index fe78452e..cf1ab04f 100644 --- a/src/components/_shared/Lightbox/Lightbox.module.scss +++ b/src/components/_shared/Lightbox/Lightbox.module.scss @@ -93,12 +93,10 @@ align-items: center; justify-content: center; z-index: 10001; - font-size: 1.2rem; border-radius: 6px; background-color: rgb(0 0 0 / 80%); color: #fff; - pointer-events: none; } diff --git a/src/components/_shared/SolidSwiper/Swiper.module.scss b/src/components/_shared/SolidSwiper/Swiper.module.scss index 3e9cdf82..b8e5b990 100644 --- a/src/components/_shared/SolidSwiper/Swiper.module.scss +++ b/src/components/_shared/SolidSwiper/Swiper.module.scss @@ -52,7 +52,7 @@ } .thumbs { - //overflow: hidden; + // overflow: hidden; box-sizing: border-box; margin: 0; position: relative; @@ -87,6 +87,7 @@ &.mobileView { .container { padding: 0; + .thumbs { & swiper-slide { // bind to html element @@ -228,7 +229,7 @@ margin-top: 24px; * { - color: var(--default-color-invert) !important; //Force fix migration errors with inline styles + color: var(--default-color-invert) !important; // Force fix migration errors with inline styles } @include media-breakpoint-up(md) { diff --git a/src/components/_shared/TimeAgo/TimeAgo.tsx b/src/components/_shared/TimeAgo/TimeAgo.tsx index 20177335..055b8e39 100644 --- a/src/components/_shared/TimeAgo/TimeAgo.tsx +++ b/src/components/_shared/TimeAgo/TimeAgo.tsx @@ -6,7 +6,7 @@ import { useLocalize } from '../../../context/localize' import styles from './TimeAgo.module.scss' type Props = { - date: any + date: string | number | Date class?: string } diff --git a/src/context/connect.tsx b/src/context/connect.tsx index 5999cd9d..fea126d5 100644 --- a/src/context/connect.tsx +++ b/src/context/connect.tsx @@ -11,7 +11,8 @@ export interface SSEMessage { id: string entity: string // follower | shout | reaction action: string // create | delete | update | join | follow | seen - payload: any // Author | Shout | Reaction | Message + // eslint-disable-next-line @typescript-eslint/no-explicit-any + payload: any // Author Shout Message Reaction Chat created_at?: number // unixtime x1000 seen?: boolean } diff --git a/src/context/reactions.tsx b/src/context/reactions.tsx index 226c408f..5011fd9a 100644 --- a/src/context/reactions.tsx +++ b/src/context/reactions.tsx @@ -43,10 +43,13 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => { offset?: number }): Promise => { const reactions = await apiClient.getReactionsBy({ by, limit, offset }) - const newReactionEntities = reactions.reduce((acc, reaction) => { - acc[reaction.id] = reaction - return acc - }, {}) + const newReactionEntities = reactions.reduce( + (acc: { [reaction_id: number]: Reaction }, reaction: Reaction) => { + acc[reaction.id] = reaction + return acc + }, + {}, + ) setReactionEntities(newReactionEntities) return reactions } @@ -79,9 +82,9 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => { } const deleteReaction = async (reaction_id: number): Promise => { - const _reaction = await apiClient.destroyReaction(reaction_id) + const r = await apiClient.destroyReaction(reaction_id) setReactionEntities({ - [reaction_id]: undefined, + [r.id]: undefined, }) } diff --git a/src/context/session.tsx b/src/context/session.tsx index 490b09ab..0b872ab4 100644 --- a/src/context/session.tsx +++ b/src/context/session.tsx @@ -83,7 +83,7 @@ const EMPTY_SUBSCRIPTIONS = { } export const SessionProvider = (props: { - onStateChangeCallback(state: any): unknown + onStateChangeCallback(state: AuthToken): unknown children: JSX.Element }) => { const { t } = useLocalize() diff --git a/src/renderer/types.ts b/src/renderer/types.ts index 7f97c7ca..4948f2a7 100644 --- a/src/renderer/types.ts +++ b/src/renderer/types.ts @@ -7,8 +7,7 @@ export type PageContext = PageContextBuiltInClientWithClientRouting & { Page: (pageProps: PageProps) => Component pageProps: PageProps lng: string - // FIXME typing - cookies: any + cookies: { [key: string]: string | number | undefined } | null documentProps?: { title?: string description?: string diff --git a/src/styles/app.scss b/src/styles/app.scss index 0977d95a..f3fae241 100644 --- a/src/styles/app.scss +++ b/src/styles/app.scss @@ -595,7 +595,9 @@ figure { figure { figcaption { color: rgb(0 0 0 / 60%); + @include font-size(1.2rem); + line-height: 1.5; } } diff --git a/src/utils/pageLoadManager.ts b/src/utils/pageLoadManager.ts index a25ff347..2f8a1798 100644 --- a/src/utils/pageLoadManager.ts +++ b/src/utils/pageLoadManager.ts @@ -1,10 +1,10 @@ const pageLoadManager: { - promise: Promise + promise: Promise } = { promise: Promise.resolve() } export const getPageLoadManagerPromise = () => { return pageLoadManager.promise } -export const setPageLoadManagerPromise = (promise: Promise) => { +export const setPageLoadManagerPromise = (promise: Promise) => { pageLoadManager.promise = promise } From dc94c5bd8b2c16799d7115bc5869e52c241b2bf5 Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 19:44:58 +0300 Subject: [PATCH 44/88] linter-tuned --- .eslintrc.cjs | 4 ++-- src/components/Article/FullArticle.tsx | 4 ++-- src/components/Discours/Donate.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 1d64686f..0007cc26 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -23,7 +23,7 @@ module.exports = { }, extends: [ 'plugin:@typescript-eslint/recommended', - // 'plugin:@typescript-eslint/recommended-requiring-type-checking', // 23-01-2024 896 problems + // 'plugin:@typescript-eslint/recommended-requiring-type-checking', // 23-01-2024 681 problems ], rules: { '@typescript-eslint/no-unused-vars': [ @@ -59,7 +59,7 @@ module.exports = { 'unicorn/import-style': 'off', 'unicorn/numeric-separators-style': 'off', 'unicorn/prefer-node-protocol': 'off', - 'unicorn/prefer-dom-node-append': 'off', // FIXME + 'unicorn/prefer-dom-node-append': 'warn', 'unicorn/prefer-top-level-await': 'warn', 'unicorn/consistent-function-scoping': 'warn', 'unicorn/no-array-callback-reference': 'warn', diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx index 3d16c043..8042c5c7 100644 --- a/src/components/Article/FullArticle.tsx +++ b/src/components/Article/FullArticle.tsx @@ -208,9 +208,9 @@ export const FullArticle = (props: Props) => { tooltipContent.classList.add(styles.tooltipContent) tooltipContent.innerHTML = element.dataset.originalTitle || element.dataset.value - tooltip.appendChild(tooltipContent) + tooltip.append(tooltipContent) - document.body.appendChild(tooltip) + document.body.append(tooltip) if (element.hasAttribute('href')) { element.setAttribute('href', 'javascript: void(0)') diff --git a/src/components/Discours/Donate.tsx b/src/components/Discours/Donate.tsx index 6f5ea453..2b31ada0 100644 --- a/src/components/Discours/Donate.tsx +++ b/src/components/Discours/Donate.tsx @@ -66,7 +66,7 @@ export const Donate = () => { script.src = 'https://widget.cloudpayments.ru/bundles/cloudpayments.js' script.async = true script.addEventListener('load', initiated) - document.head.appendChild(script) + document.head.append(script) }) const show = () => { From 5435811092e419da3ea065d2438fea766886616e Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Tue, 23 Jan 2024 22:01:41 +0300 Subject: [PATCH 45/88] Fix TopicSelect --- src/components/Editor/TopicSelect/TopicSelect.tsx | 2 +- .../Views/PublishSettings/PublishSettings.tsx | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/Editor/TopicSelect/TopicSelect.tsx b/src/components/Editor/TopicSelect/TopicSelect.tsx index 5930f959..8ab5034e 100644 --- a/src/components/Editor/TopicSelect/TopicSelect.tsx +++ b/src/components/Editor/TopicSelect/TopicSelect.tsx @@ -56,7 +56,7 @@ export const TopicSelect = (props: TopicSelectProps) => { return item.label } - const isMainTopic = item.id === props.mainTopic.id + const isMainTopic = item.id === props.mainTopic?.id return (
    { const { author } = useSession() const { sortedTopics } = useTopicsStore() + const [topics, setTopics] = createSignal(sortedTopics()) + createEffect(async () => { - if (sortedTopics()?.length < 33) { - await loadAllTopics() - } + await loadAllTopics() + setTopics(sortedTopics()) }) const composeDescription = () => { @@ -212,9 +214,9 @@ export const PublishSettings = (props: Props) => {

    - + 0}> setForm('mainTopic', mainTopic)} From 5e8c99332f515bbee0dce7bd8197953924549fdb Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 22:24:31 +0300 Subject: [PATCH 46/88] small-rating-fix --- src/context/reactions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context/reactions.tsx b/src/context/reactions.tsx index 5011fd9a..8717f6da 100644 --- a/src/context/reactions.tsx +++ b/src/context/reactions.tsx @@ -84,7 +84,7 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => { const deleteReaction = async (reaction_id: number): Promise => { const r = await apiClient.destroyReaction(reaction_id) setReactionEntities({ - [r.id]: undefined, + [reaction_id]: undefined, }) } From 0146a5cae2de8625dbf8d052a796cb9bfe532f0b Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 24 Jan 2024 00:31:07 +0300 Subject: [PATCH 47/88] create-effect-fix --- src/components/Views/PublishSettings/PublishSettings.tsx | 2 +- src/graphql/mutation/core/reaction-destroy.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Views/PublishSettings/PublishSettings.tsx b/src/components/Views/PublishSettings/PublishSettings.tsx index 0814362e..c8b0fe54 100644 --- a/src/components/Views/PublishSettings/PublishSettings.tsx +++ b/src/components/Views/PublishSettings/PublishSettings.tsx @@ -44,7 +44,7 @@ export const PublishSettings = (props: Props) => { const [topics, setTopics] = createSignal(sortedTopics()) createEffect(async () => { - await loadAllTopics() + if (!sortedTopics()) await loadAllTopics() setTopics(sortedTopics()) }) diff --git a/src/graphql/mutation/core/reaction-destroy.ts b/src/graphql/mutation/core/reaction-destroy.ts index ed90143d..be1b5828 100644 --- a/src/graphql/mutation/core/reaction-destroy.ts +++ b/src/graphql/mutation/core/reaction-destroy.ts @@ -1,8 +1,8 @@ import { gql } from '@urql/core' export default gql` - mutation DeleteReactionMutation($id: Int!) { - delete_reaction(id: $id) { + mutation DeleteReactionMutation($reaction_id: Int!) { + delete_reaction(reaction_id: $reaction_id) { error reaction { id From 83e3cf1d19739f54e03d6684f0a29889dedcd048 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 24 Jan 2024 14:32:36 +0300 Subject: [PATCH 48/88] topics-fix-4 --- src/components/Views/PublishSettings/PublishSettings.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/Views/PublishSettings/PublishSettings.tsx b/src/components/Views/PublishSettings/PublishSettings.tsx index c8b0fe54..0088b50b 100644 --- a/src/components/Views/PublishSettings/PublishSettings.tsx +++ b/src/components/Views/PublishSettings/PublishSettings.tsx @@ -1,6 +1,6 @@ import { redirectPage } from '@nanostores/router' import { clsx } from 'clsx' -import { createEffect, createSignal, lazy, Show } from 'solid-js' +import { createEffect, createSignal, lazy, onMount, Show } from 'solid-js' import { createStore } from 'solid-js/store' import { ShoutForm, useEditorContext } from '../../../context/editor' @@ -43,8 +43,11 @@ export const PublishSettings = (props: Props) => { const [topics, setTopics] = createSignal(sortedTopics()) - createEffect(async () => { - if (!sortedTopics()) await loadAllTopics() + onMount(async () => { + await loadAllTopics() + }) + + createEffect(() => { setTopics(sortedTopics()) }) From afed10dfd290dbea5d5b1958ae473822f4fb71cb Mon Sep 17 00:00:00 2001 From: Ilya Y <75578537+ilya-bkv@users.noreply.github.com> Date: Thu, 25 Jan 2024 12:57:57 +0300 Subject: [PATCH 49/88] Refactoring invite modal (#375) * Refactoring invite modal * Infinite Scroll in user search --- package-lock.json | 255 +++++++++--------- package.json | 1 + public/locales/en/translation.json | 2 + public/locales/ru/translation.json | 2 + src/components/Article/FullArticle.tsx | 6 +- .../AuthorBadge/AuthorBadge.module.scss | 24 +- .../Author/AuthorBadge/AuthorBadge.tsx | 24 +- src/components/Editor/Panel/Panel.tsx | 2 +- src/components/Inbox/DialogCard.tsx | 4 +- src/components/Views/Edit.tsx | 4 +- src/components/Views/Feed/Feed.tsx | 6 +- .../Views/Inbox}/Inbox.module.scss | 21 -- src/components/Views/{ => Inbox}/Inbox.tsx | 57 ++-- .../Views/PublishSettings/PublishSettings.tsx | 2 +- .../InviteCoAuthorsModal.tsx | 17 -- .../_shared/InviteCoAuthorsModal/index.ts | 1 - .../InviteMembers.module.scss} | 43 ++- .../_shared/InviteMembers/InviteMembers.tsx | 185 +++++++++++++ src/components/_shared/InviteMembers/index.ts | 1 + .../_shared/UserSearch/UserSearch.tsx | 61 ----- src/components/_shared/UserSearch/index.ts | 1 - src/graphql/client/chat.ts | 1 + src/pages/inbox.page.tsx | 2 +- src/stores/ui.ts | 6 +- src/stores/zine/authors.ts | 11 +- 25 files changed, 444 insertions(+), 295 deletions(-) rename src/{styles => components/Views/Inbox}/Inbox.module.scss (85%) rename src/components/Views/{ => Inbox}/Inbox.tsx (88%) delete mode 100644 src/components/_shared/InviteCoAuthorsModal/InviteCoAuthorsModal.tsx delete mode 100644 src/components/_shared/InviteCoAuthorsModal/index.ts rename src/components/_shared/{UserSearch/UserSearch.module.scss => InviteMembers/InviteMembers.module.scss} (53%) create mode 100644 src/components/_shared/InviteMembers/InviteMembers.tsx create mode 100644 src/components/_shared/InviteMembers/index.ts delete mode 100644 src/components/_shared/UserSearch/UserSearch.tsx delete mode 100644 src/components/_shared/UserSearch/index.ts diff --git a/package-lock.json b/package-lock.json index c6b0edb5..9bedafbf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "license": "MIT", "dependencies": { "@authorizerdev/authorizer-js": "1.2.11", + "@solid-primitives/pagination": "0.2.10", "form-data": "4.0.0", "i18next": "22.4.15", "i18next-icu": "2.3.0", @@ -2260,9 +2261,9 @@ } }, "node_modules/@graphql-codegen/cli/node_modules/@whatwg-node/node-fetch": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.3.tgz", - "integrity": "sha512-toMC8N53RxgprcuU7Fc05KOrJhZV49njJCHPZvXBsjZMQBKrDm9o14Y56CsrUC85cvjQu862MaYOjd8rKgHdDw==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.4.tgz", + "integrity": "sha512-5AXi4B44/6SOlQG+X3cO5lsUdRTWSXqaWLkGKnwWfeJoMgRfA53RnYVnvTV+4CoatNBStPrIoDorjgQv+ouiMQ==", "dev": true, "dependencies": { "@kamilkisiela/fast-url-parser": "^1.1.4", @@ -2767,9 +2768,9 @@ } }, "node_modules/@graphql-tools/apollo-engine-loader/node_modules/@whatwg-node/node-fetch": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.3.tgz", - "integrity": "sha512-toMC8N53RxgprcuU7Fc05KOrJhZV49njJCHPZvXBsjZMQBKrDm9o14Y56CsrUC85cvjQu862MaYOjd8rKgHdDw==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.4.tgz", + "integrity": "sha512-5AXi4B44/6SOlQG+X3cO5lsUdRTWSXqaWLkGKnwWfeJoMgRfA53RnYVnvTV+4CoatNBStPrIoDorjgQv+ouiMQ==", "dev": true, "dependencies": { "@kamilkisiela/fast-url-parser": "^1.1.4", @@ -2817,13 +2818,13 @@ } }, "node_modules/@graphql-tools/code-file-loader": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-8.0.3.tgz", - "integrity": "sha512-gVnnlWs0Ua+5FkuHHEriFUOI3OIbHv6DS1utxf28n6NkfGMJldC4j0xlJRY0LS6dWK34IGYgD4HelKYz2l8KiA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-8.1.0.tgz", + "integrity": "sha512-HKWW/B2z15ves8N9+xnVbGmFEVGyHEK80a4ghrjeTa6nwNZaKDVfq5CoYFfF0xpfjtH6gOVUExo2XCOEz4B8mQ==", "dev": true, "dependencies": { - "@graphql-tools/graphql-tag-pluck": "8.1.0", - "@graphql-tools/utils": "^10.0.0", + "@graphql-tools/graphql-tag-pluck": "8.2.0", + "@graphql-tools/utils": "^10.0.13", "globby": "^11.0.3", "tslib": "^2.4.0", "unixify": "^1.0.0" @@ -3012,9 +3013,9 @@ } }, "node_modules/@graphql-tools/executor-http/node_modules/@whatwg-node/node-fetch": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.3.tgz", - "integrity": "sha512-toMC8N53RxgprcuU7Fc05KOrJhZV49njJCHPZvXBsjZMQBKrDm9o14Y56CsrUC85cvjQu862MaYOjd8rKgHdDw==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.4.tgz", + "integrity": "sha512-5AXi4B44/6SOlQG+X3cO5lsUdRTWSXqaWLkGKnwWfeJoMgRfA53RnYVnvTV+4CoatNBStPrIoDorjgQv+ouiMQ==", "dev": true, "dependencies": { "@kamilkisiela/fast-url-parser": "^1.1.4", @@ -3097,13 +3098,13 @@ } }, "node_modules/@graphql-tools/git-loader": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@graphql-tools/git-loader/-/git-loader-8.0.3.tgz", - "integrity": "sha512-Iz9KbRUAkuOe8JGTS0qssyJ+D5Snle17W+z9anwWrLFrkBhHrRFUy5AdjZqgJuhls0x30QkZBnnCtnHDBdQ4nA==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@graphql-tools/git-loader/-/git-loader-8.0.4.tgz", + "integrity": "sha512-fBmKtnOVqzMT2N8L6nggM4skPq3y2t0eBITZJXCOuxeIlIRAeCOdjNLPKgyGb0rezIyGsn55DKMua5101VN0Sg==", "dev": true, "dependencies": { - "@graphql-tools/graphql-tag-pluck": "8.1.0", - "@graphql-tools/utils": "^10.0.0", + "@graphql-tools/graphql-tag-pluck": "8.2.0", + "@graphql-tools/utils": "^10.0.13", "is-glob": "4.0.3", "micromatch": "^4.0.4", "tslib": "^2.4.0", @@ -3160,9 +3161,9 @@ } }, "node_modules/@graphql-tools/github-loader/node_modules/@whatwg-node/node-fetch": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.3.tgz", - "integrity": "sha512-toMC8N53RxgprcuU7Fc05KOrJhZV49njJCHPZvXBsjZMQBKrDm9o14Y56CsrUC85cvjQu862MaYOjd8rKgHdDw==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.4.tgz", + "integrity": "sha512-5AXi4B44/6SOlQG+X3cO5lsUdRTWSXqaWLkGKnwWfeJoMgRfA53RnYVnvTV+4CoatNBStPrIoDorjgQv+ouiMQ==", "dev": true, "dependencies": { "@kamilkisiela/fast-url-parser": "^1.1.4", @@ -3201,9 +3202,9 @@ } }, "node_modules/@graphql-tools/graphql-tag-pluck": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-8.1.0.tgz", - "integrity": "sha512-kt5l6H/7QxQcIaewInTcune6NpATojdFEW98/8xWcgmy7dgXx5vU9e0AicFZIH+ewGyZzTpwFqO2RI03roxj2w==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-8.2.0.tgz", + "integrity": "sha512-aGIuHxyrJB+LlUfXrH73NVlQTA6LkFbLKQzHojFuwXZJpf7wPkxceN2yp7VjMedARkLJg589IoXgZeMb1EztGQ==", "dev": true, "dependencies": { "@babel/core": "^7.22.9", @@ -3211,7 +3212,7 @@ "@babel/plugin-syntax-import-assertions": "^7.20.0", "@babel/traverse": "^7.16.8", "@babel/types": "^7.16.8", - "@graphql-tools/utils": "^10.0.0", + "@graphql-tools/utils": "^10.0.13", "tslib": "^2.4.0" }, "engines": { @@ -3502,9 +3503,9 @@ } }, "node_modules/@graphql-tools/prisma-loader/node_modules/@whatwg-node/node-fetch": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.3.tgz", - "integrity": "sha512-toMC8N53RxgprcuU7Fc05KOrJhZV49njJCHPZvXBsjZMQBKrDm9o14Y56CsrUC85cvjQu862MaYOjd8rKgHdDw==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.4.tgz", + "integrity": "sha512-5AXi4B44/6SOlQG+X3cO5lsUdRTWSXqaWLkGKnwWfeJoMgRfA53RnYVnvTV+4CoatNBStPrIoDorjgQv+ouiMQ==", "dev": true, "dependencies": { "@kamilkisiela/fast-url-parser": "^1.1.4", @@ -3697,9 +3698,9 @@ } }, "node_modules/@graphql-tools/utils": { - "version": "10.0.12", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.0.12.tgz", - "integrity": "sha512-+yS1qlFwXlwU3Gv8ek/h2aJ95quog4yF22haC11M0zReMSTddbGJZ5yXKkE3sXoY2BcL1utilSFjylJ9uXpSNQ==", + "version": "10.0.13", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.0.13.tgz", + "integrity": "sha512-fMILwGr5Dm2zefNItjQ6C2rauigklv69LIwppccICuGTnGaOp3DspLt/6Lxj72cbg5d9z60Sr+Egco3CJKLsNg==", "dev": true, "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", @@ -4625,9 +4626,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -5016,16 +5017,16 @@ } }, "node_modules/@peculiar/webcrypto": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.3.tgz", - "integrity": "sha512-VtaY4spKTdN5LjJ04im/d/joXuvLbQdgy5Z4DXF4MFZhQ+MTrejbNMkfZBp1Bs3O5+bFqnJgyGdPuZQflvIa5A==", + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.5.tgz", + "integrity": "sha512-oDk93QCDGdxFRM8382Zdminzs44dg3M2+E5Np+JWkpqLDyJC9DviMh8F8mEJkYuUcUOGA5jHO5AJJ10MFWdbZw==", "dev": true, "dependencies": { - "@peculiar/asn1-schema": "^2.3.6", + "@peculiar/asn1-schema": "^2.3.8", "@peculiar/json-schema": "^1.1.12", - "pvtsutils": "^1.3.2", - "tslib": "^2.5.0", - "webcrypto-core": "^1.7.7" + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2", + "webcrypto-core": "^1.7.8" }, "engines": { "node": ">=10.12.0" @@ -5229,9 +5230,9 @@ "dev": true }, "node_modules/@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, "dependencies": { "type-detect": "4.0.8" @@ -5247,12 +5248,12 @@ } }, "node_modules/@solid-primitives/event-listener": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@solid-primitives/event-listener/-/event-listener-2.3.0.tgz", - "integrity": "sha512-0DS7DQZvCExWSpurVZC9/wjI8RmkhuOtWOy6Pp1Woq9ElMT9/bfjNpkwXsOwisLpcTqh9eUs17kp7jtpWcC20w==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@solid-primitives/event-listener/-/event-listener-2.3.1.tgz", + "integrity": "sha512-S1AfFYatOJ3g/ZUbGDoKplSGLTTfarQ3Mfd3F/fXb9SnzGtROtd+Y6yLkPVzK4AVw83r2wUSaS0GS6dg8izTEQ==", "dev": true, "dependencies": { - "@solid-primitives/utils": "^6.2.1" + "@solid-primitives/utils": "^6.2.2" }, "peerDependencies": { "solid-js": "^1.6.12" @@ -5286,34 +5287,45 @@ "solid-js": "^1.6.12" } }, + "node_modules/@solid-primitives/pagination": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@solid-primitives/pagination/-/pagination-0.2.10.tgz", + "integrity": "sha512-HVRW8NgNkjB2PPg4f4E4ava+PI6AO8INQpsARylzQcxeBW+RMY5bYJoSIQ2QSp+hHiJhNlYozdBdLUY39Vxtxg==", + "dependencies": { + "@solid-primitives/utils": "^6.2.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, "node_modules/@solid-primitives/refs": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@solid-primitives/refs/-/refs-1.0.5.tgz", - "integrity": "sha512-5hmYmYbm6rs43nMHHozyyUngGA7P7q2WtlaCLJEfmlUJf67GWI1PZmqAiol6m9F37XSMZRuvZLoQ7HA/0q3GYg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@solid-primitives/refs/-/refs-1.0.6.tgz", + "integrity": "sha512-ruh4YdVMxThEVnvqbpeLXKojW442vpFU8q7dSKtElGOTa31aKOAkRb9BTbdaTwVjN4BEq79fiiYIXozJNl4dSw==", "dev": true, "dependencies": { - "@solid-primitives/utils": "^6.2.1" + "@solid-primitives/utils": "^6.2.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "node_modules/@solid-primitives/rootless": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@solid-primitives/rootless/-/rootless-1.4.2.tgz", - "integrity": "sha512-ynI/2aEOPyc14IKCX6yDBqnsAYCoLbaP9V/jejEWMVKOT2ZdV2ZxdftaLimOpWPpvjyti5DUJIGTOfLaNb7jlg==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@solid-primitives/rootless/-/rootless-1.4.3.tgz", + "integrity": "sha512-IPsfUhKsqQOxLtRMQWK2EZAYbL9RKJMLBelLwpaXl9+oa1tl5aNvA6GHgrNrK+85oUhiYh7/OuogO18AuHepqQ==", "dev": true, "dependencies": { - "@solid-primitives/utils": "^6.2.1" + "@solid-primitives/utils": "^6.2.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "node_modules/@solid-primitives/scheduled": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@solid-primitives/scheduled/-/scheduled-1.4.1.tgz", - "integrity": "sha512-OLcNXwYpX7HUOEqNPcmR31dkyI1E2imkMDBRlqsGT0ZhJV1L2g0TEREpo4nm/kUhh8LVQzkfnxS+GONx9kh90A==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/scheduled/-/scheduled-1.4.2.tgz", + "integrity": "sha512-duKaugDQtPk0v6MnkBuEalWk66/vA2G7zzoimQEvmUdh2+K2o8t908HIfI2NdBfwakQMQBV4epE3TFeN2Vsveg==", "dev": true, "peerDependencies": { "solid-js": "^1.6.12" @@ -5353,9 +5365,9 @@ } }, "node_modules/@solid-primitives/transition-group": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@solid-primitives/transition-group/-/transition-group-1.0.3.tgz", - "integrity": "sha512-TnFADZhx9sibdoW5gxkU1QmLabzV2H2OBKYGS2aR5IC61Q/+7v8wlxOJEevxXNbPiRo6qlE3STLU3L9XS8hDbA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@solid-primitives/transition-group/-/transition-group-1.0.4.tgz", + "integrity": "sha512-9nPg6HYAmEi7riH0C2bSCVw/2asgGSzHuN0yFFYyK9JgmXqJgyeyA+6thZbj7GgUQMRhtBxpH8yG7N2nEh8ttA==", "dev": true, "peerDependencies": { "solid-js": "^1.6.12" @@ -5383,10 +5395,9 @@ } }, "node_modules/@solid-primitives/utils": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@solid-primitives/utils/-/utils-6.2.1.tgz", - "integrity": "sha512-TsecNzxiO5bLfzqb4OOuzfUmdOROcssuGqgh5rXMMaasoFZ3GoveUgdY1wcf17frMJM7kCNGNuK34EjErneZkg==", - "dev": true, + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/utils/-/utils-6.2.2.tgz", + "integrity": "sha512-11ypVbp987XxETeRqY5Y3OmmTpm8/jZqJXRvo6AyqBthzkvvjEdReuUMU2yVb+pwWGxfZpWHZ6EUCcGXUMhfwg==", "peerDependencies": { "solid-js": "^1.6.12" } @@ -6728,9 +6739,9 @@ } }, "node_modules/axios": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", - "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.6.tgz", + "integrity": "sha512-XZLZDFfXKM9U/Y/B4nNynfCRUqNyVZ4sBC/n9GDRCkq9vd2mIvKjKKsbIh1WPmHmNbg6ND7cTBY3Y2+u1G3/2Q==", "dependencies": { "follow-redirects": "^1.15.4", "form-data": "^4.0.0", @@ -6908,9 +6919,9 @@ } }, "node_modules/babel-plugin-jsx-dom-expressions": { - "version": "0.37.13", - "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.37.13.tgz", - "integrity": "sha512-oAEMMIgU0h1DmHn4ZDaBBFc08nsVJciLq9pF7g0ZdpeIDKfY4zXjXr8+/oBjKhXG8nyomhnTodPjeG+/ZXcWXQ==", + "version": "0.37.16", + "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.37.16.tgz", + "integrity": "sha512-ItMD16axbk+FqVb9vIbc7AOpNowy46VaSUHaMYPn+erPGpMCxsahQ1Iv+qhPMthjxtn5ROVMZ5AJtQvzjxjiNA==", "dev": true, "dependencies": { "@babel/helper-module-imports": "7.18.6", @@ -7368,9 +7379,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001576", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz", - "integrity": "sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==", + "version": "1.0.30001580", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001580.tgz", + "integrity": "sha512-mtj5ur2FFPZcCEpXFy8ADXbDACuNFXg6mxVDqp7tqooX6l3zwm+d8EPoeOSIFRDvHs8qu7/SLFOGniULkcH2iA==", "dev": true, "funding": [ { @@ -8012,8 +8023,7 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -8286,9 +8296,9 @@ } }, "node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz", + "integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==", "dev": true, "engines": { "node": ">=12" @@ -8328,9 +8338,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.628", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.628.tgz", - "integrity": "sha512-2k7t5PHvLsufpP6Zwk0nof62yLOsCf032wZx7/q0mv8gwlXjhcxI3lz6f0jBr0GrnWKcm3burXzI3t5IrcdUxw==", + "version": "1.4.645", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.645.tgz", + "integrity": "sha512-EeS1oQDCmnYsRDRy2zTeC336a/4LZ6WKqvSaM1jLocEk5ZuyszkQtCpsqvuvaIXGOUjwtvF6LTcS8WueibXvSw==", "dev": true }, "node_modules/emittery": { @@ -9773,9 +9783,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "funding": [ { "type": "individual", @@ -10372,9 +10382,9 @@ } }, "node_modules/graphql-config/node_modules/@whatwg-node/node-fetch": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.3.tgz", - "integrity": "sha512-toMC8N53RxgprcuU7Fc05KOrJhZV49njJCHPZvXBsjZMQBKrDm9o14Y56CsrUC85cvjQu862MaYOjd8rKgHdDw==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.4.tgz", + "integrity": "sha512-5AXi4B44/6SOlQG+X3cO5lsUdRTWSXqaWLkGKnwWfeJoMgRfA53RnYVnvTV+4CoatNBStPrIoDorjgQv+ouiMQ==", "dev": true, "dependencies": { "@kamilkisiela/fast-url-parser": "^1.1.4", @@ -13790,9 +13800,9 @@ "dev": true }, "node_modules/json-stable-stringify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.0.tgz", - "integrity": "sha512-zfA+5SuwYN2VWqN1/5HZaDzQKLJHaBVMZIIM+wuYjdptkaQsqzDdqjqf+lZZJUuJq1aanHiY8LhH8LmH+qBYJA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz", + "integrity": "sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==", "dev": true, "dependencies": { "call-bind": "^1.0.5", @@ -16905,9 +16915,9 @@ } }, "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", "dev": true }, "node_modules/rimraf": { @@ -16989,13 +16999,13 @@ } }, "node_modules/safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", + "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -17027,9 +17037,9 @@ ] }, "node_modules/safe-regex-test": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.1.tgz", - "integrity": "sha512-Y5NejJTTliTyY4H7sipGqY+RX5P87i3F7c4Rcepy72nq+mNLhIsD0W4c7kEmduMDQCSqtPsXPlSTsFhh2LQv+g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", + "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", "dev": true, "dependencies": { "call-bind": "^1.0.5", @@ -17113,7 +17123,6 @@ "version": "0.15.1", "resolved": "https://registry.npmjs.org/seroval/-/seroval-0.15.1.tgz", "integrity": "sha512-OPVtf0qmeC7RW+ScVX+7aOS+xoIM7pWcZ0jOWg2aTZigCydgRB04adfteBRbecZnnrO1WuGQ+C3tLeBBzX2zSQ==", - "dev": true, "engines": { "node": ">=10" } @@ -17125,15 +17134,16 @@ "dev": true }, "node_modules/set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", + "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", "dev": true, "dependencies": { "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.2", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -17305,7 +17315,6 @@ "version": "1.8.7", "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.8.7.tgz", "integrity": "sha512-9dzrSVieh2zj3SnJ02II6xZkonR6c+j/91b7XZUNcC6xSaldlqjjGh98F1fk5cRJ8ZTkzqF5fPIWDxEOs6QZXA==", - "dev": true, "dependencies": { "csstype": "^3.1.0", "seroval": "^0.15.1" @@ -17516,9 +17525,9 @@ } }, "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz", + "integrity": "sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==", "dev": true }, "node_modules/spdx-expression-parse": { @@ -19276,9 +19285,9 @@ } }, "node_modules/vue-eslint-parser": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.0.tgz", - "integrity": "sha512-7KsNBb6gHFA75BtneJsoK/dbZ281whUIwFYdQxA68QrCrGMXYzUMbPDHGcOQ0OocIVKrWSKWXZ4mL7tonCXoUw==", + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.2.tgz", + "integrity": "sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==", "dev": true, "dependencies": { "debug": "^4.3.4", @@ -19367,16 +19376,16 @@ } }, "node_modules/webcrypto-core": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.7.tgz", - "integrity": "sha512-7FjigXNsBfopEj+5DV2nhNpfic2vumtjjgPmeDKk45z+MJwXKKfhPB7118Pfzrmh4jqOMST6Ch37iPAHoImg5g==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.8.tgz", + "integrity": "sha512-eBR98r9nQXTqXt/yDRtInszPMjTaSAMJAFDg2AHsgrnczawT1asx9YNBX6k5p+MekbPF4+s/UJJrr88zsTqkSg==", "dev": true, "dependencies": { - "@peculiar/asn1-schema": "^2.3.6", + "@peculiar/asn1-schema": "^2.3.8", "@peculiar/json-schema": "^1.1.12", "asn1js": "^3.0.1", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2" } }, "node_modules/webidl-conversions": { diff --git a/package.json b/package.json index 3162d672..a117a93f 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ }, "dependencies": { "@authorizerdev/authorizer-js": "1.2.11", + "@solid-primitives/pagination": "0.2.10", "form-data": "4.0.0", "i18next": "22.4.15", "i18next-icu": "2.3.0", diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index a8bf5807..336a8237 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -203,6 +203,7 @@ "Invalid email": "Check if your email is correct", "Invalid image URL": "Invalid image URL", "Invalid url format": "Invalid url format", + "Invite": "Invite", "Invite co-authors": "Invite co-authors", "Invite collaborators": "Invite collaborators", "Invite to collab": "Invite to Collab", @@ -343,6 +344,7 @@ "Special projects": "Special projects", "Specify the source and the name of the author": "Specify the source and the name of the author", "Start conversation": "Start a conversation", + "Start dialog": "Start dialog", "Subsccriptions": "Subscriptions", "Subscribe": "Subscribe", "Subscribe to the best publications newsletter": "Subscribe to the best publications newsletter", diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index 6638d0de..a06c7c81 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -213,6 +213,7 @@ "Invalid email": "Проверьте правильность ввода почты", "Invalid image URL": "Некорректная ссылка на изображение", "Invalid url format": "Неверный формат ссылки", + "Invite": "Пригласить", "Invite co-authors": "Пригласить соавторов", "Invite collaborators": "Пригласить соавторов", "Invite experts": "Пригласить экспертов", @@ -364,6 +365,7 @@ "Special projects": "Спецпроекты", "Specify the source and the name of the author": "Укажите источник и имя автора", "Start conversation": "Начать беседу", + "Start dialog": "Начать диалог", "Subheader": "Подзаголовок", "Subscribe": "Подписаться", "Subscribe to comments": "Подписаться на комментарии", diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx index 8042c5c7..e296bbb7 100644 --- a/src/components/Article/FullArticle.tsx +++ b/src/components/Article/FullArticle.tsx @@ -19,7 +19,7 @@ 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 { InviteMembers } from '../_shared/InviteMembers' import { Lightbox } from '../_shared/Lightbox' import { Popover } from '../_shared/Popover' import { ShareModal } from '../_shared/ShareModal' @@ -555,7 +555,7 @@ export const FullArticle = (props: Props) => { isOwner={canEdit()} containerCssClass={clsx(stylesHeader.control, styles.articlePopupOpener)} onShareClick={() => showModal('share')} - onInviteClick={() => showModal('inviteCoAuthors')} + onInviteClick={() => showModal('inviteMembers')} onVisibilityChange={(isVisible) => setIsActionPopupActive(isVisible)} trigger={
    @@ -195,6 +206,13 @@ export const AuthorBadge = (props: Props) => {
    + + props.onInvite(props.author.id)} + /> +
    ) } diff --git a/src/components/Editor/Panel/Panel.tsx b/src/components/Editor/Panel/Panel.tsx index b639924c..3366f8b7 100644 --- a/src/components/Editor/Panel/Panel.tsx +++ b/src/components/Editor/Panel/Panel.tsx @@ -92,7 +92,7 @@ export const Panel = (props: Props) => {

    - showModal('inviteCoAuthors')}> + showModal('inviteMembers')}> {t('Invite co-authors')}

    diff --git a/src/components/Inbox/DialogCard.tsx b/src/components/Inbox/DialogCard.tsx index 19b5ee03..fcac47cc 100644 --- a/src/components/Inbox/DialogCard.tsx +++ b/src/components/Inbox/DialogCard.tsx @@ -33,7 +33,7 @@ const DialogCard = (props: DialogProps) => { const names = createMemo(() => (companions() || []).map((companion) => companion.name).join(', ')) return ( - + 0} fallback={
    'No chat members'
    }>
    { when={props.isChatHeader} fallback={
    - +
    } > diff --git a/src/components/Views/Edit.tsx b/src/components/Views/Edit.tsx index 4a083124..499b0a9d 100644 --- a/src/components/Views/Edit.tsx +++ b/src/components/Views/Edit.tsx @@ -14,7 +14,7 @@ import { isDesktop } from '../../utils/media-query' import { slugify } from '../../utils/slugify' import { DropArea } from '../_shared/DropArea' import { Icon } from '../_shared/Icon' -import { InviteCoAuthorsModal } from '../_shared/InviteCoAuthorsModal' +import { InviteMembers } from '../_shared/InviteMembers' import { Popover } from '../_shared/Popover' import { EditorSwiper } from '../_shared/SolidSwiper' import { Editor, Panel } from '../Editor' @@ -413,7 +413,7 @@ export const EditView = (props: Props) => { - + ) } diff --git a/src/components/Views/Feed/Feed.tsx b/src/components/Views/Feed/Feed.tsx index b3df32b7..5bd73f71 100644 --- a/src/components/Views/Feed/Feed.tsx +++ b/src/components/Views/Feed/Feed.tsx @@ -17,7 +17,7 @@ import { useTopicsStore } from '../../../stores/zine/topics' import { getImageUrl } from '../../../utils/getImageUrl' import { DropDown } from '../../_shared/DropDown' import { Icon } from '../../_shared/Icon' -import { InviteCoAuthorsModal } from '../../_shared/InviteCoAuthorsModal' +import { InviteMembers } from '../../_shared/InviteMembers' import { Loading } from '../../_shared/Loading' import { ShareModal } from '../../_shared/ShareModal' import { CommentDate } from '../../Article/CommentDate' @@ -305,7 +305,7 @@ export const FeedView = (props: Props) => { {(article) => ( handleShare(shared)} - onInvite={() => showModal('inviteCoAuthors')} + onInvite={() => showModal('inviteMembers')} article={article} settings={{ isFeedMode: true }} desktopCoverSize="M" @@ -432,7 +432,7 @@ export const FeedView = (props: Props) => { shareUrl={getShareUrl({ pathname: `/${shareData().slug}` })} /> - +
    ) } diff --git a/src/styles/Inbox.module.scss b/src/components/Views/Inbox/Inbox.module.scss similarity index 85% rename from src/styles/Inbox.module.scss rename to src/components/Views/Inbox/Inbox.module.scss index 0230879d..9e0f1737 100644 --- a/src/styles/Inbox.module.scss +++ b/src/components/Views/Inbox/Inbox.module.scss @@ -36,7 +36,6 @@ main { display: flex; flex-direction: column; padding: 10px; - height: calc(100% - 10px); $fadeHeight: 10px; @@ -52,26 +51,6 @@ main { position: relative; padding: $fadeHeight 0; - &::before, - &::after { - content: ''; - position: absolute; - width: 100%; - right: 0; - z-index: 1; - height: $fadeHeight; - } - - &::before { - top: 0; - background: linear-gradient(white, transparent $fadeHeight); - } - - &::after { - bottom: 0; - background: linear-gradient(transparent, white $fadeHeight); - } - .dialogs { scroll-behavior: smooth; display: flex; diff --git a/src/components/Views/Inbox.tsx b/src/components/Views/Inbox/Inbox.tsx similarity index 88% rename from src/components/Views/Inbox.tsx rename to src/components/Views/Inbox/Inbox.tsx index 3600d476..593df862 100644 --- a/src/components/Views/Inbox.tsx +++ b/src/components/Views/Inbox/Inbox.tsx @@ -1,27 +1,26 @@ -import type { Chat, Message as MessageType } from '../../graphql/schema/chat.gen' -import type { Author } from '../../graphql/schema/core.gen' +import type { Chat, Message as MessageType } from '../../../graphql/schema/chat.gen' +import type { Author } from '../../../graphql/schema/core.gen' import { clsx } from 'clsx' import { For, createSignal, Show, onMount, createEffect, createMemo, on } from 'solid-js' -import { useInbox } from '../../context/inbox' -import { useLocalize } from '../../context/localize' -import { useSession } from '../../context/session' -import { useRouter } from '../../stores/router' -import { showModal } from '../../stores/ui' -// import { AuthorsSortBy, useAuthorsStore } from '../../stores/zine/authors' -import { Icon } from '../_shared/Icon' -import { Popover } from '../_shared/Popover' -import SimplifiedEditor from '../Editor/SimplifiedEditor' -import CreateModalContent from '../Inbox/CreateModalContent' -import DialogCard from '../Inbox/DialogCard' -import DialogHeader from '../Inbox/DialogHeader' -import { Message } from '../Inbox/Message' -import MessagesFallback from '../Inbox/MessagesFallback' -import Search from '../Inbox/Search' -import { Modal } from '../Nav/Modal' +import { useInbox } from '../../../context/inbox' +import { useLocalize } from '../../../context/localize' +import { useSession } from '../../../context/session' +import { useRouter } from '../../../stores/router' +import { showModal } from '../../../stores/ui' +import { useAuthorsStore } from '../../../stores/zine/authors' +import { Icon } from '../../_shared/Icon' +import { InviteMembers } from '../../_shared/InviteMembers' +import { Popover } from '../../_shared/Popover' +import SimplifiedEditor from '../../Editor/SimplifiedEditor' +import DialogCard from '../../Inbox/DialogCard' +import DialogHeader from '../../Inbox/DialogHeader' +import { Message } from '../../Inbox/Message' +import MessagesFallback from '../../Inbox/MessagesFallback' +import Search from '../../Inbox/Search' -import styles from '../../styles/Inbox.module.scss' +import styles from './Inbox.module.scss' type InboxSearchParams = { by?: string @@ -34,7 +33,7 @@ const userSearch = (array: Author[], keyword: string) => { } const handleOpenInviteModal = () => { - showModal('inviteToChat') + showModal('inviteMembers') } type Props = { @@ -64,16 +63,12 @@ export const InboxView = (props: Props) => { current: null, } - // Поиск по диалогам const getQuery = (query) => { if (query().length >= 2) { const match = userSearch(recipients(), query()) setRecipients(match) - } else { - // setRecipients(cashedRecipients()) } } - const handleOpenChat = async (chat: Chat) => { setCurrentDialog(chat) changeSearchParams({ @@ -91,8 +86,6 @@ export const InboxView = (props: Props) => { } } - onMount(loadChats) - const handleSubmit = async (message: string) => { sendMessage({ body: message, @@ -129,6 +122,7 @@ export const InboxView = (props: Props) => { }) const chatsToShow = () => { + if (!chats()) return const sorted = chats().sort((a, b) => { return b.updated_at - a.updated_at }) @@ -181,11 +175,14 @@ export const InboxView = (props: Props) => { setIsScrollToNewVisible(false) } + onMount(async () => { + await loadChats() + }) + return (
    - - - + + {/**/}
    @@ -195,7 +192,7 @@ export const InboxView = (props: Props) => {
    - +
    diff --git a/src/components/_shared/InviteCoAuthorsModal/InviteCoAuthorsModal.tsx b/src/components/_shared/InviteCoAuthorsModal/InviteCoAuthorsModal.tsx deleted file mode 100644 index 859c295b..00000000 --- a/src/components/_shared/InviteCoAuthorsModal/InviteCoAuthorsModal.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { useLocalize } from '../../../context/localize' -import { Modal } from '../../Nav/Modal' -import { UserSearch } from '../UserSearch' - -type Props = { - title?: string -} -export const InviteCoAuthorsModal = (props: Props) => { - const { t } = useLocalize() - - return ( - -

    {props.title || t('Invite collaborators')}

    - {}} /> -
    - ) -} diff --git a/src/components/_shared/InviteCoAuthorsModal/index.ts b/src/components/_shared/InviteCoAuthorsModal/index.ts deleted file mode 100644 index cf10fce7..00000000 --- a/src/components/_shared/InviteCoAuthorsModal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { InviteCoAuthorsModal } from './InviteCoAuthorsModal' diff --git a/src/components/_shared/UserSearch/UserSearch.module.scss b/src/components/_shared/InviteMembers/InviteMembers.module.scss similarity index 53% rename from src/components/_shared/UserSearch/UserSearch.module.scss rename to src/components/_shared/InviteMembers/InviteMembers.module.scss index 45a6d74d..8710a65a 100644 --- a/src/components/_shared/UserSearch/UserSearch.module.scss +++ b/src/components/_shared/InviteMembers/InviteMembers.module.scss @@ -1,4 +1,4 @@ -.UserSearch { +.InviteMembers { .searchHeader { display: flex; flex-flow: row nowrap; @@ -32,10 +32,40 @@ } } + .searchButton { + margin: 0; + } + .authors { - height: 400px; + height: 300px; overflow: auto; - padding: 1rem 0; + margin-top: 1rem; + + .author { + cursor: pointer; + + &:hover { + background: var(--black-100); + } + } + } + + .loading { + @include font-size(1.4rem); + + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; + width: 100%; + flex-direction: row; + opacity: 0.5; + + .icon { + position: relative; + width: 18px; + height: 18px; + } } .teaser { @@ -46,4 +76,11 @@ justify-content: center; text-align: center; } + + .actions { + display: flex; + margin-top: 1rem; + flex-direction: row; + justify-content: space-between; + } } diff --git a/src/components/_shared/InviteMembers/InviteMembers.tsx b/src/components/_shared/InviteMembers/InviteMembers.tsx new file mode 100644 index 00000000..408ffbdd --- /dev/null +++ b/src/components/_shared/InviteMembers/InviteMembers.tsx @@ -0,0 +1,185 @@ +import { createInfiniteScroll } from '@solid-primitives/pagination' +import { clsx } from 'clsx' +import { createEffect, createSignal, For, on, Show } from 'solid-js' + +import { useInbox } from '../../../context/inbox' +import { useLocalize } from '../../../context/localize' +import { Author } from '../../../graphql/schema/core.gen' +import { hideModal } from '../../../stores/ui' +import { useAuthorsStore } from '../../../stores/zine/authors' +import { AuthorBadge } from '../../Author/AuthorBadge' +import { Modal } from '../../Nav/Modal' +import { Button } from '../Button' +import { DropdownSelect } from '../DropdownSelect' +import { Loading } from '../Loading' + +import styles from './InviteMembers.module.scss' + +type InviteAuthor = Author & { selected: boolean } + +type Props = { + title?: string + variant?: 'coauthors' | 'recipients' +} + +const PAGE_SIZE = 50 +export const InviteMembers = (props: Props) => { + const { t } = useLocalize() + const roles = [ + { + title: t('Editor'), + description: t('Can write and edit text directly, and accept or reject suggestions from others'), + }, + { + title: t('Co-author'), + description: t('Can make any changes, accept or reject suggestions, and share access with others'), + }, + { + title: t('Commentator'), + description: t('Can offer edits and comments, but cannot edit the post or share access with others'), + }, + ] + + const { sortedAuthors } = useAuthorsStore({ sortBy: 'name' }) + const { actions } = useInbox() + const [authorsToInvite, setAuthorsToInvite] = createSignal() + + const [searchResultAuthors, setSearchResultAuthors] = createSignal() + const [collectionToInvite, setCollectionToInvite] = createSignal([]) + const fetcher = async (page: number) => { + await new Promise((resolve, reject) => { + const checkDataLoaded = () => { + if (sortedAuthors().length > 0) { + resolve(true) + } else { + setTimeout(checkDataLoaded, 100) + } + } + setTimeout(() => reject(new Error('Timeout waiting for sortedAuthors')), 10000) + checkDataLoaded() + }) + const start = page * PAGE_SIZE + const end = start + PAGE_SIZE + const authors = authorsToInvite().map((author) => ({ ...author, selected: false })) + return authors.slice(start, end) + } + + const [pages, infiniteScrollLoader, { end }] = createInfiniteScroll(fetcher) + + createEffect( + on( + () => sortedAuthors(), + (currentAuthors) => { + setAuthorsToInvite(currentAuthors.map((author) => ({ ...author, selected: false }))) + }, + { defer: true }, + ), + ) + + const handleInputChange = async (value: string) => { + if (value.length > 1) { + const match = authorsToInvite().filter((author) => + author.name.toLowerCase().includes(value.toLowerCase()), + ) + setSearchResultAuthors(match) + } else { + setSearchResultAuthors() + } + } + + const handleInvite = (id) => { + setCollectionToInvite((prev) => [...prev, id]) + } + + const handleCloseModal = () => { + setSearchResultAuthors() + setCollectionToInvite() + hideModal() + } + + const handleCreate = async () => { + try { + const initChat = await actions.createChat(collectionToInvite(), 'chat Title') + console.debug('[components.Inbox] create chat result:', initChat) + hideModal() + await actions.loadChats() + } catch (error) { + console.error('handleCreate chat', error) + } + } + + return ( + +

    {props.title || t('Invite collaborators')}

    +
    +
    +
    + { + if (props.variant === 'recipients') return + handleInputChange(e.target.value) + }} + onInput={(e) => { + if (props.variant === 'coauthors') return + handleInputChange(e.target.value) + }} + /> + + + +
    + +
    + +
    +

    {t('Coming soon')}

    +

    + {t( + 'We are working on collaborative editing of articles and in the near future you will have an amazing opportunity - to create together with your colleagues', + )} +

    +
    +
    + +
    + + {(author) => ( +
    + handleInvite(id)} + /> +
    + )} +
    + +
    +
    + +
    +
    {t('Loading')}
    +
    +
    +
    +
    +
    +
    +
    +
    + ) +} diff --git a/src/components/_shared/InviteMembers/index.ts b/src/components/_shared/InviteMembers/index.ts new file mode 100644 index 00000000..9f759543 --- /dev/null +++ b/src/components/_shared/InviteMembers/index.ts @@ -0,0 +1 @@ +export { InviteMembers } from './InviteMembers' diff --git a/src/components/_shared/UserSearch/UserSearch.tsx b/src/components/_shared/UserSearch/UserSearch.tsx deleted file mode 100644 index 296c5d06..00000000 --- a/src/components/_shared/UserSearch/UserSearch.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { clsx } from 'clsx' - -import { useLocalize } from '../../../context/localize' -import { Button } from '../Button' -import { DropdownSelect } from '../DropdownSelect' - -import styles from './UserSearch.module.scss' - -type Props = { - class?: string - placeholder: string - onChange: (value: string) => void -} - -export const UserSearch = (props: Props) => { - const { t } = useLocalize() - const roles = [ - { - title: t('Editor'), - description: t('Can write and edit text directly, and accept or reject suggestions from others'), - }, - { - title: t('Co-author'), - description: t('Can make any changes, accept or reject suggestions, and share access with others'), - }, - { - title: t('Commentator'), - description: t('Can offer edits and comments, but cannot edit the post or share access with others'), - }, - ] - const handleInputChange = (value: string) => { - props.onChange(value) - } - - return ( -
    -
    -
    - handleInputChange(e.target.value)} - /> - -
    - -
    - -
    -

    {t('Coming soon')}

    -

    - {t( - 'We are working on collaborative editing of articles and in the near future you will have an amazing opportunity - to create together with your colleagues', - )} -

    -
    -
    - ) -} diff --git a/src/components/_shared/UserSearch/index.ts b/src/components/_shared/UserSearch/index.ts deleted file mode 100644 index 5b665453..00000000 --- a/src/components/_shared/UserSearch/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { UserSearch } from './UserSearch' diff --git a/src/graphql/client/chat.ts b/src/graphql/client/chat.ts index 42c5be97..2f637fe3 100644 --- a/src/graphql/client/chat.ts +++ b/src/graphql/client/chat.ts @@ -28,6 +28,7 @@ export const inboxClient = { loadChats: async (options: QueryLoad_ChatsArgs): Promise => { const resp = await inboxClient.private.query(myChats, options).toPromise() + console.log('!!! resp:', resp) return resp.data.load_chats.chats }, diff --git a/src/pages/inbox.page.tsx b/src/pages/inbox.page.tsx index 13f77c07..5b9a9b42 100644 --- a/src/pages/inbox.page.tsx +++ b/src/pages/inbox.page.tsx @@ -4,7 +4,7 @@ import { createSignal, onMount } from 'solid-js' import { PageLayout } from '../components/_shared/PageLayout' import { ShowOnlyOnClient } from '../components/_shared/ShowOnlyOnClient' -import { InboxView } from '../components/Views/Inbox' +import { InboxView } from '../components/Views/Inbox/Inbox' import { InboxProvider } from '../context/inbox' import { useLocalize } from '../context/localize' import { loadAllAuthors } from '../stores/zine/authors' diff --git a/src/stores/ui.ts b/src/stores/ui.ts index 551fe226..4c8fadc1 100644 --- a/src/stores/ui.ts +++ b/src/stores/ui.ts @@ -16,7 +16,6 @@ export type ModalType = | 'thank' | 'confirm' | 'donate' - | 'inviteToChat' | 'uploadImage' | 'simplifiedEditorUploadImage' | 'uploadCoverImage' @@ -24,7 +23,7 @@ export type ModalType = | 'followers' | 'following' | 'search' - | 'inviteCoAuthors' + | 'inviteMembers' | 'share' export const MODALS: Record = { @@ -34,14 +33,13 @@ export const MODALS: Record = { thank: 'thank', confirm: 'confirm', donate: 'donate', - inviteToChat: 'inviteToChat', + inviteMembers: 'inviteMembers', uploadImage: 'uploadImage', simplifiedEditorUploadImage: 'simplifiedEditorUploadImage', uploadCoverImage: 'uploadCoverImage', editorInsertLink: 'editorInsertLink', followers: 'followers', following: 'following', - inviteCoAuthors: 'inviteCoAuthors', search: 'search', share: 'share', } diff --git a/src/stores/zine/authors.ts b/src/stores/zine/authors.ts index 161b7642..099d4e18 100644 --- a/src/stores/zine/authors.ts +++ b/src/stores/zine/authors.ts @@ -1,5 +1,5 @@ import { createLazyMemo } from '@solid-primitives/memo' -import { createSignal } from 'solid-js' +import { createMemo, createSignal } from 'solid-js' import { apiClient } from '../../graphql/client/core' import { Author, QueryLoad_Authors_ByArgs } from '../../graphql/schema/core.gen' @@ -18,16 +18,13 @@ const sortedAuthors = createLazyMemo(() => { const authors = Object.values(authorEntities()) switch (sortAllBy()) { case 'followers': { - authors.sort(byStat('followers')) - break + return authors.sort(byStat('followers')) } case 'shouts': { - authors.sort(byStat('shouts')) - break + return authors.sort(byStat('shouts')) } case 'name': { - authors.sort((a, b) => a.name.localeCompare(b.name)) - break + return authors.sort((a, b) => a.name.localeCompare(b.name)) } } return authors From 591fd2ecbfd5e5794824306f9ea1585113dfb60a Mon Sep 17 00:00:00 2001 From: dog Date: Thu, 25 Jan 2024 15:41:25 +0300 Subject: [PATCH 50/88] implement image crop --- public/locales/en/translation.json | 1 + public/locales/ru/translation.json | 1 + .../ProfileSettings/ProfileSettings.tsx | 67 +++++-- .../ImageCropper/ImageCropper.module.scss | 6 + .../_shared/ImageCropper/ImageCropper.tsx | 165 ++++++++---------- src/stores/ui.ts | 2 + src/styles/app.scss | 28 +++ 7 files changed, 157 insertions(+), 113 deletions(-) diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index fc967d81..2c65fac2 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -105,6 +105,7 @@ "Create gallery": "Create gallery", "Create post": "Create post", "Create video": "Create video", + "Crop image": "Crop image", "Culture": "Culture", "Date of Birth": "Date of Birth", "Decline": "Decline", diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index 5694bc44..ab5481e8 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -109,6 +109,7 @@ "Create gallery": "Создать галерею", "Create post": "Создать публикацию", "Create video": "Создать видео", + "Crop image": "Скадрируйте изображение", "Culture": "Культура", "Date of Birth": "Дата рождения", "Decline": "Отмена", diff --git a/src/components/ProfileSettings/ProfileSettings.tsx b/src/components/ProfileSettings/ProfileSettings.tsx index 1cc18e4d..176a7fa8 100644 --- a/src/components/ProfileSettings/ProfileSettings.tsx +++ b/src/components/ProfileSettings/ProfileSettings.tsx @@ -14,13 +14,18 @@ import { getImageUrl } from '../../utils/getImageUrl' import { handleImageUpload } from '../../utils/handleImageUpload' import { profileSocialLinks } from '../../utils/profileSocialLinks' import { validateUrl } from '../../utils/validateUrl' + +import { Modal } from '../Nav/Modal' import { Button } from '../_shared/Button' import { Icon } from '../_shared/Icon' import { Loading } from '../_shared/Loading' import { Popover } from '../_shared/Popover' import { SocialNetworkInput } from '../_shared/SocialNetworkInput' +import { ImageCropper } from '../_shared/ImageCropper' import { ProfileSettingsNavigation } from '../Nav/ProfileSettingsNavigation' +import { showModal, hideModal } from '../../stores/ui' + import styles from '../../pages/profile/Settings.module.scss' const SimplifiedEditor = lazy(() => import('../../components/Editor/SimplifiedEditor')) @@ -28,12 +33,14 @@ const GrowingTextarea = lazy(() => import('../../components/_shared/GrowingTexta export const ProfileSettings = () => { const { t } = useLocalize() + const [prevForm, setPrevForm] = createStore({}) const [isFormInitialized, setIsFormInitialized] = createSignal(false) const [social, setSocial] = createSignal([]) const [addLinkForm, setAddLinkForm] = createSignal(false) const [incorrectUrl, setIncorrectUrl] = createSignal(false) const [isUserpicUpdating, setIsUserpicUpdating] = createSignal(false) + const [userpicFile, setUserpicFile] = createSignal(null) const [uploadError, setUploadError] = createSignal(false) const [isFloatingPanelVisible, setIsFloatingPanelVisible] = createSignal(false) const [hostname, setHostname] = createSignal(null) @@ -115,23 +122,32 @@ export const ProfileSettings = () => { } } - const { selectFiles } = createFileUploader({ multiple: false, accept: 'image/*' }) + const handleCropAvatar = () => { + const { selectFiles } = createFileUploader({ multiple: false, accept: 'image/*' }) - const handleUploadAvatar = async () => { - selectFiles(async ([uploadFile]) => { - try { - setUploadError(false) - setIsUserpicUpdating(true) - const result = await handleImageUpload(uploadFile) - updateFormField('userpic', result.url) - setIsUserpicUpdating(false) - } catch (error) { - setUploadError(true) - console.error('[upload avatar] error', error) - } + selectFiles(([uploadFile]) => { + setUserpicFile(uploadFile) + + showModal('cropImage') }) } + const handleUploadAvatar = async (uploadFile) => { + try { + setUploadError(false) + setIsUserpicUpdating(true) + + const result = await handleImageUpload(uploadFile) + updateFormField('userpic', result.url) + + setUserpicFile(null) + setIsUserpicUpdating(false) + } catch (error) { + setUploadError(true) + console.error('[upload avatar] error', error) + } + } + onMount(() => { setHostname(window?.location.host) @@ -178,7 +194,7 @@ export const ProfileSettings = () => {
    @@ -206,17 +222,19 @@ export const ProfileSettings = () => { )} - + + {/* @@TODO inspect popover below. onClick causes page refreshing */} + {/* {(triggerRef: (el) => void) => ( )} - + */}
    @@ -365,6 +383,21 @@ export const ProfileSettings = () => {
    + setUserpicFile(null)}> +

    {t('Crop image')}

    + + + { + handleUploadAvatar(data) + + hideModal() + }} + onDecline={() => hideModal()} + /> + +
    ) diff --git a/src/components/_shared/ImageCropper/ImageCropper.module.scss b/src/components/_shared/ImageCropper/ImageCropper.module.scss index e69de29b..19d5ff12 100644 --- a/src/components/_shared/ImageCropper/ImageCropper.module.scss +++ b/src/components/_shared/ImageCropper/ImageCropper.module.scss @@ -0,0 +1,6 @@ +.cropperControls { + display: flex; + justify-content: space-between; + + margin-top: 2rem; +} diff --git a/src/components/_shared/ImageCropper/ImageCropper.tsx b/src/components/_shared/ImageCropper/ImageCropper.tsx index 99d86faf..1d5caded 100644 --- a/src/components/_shared/ImageCropper/ImageCropper.tsx +++ b/src/components/_shared/ImageCropper/ImageCropper.tsx @@ -1,105 +1,78 @@ -import { createSignal, Show } from 'solid-js' -import { createStore } from 'solid-js/store' +import 'cropperjs/dist/cropper.css' + +import { createSignal, onMount, Show } from 'solid-js' import Cropper from 'cropperjs' +import { UploadFile } from '@solid-primitives/upload' + +import { useLocalize } from '../../../context/localize' + +import { Button } from '../Button' import styles from './ImageCropper.module.scss' -export const ImageCropper = (props) => { - let cropImage - const [state, setState] = createStore({ - error: null, - loading: false, - file: {}, - croppedImage: null, - }), - [dropZoneActive, setDropZoneActive] = createSignal(false), - [uploading, setUploading] = createSignal(false), - [preview, setPreview] = createSignal(null), - [cropper, setCropper] = createSignal(null), - noPropagate = (e) => { - e.preventDefault() - }, - uploadFile = async (file) => { - if (!file) return - setUploading(true) - setState('loading', true) - setState('file', file) - try { - const reader = new FileReader() - reader.onload = (e) => { - setPreview(e.target.result) - setCropper( - new Cropper(cropImage, { - aspectRatio: 1 / 1, - viewMode: 1, - rotatable: false, - }), - ) - } - reader.readAsDataURL(file) - } catch (e) { - console.error('upload failed', e) - const message = e instanceof Error ? e.message : String(e) - setState('error', message) - } - setState('loading', false) - setUploading(false) - }, - handleFileDrop = async (e) => { - e.preventDefault() - setDropZoneActive(false) - uploadFile(e.dataTransfer.files[0]) - }, - handleFileInput = async (e) => { - e.preventDefault() - uploadFile(e.currentTarget.files[0]) +interface CropperProps { + uploadFile: UploadFile + onSave: (any) => void + onDecline?: () => void +} + +export const ImageCropper = (props: CropperProps) => { + const { t } = useLocalize() + + const imageTagRef: { current: HTMLImageElement } = { + current: null, + } + + const [cropper, setCropper] = createSignal(null) + + onMount(() => { + if (imageTagRef.current) { + setCropper( + new Cropper(imageTagRef.current, { + viewMode: 1, + aspectRatio: 1, + guides: false, + background: false, + rotatable: false, + modal: true, + }), + ) } + }) return ( - <> - -
    -
    - cropper -
    - -
    -
    - -
    -
    (uploading() ? undefined : setDropZoneActive(true))} - onDragLeave={() => setDropZoneActive(false)} - onDragOver={noPropagate} - onDrop={(event) => (uploading() ? noPropagate(event) : handleFileDrop(event))} - > -
    upload
    - -
    -
    - - - +
    +
    + (imageTagRef.current = el)} + src={props.uploadFile.source} + alt="image crop panel" + /> +
    + +
    + +
    +
    ) } diff --git a/src/stores/ui.ts b/src/stores/ui.ts index 7fcb4fe5..cfaf0c9e 100644 --- a/src/stores/ui.ts +++ b/src/stores/ui.ts @@ -25,6 +25,7 @@ export type ModalType = | 'following' | 'inviteCoAuthors' | 'share' + | 'cropImage' export const MODALS: Record = { auth: 'auth', @@ -42,6 +43,7 @@ export const MODALS: Record = { following: 'following', inviteCoAuthors: 'inviteCoAuthors', share: 'share', + cropImage: 'cropImage', } const [modal, setModal] = createSignal(null) diff --git a/src/styles/app.scss b/src/styles/app.scss index 2d3a7ac2..4efca363 100644 --- a/src/styles/app.scss +++ b/src/styles/app.scss @@ -1070,3 +1070,31 @@ iframe { .img-align-column { clear: both; } + +.cropper-modal { + background-color: #fff !important; +} + +.cropper-canvas { + filter: blur(2px); +} + +.cropper-view-box, +.cropper-crop-box, +.cropper-line, +.cropper-point { + box-shadow: none !important; + outline: none !important; + border: none !important; + background-color: transparent !important; +} + +.cropper-crop-box { + border: 2px solid #000 !important; + border-radius: 8px; +} + +.cropper-view-box, +.cropper-face { + border-radius: 50%; +} From f0dd3c9c8896e8aaf42dbfa6fe2a7cdd45e4b444 Mon Sep 17 00:00:00 2001 From: dog Date: Thu, 25 Jan 2024 18:06:26 +0300 Subject: [PATCH 51/88] fix search modal behavior --- .../Feed/ArticleCard/ArticleCard.tsx | 4 +- src/components/Nav/HeaderAuth.tsx | 4 +- src/components/Nav/Modal/Modal.tsx | 2 +- .../Nav/SearchModal/SearchModal.module.scss | 97 ++- .../Nav/SearchModal/SearchModal.tsx | 274 ++++--- .../Nav/SearchModal/SearchResultItem.tsx | 33 + src/graphql/types.gen.ts | 726 ++++++++++++++++++ src/styles/app.scss | 5 + src/utils/apiClient.ts | 31 + src/utils/config.ts | 3 + 10 files changed, 1023 insertions(+), 156 deletions(-) create mode 100644 src/components/Nav/SearchModal/SearchResultItem.tsx create mode 100644 src/graphql/types.gen.ts create mode 100644 src/utils/apiClient.ts diff --git a/src/components/Feed/ArticleCard/ArticleCard.tsx b/src/components/Feed/ArticleCard/ArticleCard.tsx index 0a6fcf1c..0148697d 100644 --- a/src/components/Feed/ArticleCard/ArticleCard.tsx +++ b/src/components/Feed/ArticleCard/ArticleCard.tsx @@ -214,13 +214,13 @@ export const ArticleCard = (props: ArticleCardProps) => {
    - {title} +
    - {subtitle} +
    diff --git a/src/components/Nav/HeaderAuth.tsx b/src/components/Nav/HeaderAuth.tsx index 44b3f17a..20b51d70 100644 --- a/src/components/Nav/HeaderAuth.tsx +++ b/src/components/Nav/HeaderAuth.tsx @@ -128,10 +128,10 @@ export const HeaderAuth = (props: Props) => {
    - +
    diff --git a/src/components/Nav/Modal/Modal.tsx b/src/components/Nav/Modal/Modal.tsx index 24f9c887..4e25cbfb 100644 --- a/src/components/Nav/Modal/Modal.tsx +++ b/src/components/Nav/Modal/Modal.tsx @@ -55,7 +55,7 @@ export const Modal = (props: Props) => { return (
    + `${str.replace( + new RegExp(intersection, 'gi'), + (casePreservedMatch) => `${casePreservedMatch}`, + )}` + +const prepareSearchResults = (list, searchValue) => + list.map((article, index) => ({ + ...article, + body: '', + cover: '', + createdAt: '', + id: index, + slug: article.slug, + authors: [], + topics: [], + title: article.title + ? getSearchCoincidences({ + str: article.title, + intersection: searchValue, + }) + : '', + subtitle: article.subtitle + ? getSearchCoincidences({ + str: article.subtitle, + intersection: searchValue, + }) + : '', + })) + export const SearchModal = () => { const { t } = useLocalize() - const { changeSearchParams } = useRouter() - let qElement: HTMLInputElement | undefined - const submitQuery = async (ev) => { - ev.preventDefault() - changeSearchParams({}, true) - hideModal() - openPage(router, 'search', { q: qElement.value }) + const [inputValue, setInputValue] = createSignal('') + const [searchResultsList, setSearchResultsList] = createSignal<[] | null>([]) + const [isLoading, setIsLoading] = createSignal(false) + // const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) + + const handleSearch = async () => { + const searchValue = inputValue() || '' + + if (Boolean(searchValue) && searchValue.length > 2) { + setIsLoading(true) + + try { + const response = await apiClient.getSearchResults(searchValue) + const searchResult = await response.json() + + if (searchResult.length > 0) { + const preparedSearchResultsList = prepareSearchResults(searchResult, searchValue) + + setSearchResultsList(preparedSearchResultsList) + } else { + setSearchResultsList(null) + } + } catch (error) { + console.log('search request failed', error) + } finally { + setIsLoading(false) + } + } } + return ( -
    +
    { + setInputValue(event.target.value) + + handleSearch() + }} /> - -

    - Для поиска публикаций, искусства, комментариев, интересных вам авторов и тем, просто начните - вводить ваш запрос -

    -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    + - - - - - -
    +

    -

    -
    -
    - - - - - - - - - - - - - - - - - - - - + + + + {(article: Shout) => ( +
    + +
    + )} +
    + + {/* +

    + +

    +
    */} +
    + + +

    + + + + {/* @@TODO handle filter */} + {/* +

    + + {(filter) => ( + + )} + +
    +
    */} + + {/* @@TODO handle topics */} + {/* +
    +
    +
    + + {(topic) => ( + + )} + +
    -
    - + */} +
    ) } diff --git a/src/components/Nav/SearchModal/SearchResultItem.tsx b/src/components/Nav/SearchModal/SearchResultItem.tsx new file mode 100644 index 00000000..b4b0fbb0 --- /dev/null +++ b/src/components/Nav/SearchModal/SearchResultItem.tsx @@ -0,0 +1,33 @@ +import { ArticleCard } from '../../Feed/ArticleCard' + +import type { Shout } from '../../../graphql/schema/core.gen' + +interface SearchCardProps { + settings?: { + noicon?: boolean + noimage?: boolean + nosubtitle?: boolean + noauthor?: boolean + nodate?: boolean + isGroup?: boolean + photoBottom?: boolean + additionalClass?: string + isFeedMode?: boolean + isFloorImportant?: boolean + isWithCover?: boolean + isBigTitle?: boolean + isVertical?: boolean + isShort?: boolean + withBorder?: boolean + isCompact?: boolean + isSingle?: boolean + isBeside?: boolean + withViewed?: boolean + noAuthorLink?: boolean + } + article: Shout +} + +export const SearchResultItem = (props: SearchCardProps) => { + return +} diff --git a/src/graphql/types.gen.ts b/src/graphql/types.gen.ts new file mode 100644 index 00000000..60674764 --- /dev/null +++ b/src/graphql/types.gen.ts @@ -0,0 +1,726 @@ +import gql from 'graphql-tag' +export type Maybe = T | null +export type InputMaybe = Maybe +export type Exact = { [K in keyof T]: T[K] } +export type MakeOptional = Omit & { [SubKey in K]?: Maybe } +export type MakeMaybe = Omit & { [SubKey in K]: Maybe } +export type MakeEmpty = { [_ in K]?: never } +export type Incremental = + | T + | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never } +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: { input: string; output: string } + String: { input: string; output: string } + Boolean: { input: boolean; output: boolean } + Int: { input: number; output: number } + Float: { input: number; output: number } + DateTime: { input: any; output: any } +} + +export type AuthResult = { + error?: Maybe + token?: Maybe + user?: Maybe +} + +export type Author = { + about?: Maybe + bio?: Maybe + caption?: Maybe + createdAt?: Maybe + id: Scalars['Int']['output'] + lastSeen?: Maybe + links?: Maybe>> + name: Scalars['String']['output'] + roles?: Maybe>> + slug: Scalars['String']['output'] + stat?: Maybe + userpic?: Maybe +} + +export type AuthorStat = { + commented?: Maybe + followers?: Maybe + followings?: Maybe + rating?: Maybe + shouts?: Maybe +} + +export type AuthorsBy = { + createdAt?: InputMaybe + days?: InputMaybe + lastSeen?: InputMaybe + name?: InputMaybe + order?: InputMaybe + slug?: InputMaybe + stat?: InputMaybe + topic?: InputMaybe +} + +export type Chat = { + admins?: Maybe>> + createdAt: Scalars['Int']['output'] + createdBy: Scalars['Int']['output'] + description?: Maybe + id: Scalars['String']['output'] + members?: Maybe>> + messages?: Maybe>> + private?: Maybe + title?: Maybe + unread?: Maybe + updatedAt: Scalars['Int']['output'] + users?: Maybe>> +} + +export type ChatInput = { + description?: InputMaybe + id: Scalars['String']['input'] + title?: InputMaybe +} + +export type ChatMember = { + id: Scalars['Int']['output'] + lastSeen?: Maybe + name: Scalars['String']['output'] + online?: Maybe + slug: Scalars['String']['output'] + userpic?: Maybe +} + +export type Collection = { + amount?: Maybe + createdAt: Scalars['DateTime']['output'] + createdBy: User + desc?: Maybe + id: Scalars['Int']['output'] + publishedAt?: Maybe + slug: Scalars['String']['output'] + title: Scalars['String']['output'] +} + +export type Community = { + createdAt: Scalars['DateTime']['output'] + createdBy: User + desc?: Maybe + id: Scalars['Int']['output'] + name: Scalars['String']['output'] + pic: Scalars['String']['output'] + slug: Scalars['String']['output'] +} + +export enum FollowingEntity { + Author = 'AUTHOR', + Community = 'COMMUNITY', + Reactions = 'REACTIONS', + Topic = 'TOPIC', +} + +export type LoadRandomTopShoutsParams = { + filters?: InputMaybe + fromRandomCount?: InputMaybe + limit: Scalars['Int']['input'] +} + +export type LoadShoutsFilters = { + author?: InputMaybe + excludeLayout?: InputMaybe + fromDate?: InputMaybe + layout?: InputMaybe + reacted?: InputMaybe + toDate?: InputMaybe + topic?: InputMaybe + visibility?: InputMaybe +} + +export type LoadShoutsOptions = { + filters?: InputMaybe + limit: Scalars['Int']['input'] + offset?: InputMaybe + order_by?: InputMaybe + order_by_desc?: InputMaybe + with_author_captions?: InputMaybe +} + +export type Message = { + author: Scalars['Int']['output'] + body: Scalars['String']['output'] + chatId: Scalars['String']['output'] + createdAt: Scalars['Int']['output'] + id: Scalars['Int']['output'] + replyTo?: Maybe + seen?: Maybe + updatedAt?: Maybe +} + +export enum MessageStatus { + Deleted = 'DELETED', + New = 'NEW', + Updated = 'UPDATED', +} + +export type MessagesBy = { + author?: InputMaybe + body?: InputMaybe + chat?: InputMaybe + days?: InputMaybe + order?: InputMaybe + stat?: InputMaybe +} + +export type Mutation = { + confirmEmail: AuthResult + createChat: Result + createMessage: Result + createReaction: Result + createShout: Result + createTopic: Result + deleteChat: Result + deleteMessage: Result + deleteReaction: Result + deleteShout: Result + destroyTopic: Result + follow: Result + getSession: AuthResult + markAllNotificationsAsRead: Result + markAsRead: Result + markNotificationAsRead: Result + rateUser: Result + registerUser: AuthResult + sendLink: Result + unfollow: Result + updateChat: Result + updateMessage: Result + updateProfile: Result + updateReaction: Result + updateShout: Result + updateTopic: Result +} + +export type MutationConfirmEmailArgs = { + token: Scalars['String']['input'] +} + +export type MutationCreateChatArgs = { + members: Array> + title?: InputMaybe +} + +export type MutationCreateMessageArgs = { + body: Scalars['String']['input'] + chat: Scalars['String']['input'] + replyTo?: InputMaybe +} + +export type MutationCreateReactionArgs = { + reaction: ReactionInput +} + +export type MutationCreateShoutArgs = { + inp: ShoutInput +} + +export type MutationCreateTopicArgs = { + input: TopicInput +} + +export type MutationDeleteChatArgs = { + chatId: Scalars['String']['input'] +} + +export type MutationDeleteMessageArgs = { + chatId: Scalars['String']['input'] + id: Scalars['Int']['input'] +} + +export type MutationDeleteReactionArgs = { + id: Scalars['Int']['input'] +} + +export type MutationDeleteShoutArgs = { + shout_id: Scalars['Int']['input'] +} + +export type MutationDestroyTopicArgs = { + slug: Scalars['String']['input'] +} + +export type MutationFollowArgs = { + slug: Scalars['String']['input'] + what: FollowingEntity +} + +export type MutationMarkAsReadArgs = { + chatId: Scalars['String']['input'] + ids: Array> +} + +export type MutationMarkNotificationAsReadArgs = { + notification_id: Scalars['Int']['input'] +} + +export type MutationRateUserArgs = { + slug: Scalars['String']['input'] + value: Scalars['Int']['input'] +} + +export type MutationRegisterUserArgs = { + email: Scalars['String']['input'] + name?: InputMaybe + password?: InputMaybe +} + +export type MutationSendLinkArgs = { + email: Scalars['String']['input'] + lang?: InputMaybe + template?: InputMaybe +} + +export type MutationUnfollowArgs = { + slug: Scalars['String']['input'] + what: FollowingEntity +} + +export type MutationUpdateChatArgs = { + chat: ChatInput +} + +export type MutationUpdateMessageArgs = { + body: Scalars['String']['input'] + chatId: Scalars['String']['input'] + id: Scalars['Int']['input'] +} + +export type MutationUpdateProfileArgs = { + profile: ProfileInput +} + +export type MutationUpdateReactionArgs = { + id: Scalars['Int']['input'] + reaction: ReactionInput +} + +export type MutationUpdateShoutArgs = { + publish?: InputMaybe + shout_id: Scalars['Int']['input'] + shout_input?: InputMaybe +} + +export type MutationUpdateTopicArgs = { + input: TopicInput +} + +export type MySubscriptionsQueryResult = { + authors: Array> + topics: Array> +} + +export type Notification = { + createdAt: Scalars['DateTime']['output'] + data?: Maybe + id: Scalars['Int']['output'] + occurrences: Scalars['Int']['output'] + reaction?: Maybe + seen: Scalars['Boolean']['output'] + shout?: Maybe + type: NotificationType +} + +export enum NotificationType { + NewComment = 'NEW_COMMENT', + NewReply = 'NEW_REPLY', +} + +export type NotificationsQueryParams = { + limit?: InputMaybe + offset?: InputMaybe +} + +export type NotificationsQueryResult = { + notifications: Array> + totalCount: Scalars['Int']['output'] + totalUnreadCount: Scalars['Int']['output'] +} + +export type Operation = { + id: Scalars['Int']['output'] + name: Scalars['String']['output'] +} + +export type Permission = { + operation: Scalars['Int']['output'] + resource: Scalars['Int']['output'] +} + +export type ProfileInput = { + about?: InputMaybe + bio?: InputMaybe + links?: InputMaybe>> + name?: InputMaybe + slug?: InputMaybe + userpic?: InputMaybe +} + +export type Query = { + authorsAll: Array> + getAuthor?: Maybe + getTopic?: Maybe + isEmailUsed: Scalars['Boolean']['output'] + loadAuthorsBy: Array> + loadChats: Result + loadDrafts: Array> + loadMessagesBy: Result + loadMySubscriptions?: Maybe + loadNotifications: NotificationsQueryResult + loadRandomTopShouts: Array> + loadRandomTopicShouts: RandomTopicShoutsQueryResult + loadReactionsBy: Array> + loadRecipients: Result + loadShout?: Maybe + loadShouts: Array> + loadUnratedShouts: Array> + markdownBody: Scalars['String']['output'] + myFeed?: Maybe>> + searchMessages: Result + searchRecipients: Result + signIn: AuthResult + signOut: AuthResult + topicsAll: Array> + topicsByAuthor: Array> + topicsByCommunity: Array> + topicsRandom: Array> + userFollowedAuthors: Array> + userFollowedTopics: Array> + userFollowers: Array> +} + +export type QueryGetAuthorArgs = { + slug: Scalars['String']['input'] +} + +export type QueryGetTopicArgs = { + slug: Scalars['String']['input'] +} + +export type QueryIsEmailUsedArgs = { + email: Scalars['String']['input'] +} + +export type QueryLoadAuthorsByArgs = { + by?: InputMaybe + limit?: InputMaybe + offset?: InputMaybe +} + +export type QueryLoadChatsArgs = { + limit?: InputMaybe + offset?: InputMaybe +} + +export type QueryLoadMessagesByArgs = { + by: MessagesBy + limit?: InputMaybe + offset?: InputMaybe +} + +export type QueryLoadNotificationsArgs = { + params: NotificationsQueryParams +} + +export type QueryLoadRandomTopShoutsArgs = { + params?: InputMaybe +} + +export type QueryLoadRandomTopicShoutsArgs = { + limit: Scalars['Int']['input'] +} + +export type QueryLoadReactionsByArgs = { + by: ReactionBy + limit?: InputMaybe + offset?: InputMaybe +} + +export type QueryLoadRecipientsArgs = { + limit?: InputMaybe + offset?: InputMaybe +} + +export type QueryLoadShoutArgs = { + shout_id?: InputMaybe + slug?: InputMaybe +} + +export type QueryLoadShoutsArgs = { + options?: InputMaybe +} + +export type QueryLoadUnratedShoutsArgs = { + limit: Scalars['Int']['input'] +} + +export type QueryMarkdownBodyArgs = { + body: Scalars['String']['input'] +} + +export type QueryMyFeedArgs = { + options?: InputMaybe +} + +export type QuerySearchMessagesArgs = { + by: MessagesBy + limit?: InputMaybe + offset?: InputMaybe +} + +export type QuerySearchRecipientsArgs = { + limit?: InputMaybe + offset?: InputMaybe + query: Scalars['String']['input'] +} + +export type QuerySignInArgs = { + email: Scalars['String']['input'] + lang?: InputMaybe + password?: InputMaybe +} + +export type QueryTopicsByAuthorArgs = { + author: Scalars['String']['input'] +} + +export type QueryTopicsByCommunityArgs = { + community: Scalars['String']['input'] +} + +export type QueryTopicsRandomArgs = { + amount?: InputMaybe +} + +export type QueryUserFollowedAuthorsArgs = { + slug: Scalars['String']['input'] +} + +export type QueryUserFollowedTopicsArgs = { + slug: Scalars['String']['input'] +} + +export type QueryUserFollowersArgs = { + slug: Scalars['String']['input'] +} + +export type RandomTopicShoutsQueryResult = { + shouts: Array> + topic: Topic +} + +export type Rating = { + rater: Scalars['String']['output'] + value: Scalars['Int']['output'] +} + +export type Reaction = { + body?: Maybe + createdAt: Scalars['DateTime']['output'] + createdBy: User + deletedAt?: Maybe + deletedBy?: Maybe + id: Scalars['Int']['output'] + kind: ReactionKind + old_id?: Maybe + old_thread?: Maybe + range?: Maybe + replyTo?: Maybe + shout: Shout + stat?: Maybe + updatedAt?: Maybe +} + +export type ReactionBy = { + comment?: InputMaybe + createdBy?: InputMaybe + days?: InputMaybe + search?: InputMaybe + shout?: InputMaybe + shouts?: InputMaybe>> + sort?: InputMaybe + topic?: InputMaybe +} + +export type ReactionInput = { + body?: InputMaybe + kind: ReactionKind + range?: InputMaybe + replyTo?: InputMaybe + shout: Scalars['Int']['input'] +} + +export enum ReactionKind { + Accept = 'ACCEPT', + Agree = 'AGREE', + Ask = 'ASK', + Comment = 'COMMENT', + Disagree = 'DISAGREE', + Dislike = 'DISLIKE', + Disproof = 'DISPROOF', + Footnote = 'FOOTNOTE', + Like = 'LIKE', + Proof = 'PROOF', + Propose = 'PROPOSE', + Quote = 'QUOTE', + Reject = 'REJECT', + Remark = 'REMARK', +} + +export enum ReactionStatus { + Changed = 'CHANGED', + Deleted = 'DELETED', + Explained = 'EXPLAINED', + New = 'NEW', + Updated = 'UPDATED', +} + +export type ReactionUpdating = { + error?: Maybe + reaction?: Maybe + status?: Maybe +} + +export type Resource = { + id: Scalars['Int']['output'] + name: Scalars['String']['output'] +} + +export type Result = { + author?: Maybe + authors?: Maybe>> + chat?: Maybe + chats?: Maybe>> + communities?: Maybe>> + community?: Maybe + error?: Maybe + members?: Maybe>> + message?: Maybe + messages?: Maybe>> + reaction?: Maybe + reactions?: Maybe>> + shout?: Maybe + shouts?: Maybe>> + slugs?: Maybe>> + topic?: Maybe + topics?: Maybe>> +} + +export type Role = { + community: Scalars['String']['output'] + desc?: Maybe + id: Scalars['Int']['output'] + name: Scalars['String']['output'] + permissions: Array +} + +export type Shout = { + authors?: Maybe>> + body: Scalars['String']['output'] + community?: Maybe + cover?: Maybe + createdAt: Scalars['DateTime']['output'] + deletedAt?: Maybe + deletedBy?: Maybe + description?: Maybe + id: Scalars['Int']['output'] + lang?: Maybe + layout?: Maybe + lead?: Maybe + mainTopic?: Maybe + media?: Maybe + publishedAt?: Maybe + slug: Scalars['String']['output'] + stat?: Maybe + subtitle?: Maybe + title?: Maybe + topics?: Maybe>> + updatedAt?: Maybe + updatedBy?: Maybe + versionOf?: Maybe + visibility?: Maybe +} + +export type ShoutInput = { + authors?: InputMaybe>> + body?: InputMaybe + community?: InputMaybe + cover?: InputMaybe + description?: InputMaybe + layout?: InputMaybe + lead?: InputMaybe + mainTopic?: InputMaybe + media?: InputMaybe + slug?: InputMaybe + subtitle?: InputMaybe + title?: InputMaybe + topics?: InputMaybe>> +} + +export type Stat = { + commented?: Maybe + ranking?: Maybe + rating?: Maybe + reacted?: Maybe + viewed?: Maybe +} + +export type Token = { + createdAt: Scalars['DateTime']['output'] + expiresAt?: Maybe + id: Scalars['Int']['output'] + ownerId: Scalars['Int']['output'] + usedAt?: Maybe + value: Scalars['String']['output'] +} + +export type Topic = { + body?: Maybe + id: Scalars['Int']['output'] + oid?: Maybe + pic?: Maybe + slug: Scalars['String']['output'] + stat?: Maybe + title?: Maybe +} + +export type TopicInput = { + body?: InputMaybe + id?: InputMaybe + pic?: InputMaybe + slug: Scalars['String']['input'] + title?: InputMaybe +} + +export type TopicStat = { + authors: Scalars['Int']['output'] + followers: Scalars['Int']['output'] + shouts: Scalars['Int']['output'] +} + +export type User = { + about?: Maybe + bio?: Maybe + communities?: Maybe>> + createdAt: Scalars['DateTime']['output'] + email?: Maybe + emailConfirmed?: Maybe + id: Scalars['Int']['output'] + lastSeen?: Maybe + links?: Maybe>> + muted?: Maybe + name?: Maybe + oauth?: Maybe + oid?: Maybe + password?: Maybe + ratings?: Maybe>> + slug: Scalars['String']['output'] + updatedAt?: Maybe + username: Scalars['String']['output'] + userpic?: Maybe +} diff --git a/src/styles/app.scss b/src/styles/app.scss index f3fae241..af875c73 100644 --- a/src/styles/app.scss +++ b/src/styles/app.scss @@ -1071,3 +1071,8 @@ iframe { .img-align-column { clear: both; } + +.blackModeIntersection { + color: var(--default-color); + background: #fef2f2; +} diff --git a/src/utils/apiClient.ts b/src/utils/apiClient.ts new file mode 100644 index 00000000..ed0dbcc1 --- /dev/null +++ b/src/utils/apiClient.ts @@ -0,0 +1,31 @@ +import { searchUrl } from './config' + +type ApiErrorCode = + | 'unknown' + | 'email_not_confirmed' + | 'user_not_found' + | 'user_already_exists' + | 'token_expired' + | 'token_invalid' + | 'duplicate_slug' + +export class ApiError extends Error { + code: ApiErrorCode + + constructor(code: ApiErrorCode, message?: string) { + super(message) + this.code = code + } +} + +export const apiClient = { + getSearchResults: async (searchValue: string) => { + return await fetch(`${searchUrl}/search?q=${searchValue}`, { + method: 'GET', + headers: { + accept: 'application/json', + 'content-type': 'application/json; charset=utf-8', + }, + }) + }, +} diff --git a/src/utils/config.ts b/src/utils/config.ts index 78f683e5..1cfd89a5 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -5,3 +5,6 @@ export const cdnUrl = 'https://cdn.discours.io' export const thumborUrl = import.meta.env.PUBLIC_THUMBOR_URL || defaultThumborUrl export const SENTRY_DSN = import.meta.env.PUBLIC_SENTRY_DSN || '' + +const defaultSearchUrl = 'https://search.discours.io' +export const searchUrl = import.meta.env.PUBLIC_SEARCH_URL || defaultSearchUrl From 5f592e6fff90b88480f9cc29d47ffbc5b08d55d5 Mon Sep 17 00:00:00 2001 From: Untone Date: Thu, 25 Jan 2024 21:19:59 +0300 Subject: [PATCH 52/88] postmerge-fix --- .../Author/AuthorBadge/AuthorBadge.tsx | 2 +- .../Nav/SearchModal/SearchModal.tsx | 24 +- .../Nav/SearchModal/SearchResultItem.tsx | 4 +- src/context/reactions.tsx | 10 +- src/graphql/types.gen.ts | 726 ------------------ src/stores/zine/authors.ts | 2 +- src/utils/apiClient.ts | 31 - 7 files changed, 25 insertions(+), 774 deletions(-) delete mode 100644 src/graphql/types.gen.ts delete mode 100644 src/utils/apiClient.ts diff --git a/src/components/Author/AuthorBadge/AuthorBadge.tsx b/src/components/Author/AuthorBadge/AuthorBadge.tsx index 64a6275b..a596075a 100644 --- a/src/components/Author/AuthorBadge/AuthorBadge.tsx +++ b/src/components/Author/AuthorBadge/AuthorBadge.tsx @@ -1,4 +1,4 @@ -import { getPagePath, openPage } from '@nanostores/router' +import { openPage } from '@nanostores/router' import { clsx } from 'clsx' import { createEffect, createMemo, createSignal, Match, Show, Switch } from 'solid-js' diff --git a/src/components/Nav/SearchModal/SearchModal.tsx b/src/components/Nav/SearchModal/SearchModal.tsx index 5bcb3e50..a0295f5f 100644 --- a/src/components/Nav/SearchModal/SearchModal.tsx +++ b/src/components/Nav/SearchModal/SearchModal.tsx @@ -1,13 +1,14 @@ -import { createSignal, Show, For } from 'solid-js' - -import { Button } from '../../_shared/Button' -import { Icon } from '../../_shared/Icon' -import { SearchResultItem } from './SearchResultItem' - -import { apiClient } from '../../../utils/apiClient' import type { Shout } from '../../../graphql/schema/core.gen' +import { createSignal, Show, For } from 'solid-js' + import { useLocalize } from '../../../context/localize' +import { apiClient } from '../../../graphql/client/core' +import { Button } from '../../_shared/Button' +import { Icon } from '../../_shared/Icon' +import { FEED_PAGE_SIZE } from '../../Views/Feed/Feed' + +import { SearchResultItem } from './SearchResultItem' import styles from './SearchModal.module.scss' @@ -16,7 +17,7 @@ import styles from './SearchModal.module.scss' // @@TODO implement FILTERS & TOPICS const getSearchCoincidences = ({ str, intersection }: { str: string; intersection: string }) => - `${str.replace( + `${str.replaceAll( new RegExp(intersection, 'gi'), (casePreservedMatch) => `${casePreservedMatch}`, )}` @@ -60,7 +61,12 @@ export const SearchModal = () => { setIsLoading(true) try { - const response = await apiClient.getSearchResults(searchValue) + // TODO: use offset to load more + const response = await apiClient.getShoutsSearch({ + text: searchValue, + limit: FEED_PAGE_SIZE, + offset: 0, + }) const searchResult = await response.json() if (searchResult.length > 0) { diff --git a/src/components/Nav/SearchModal/SearchResultItem.tsx b/src/components/Nav/SearchModal/SearchResultItem.tsx index b4b0fbb0..948e37de 100644 --- a/src/components/Nav/SearchModal/SearchResultItem.tsx +++ b/src/components/Nav/SearchModal/SearchResultItem.tsx @@ -1,7 +1,7 @@ -import { ArticleCard } from '../../Feed/ArticleCard' - import type { Shout } from '../../../graphql/schema/core.gen' +import { ArticleCard } from '../../Feed/ArticleCard' + interface SearchCardProps { settings?: { noicon?: boolean diff --git a/src/context/reactions.tsx b/src/context/reactions.tsx index 8717f6da..c98ebcaa 100644 --- a/src/context/reactions.tsx +++ b/src/context/reactions.tsx @@ -82,10 +82,12 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => { } const deleteReaction = async (reaction_id: number): Promise => { - const r = await apiClient.destroyReaction(reaction_id) - setReactionEntities({ - [reaction_id]: undefined, - }) + if (reaction_id) { + await apiClient.destroyReaction(reaction_id) + setReactionEntities({ + [reaction_id]: undefined, + }) + } } const updateReaction = async (id: number, input: ReactionInput): Promise => { diff --git a/src/graphql/types.gen.ts b/src/graphql/types.gen.ts deleted file mode 100644 index 60674764..00000000 --- a/src/graphql/types.gen.ts +++ /dev/null @@ -1,726 +0,0 @@ -import gql from 'graphql-tag' -export type Maybe = T | null -export type InputMaybe = Maybe -export type Exact = { [K in keyof T]: T[K] } -export type MakeOptional = Omit & { [SubKey in K]?: Maybe } -export type MakeMaybe = Omit & { [SubKey in K]: Maybe } -export type MakeEmpty = { [_ in K]?: never } -export type Incremental = - | T - | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never } -/** All built-in and custom scalars, mapped to their actual values */ -export type Scalars = { - ID: { input: string; output: string } - String: { input: string; output: string } - Boolean: { input: boolean; output: boolean } - Int: { input: number; output: number } - Float: { input: number; output: number } - DateTime: { input: any; output: any } -} - -export type AuthResult = { - error?: Maybe - token?: Maybe - user?: Maybe -} - -export type Author = { - about?: Maybe - bio?: Maybe - caption?: Maybe - createdAt?: Maybe - id: Scalars['Int']['output'] - lastSeen?: Maybe - links?: Maybe>> - name: Scalars['String']['output'] - roles?: Maybe>> - slug: Scalars['String']['output'] - stat?: Maybe - userpic?: Maybe -} - -export type AuthorStat = { - commented?: Maybe - followers?: Maybe - followings?: Maybe - rating?: Maybe - shouts?: Maybe -} - -export type AuthorsBy = { - createdAt?: InputMaybe - days?: InputMaybe - lastSeen?: InputMaybe - name?: InputMaybe - order?: InputMaybe - slug?: InputMaybe - stat?: InputMaybe - topic?: InputMaybe -} - -export type Chat = { - admins?: Maybe>> - createdAt: Scalars['Int']['output'] - createdBy: Scalars['Int']['output'] - description?: Maybe - id: Scalars['String']['output'] - members?: Maybe>> - messages?: Maybe>> - private?: Maybe - title?: Maybe - unread?: Maybe - updatedAt: Scalars['Int']['output'] - users?: Maybe>> -} - -export type ChatInput = { - description?: InputMaybe - id: Scalars['String']['input'] - title?: InputMaybe -} - -export type ChatMember = { - id: Scalars['Int']['output'] - lastSeen?: Maybe - name: Scalars['String']['output'] - online?: Maybe - slug: Scalars['String']['output'] - userpic?: Maybe -} - -export type Collection = { - amount?: Maybe - createdAt: Scalars['DateTime']['output'] - createdBy: User - desc?: Maybe - id: Scalars['Int']['output'] - publishedAt?: Maybe - slug: Scalars['String']['output'] - title: Scalars['String']['output'] -} - -export type Community = { - createdAt: Scalars['DateTime']['output'] - createdBy: User - desc?: Maybe - id: Scalars['Int']['output'] - name: Scalars['String']['output'] - pic: Scalars['String']['output'] - slug: Scalars['String']['output'] -} - -export enum FollowingEntity { - Author = 'AUTHOR', - Community = 'COMMUNITY', - Reactions = 'REACTIONS', - Topic = 'TOPIC', -} - -export type LoadRandomTopShoutsParams = { - filters?: InputMaybe - fromRandomCount?: InputMaybe - limit: Scalars['Int']['input'] -} - -export type LoadShoutsFilters = { - author?: InputMaybe - excludeLayout?: InputMaybe - fromDate?: InputMaybe - layout?: InputMaybe - reacted?: InputMaybe - toDate?: InputMaybe - topic?: InputMaybe - visibility?: InputMaybe -} - -export type LoadShoutsOptions = { - filters?: InputMaybe - limit: Scalars['Int']['input'] - offset?: InputMaybe - order_by?: InputMaybe - order_by_desc?: InputMaybe - with_author_captions?: InputMaybe -} - -export type Message = { - author: Scalars['Int']['output'] - body: Scalars['String']['output'] - chatId: Scalars['String']['output'] - createdAt: Scalars['Int']['output'] - id: Scalars['Int']['output'] - replyTo?: Maybe - seen?: Maybe - updatedAt?: Maybe -} - -export enum MessageStatus { - Deleted = 'DELETED', - New = 'NEW', - Updated = 'UPDATED', -} - -export type MessagesBy = { - author?: InputMaybe - body?: InputMaybe - chat?: InputMaybe - days?: InputMaybe - order?: InputMaybe - stat?: InputMaybe -} - -export type Mutation = { - confirmEmail: AuthResult - createChat: Result - createMessage: Result - createReaction: Result - createShout: Result - createTopic: Result - deleteChat: Result - deleteMessage: Result - deleteReaction: Result - deleteShout: Result - destroyTopic: Result - follow: Result - getSession: AuthResult - markAllNotificationsAsRead: Result - markAsRead: Result - markNotificationAsRead: Result - rateUser: Result - registerUser: AuthResult - sendLink: Result - unfollow: Result - updateChat: Result - updateMessage: Result - updateProfile: Result - updateReaction: Result - updateShout: Result - updateTopic: Result -} - -export type MutationConfirmEmailArgs = { - token: Scalars['String']['input'] -} - -export type MutationCreateChatArgs = { - members: Array> - title?: InputMaybe -} - -export type MutationCreateMessageArgs = { - body: Scalars['String']['input'] - chat: Scalars['String']['input'] - replyTo?: InputMaybe -} - -export type MutationCreateReactionArgs = { - reaction: ReactionInput -} - -export type MutationCreateShoutArgs = { - inp: ShoutInput -} - -export type MutationCreateTopicArgs = { - input: TopicInput -} - -export type MutationDeleteChatArgs = { - chatId: Scalars['String']['input'] -} - -export type MutationDeleteMessageArgs = { - chatId: Scalars['String']['input'] - id: Scalars['Int']['input'] -} - -export type MutationDeleteReactionArgs = { - id: Scalars['Int']['input'] -} - -export type MutationDeleteShoutArgs = { - shout_id: Scalars['Int']['input'] -} - -export type MutationDestroyTopicArgs = { - slug: Scalars['String']['input'] -} - -export type MutationFollowArgs = { - slug: Scalars['String']['input'] - what: FollowingEntity -} - -export type MutationMarkAsReadArgs = { - chatId: Scalars['String']['input'] - ids: Array> -} - -export type MutationMarkNotificationAsReadArgs = { - notification_id: Scalars['Int']['input'] -} - -export type MutationRateUserArgs = { - slug: Scalars['String']['input'] - value: Scalars['Int']['input'] -} - -export type MutationRegisterUserArgs = { - email: Scalars['String']['input'] - name?: InputMaybe - password?: InputMaybe -} - -export type MutationSendLinkArgs = { - email: Scalars['String']['input'] - lang?: InputMaybe - template?: InputMaybe -} - -export type MutationUnfollowArgs = { - slug: Scalars['String']['input'] - what: FollowingEntity -} - -export type MutationUpdateChatArgs = { - chat: ChatInput -} - -export type MutationUpdateMessageArgs = { - body: Scalars['String']['input'] - chatId: Scalars['String']['input'] - id: Scalars['Int']['input'] -} - -export type MutationUpdateProfileArgs = { - profile: ProfileInput -} - -export type MutationUpdateReactionArgs = { - id: Scalars['Int']['input'] - reaction: ReactionInput -} - -export type MutationUpdateShoutArgs = { - publish?: InputMaybe - shout_id: Scalars['Int']['input'] - shout_input?: InputMaybe -} - -export type MutationUpdateTopicArgs = { - input: TopicInput -} - -export type MySubscriptionsQueryResult = { - authors: Array> - topics: Array> -} - -export type Notification = { - createdAt: Scalars['DateTime']['output'] - data?: Maybe - id: Scalars['Int']['output'] - occurrences: Scalars['Int']['output'] - reaction?: Maybe - seen: Scalars['Boolean']['output'] - shout?: Maybe - type: NotificationType -} - -export enum NotificationType { - NewComment = 'NEW_COMMENT', - NewReply = 'NEW_REPLY', -} - -export type NotificationsQueryParams = { - limit?: InputMaybe - offset?: InputMaybe -} - -export type NotificationsQueryResult = { - notifications: Array> - totalCount: Scalars['Int']['output'] - totalUnreadCount: Scalars['Int']['output'] -} - -export type Operation = { - id: Scalars['Int']['output'] - name: Scalars['String']['output'] -} - -export type Permission = { - operation: Scalars['Int']['output'] - resource: Scalars['Int']['output'] -} - -export type ProfileInput = { - about?: InputMaybe - bio?: InputMaybe - links?: InputMaybe>> - name?: InputMaybe - slug?: InputMaybe - userpic?: InputMaybe -} - -export type Query = { - authorsAll: Array> - getAuthor?: Maybe - getTopic?: Maybe - isEmailUsed: Scalars['Boolean']['output'] - loadAuthorsBy: Array> - loadChats: Result - loadDrafts: Array> - loadMessagesBy: Result - loadMySubscriptions?: Maybe - loadNotifications: NotificationsQueryResult - loadRandomTopShouts: Array> - loadRandomTopicShouts: RandomTopicShoutsQueryResult - loadReactionsBy: Array> - loadRecipients: Result - loadShout?: Maybe - loadShouts: Array> - loadUnratedShouts: Array> - markdownBody: Scalars['String']['output'] - myFeed?: Maybe>> - searchMessages: Result - searchRecipients: Result - signIn: AuthResult - signOut: AuthResult - topicsAll: Array> - topicsByAuthor: Array> - topicsByCommunity: Array> - topicsRandom: Array> - userFollowedAuthors: Array> - userFollowedTopics: Array> - userFollowers: Array> -} - -export type QueryGetAuthorArgs = { - slug: Scalars['String']['input'] -} - -export type QueryGetTopicArgs = { - slug: Scalars['String']['input'] -} - -export type QueryIsEmailUsedArgs = { - email: Scalars['String']['input'] -} - -export type QueryLoadAuthorsByArgs = { - by?: InputMaybe - limit?: InputMaybe - offset?: InputMaybe -} - -export type QueryLoadChatsArgs = { - limit?: InputMaybe - offset?: InputMaybe -} - -export type QueryLoadMessagesByArgs = { - by: MessagesBy - limit?: InputMaybe - offset?: InputMaybe -} - -export type QueryLoadNotificationsArgs = { - params: NotificationsQueryParams -} - -export type QueryLoadRandomTopShoutsArgs = { - params?: InputMaybe -} - -export type QueryLoadRandomTopicShoutsArgs = { - limit: Scalars['Int']['input'] -} - -export type QueryLoadReactionsByArgs = { - by: ReactionBy - limit?: InputMaybe - offset?: InputMaybe -} - -export type QueryLoadRecipientsArgs = { - limit?: InputMaybe - offset?: InputMaybe -} - -export type QueryLoadShoutArgs = { - shout_id?: InputMaybe - slug?: InputMaybe -} - -export type QueryLoadShoutsArgs = { - options?: InputMaybe -} - -export type QueryLoadUnratedShoutsArgs = { - limit: Scalars['Int']['input'] -} - -export type QueryMarkdownBodyArgs = { - body: Scalars['String']['input'] -} - -export type QueryMyFeedArgs = { - options?: InputMaybe -} - -export type QuerySearchMessagesArgs = { - by: MessagesBy - limit?: InputMaybe - offset?: InputMaybe -} - -export type QuerySearchRecipientsArgs = { - limit?: InputMaybe - offset?: InputMaybe - query: Scalars['String']['input'] -} - -export type QuerySignInArgs = { - email: Scalars['String']['input'] - lang?: InputMaybe - password?: InputMaybe -} - -export type QueryTopicsByAuthorArgs = { - author: Scalars['String']['input'] -} - -export type QueryTopicsByCommunityArgs = { - community: Scalars['String']['input'] -} - -export type QueryTopicsRandomArgs = { - amount?: InputMaybe -} - -export type QueryUserFollowedAuthorsArgs = { - slug: Scalars['String']['input'] -} - -export type QueryUserFollowedTopicsArgs = { - slug: Scalars['String']['input'] -} - -export type QueryUserFollowersArgs = { - slug: Scalars['String']['input'] -} - -export type RandomTopicShoutsQueryResult = { - shouts: Array> - topic: Topic -} - -export type Rating = { - rater: Scalars['String']['output'] - value: Scalars['Int']['output'] -} - -export type Reaction = { - body?: Maybe - createdAt: Scalars['DateTime']['output'] - createdBy: User - deletedAt?: Maybe - deletedBy?: Maybe - id: Scalars['Int']['output'] - kind: ReactionKind - old_id?: Maybe - old_thread?: Maybe - range?: Maybe - replyTo?: Maybe - shout: Shout - stat?: Maybe - updatedAt?: Maybe -} - -export type ReactionBy = { - comment?: InputMaybe - createdBy?: InputMaybe - days?: InputMaybe - search?: InputMaybe - shout?: InputMaybe - shouts?: InputMaybe>> - sort?: InputMaybe - topic?: InputMaybe -} - -export type ReactionInput = { - body?: InputMaybe - kind: ReactionKind - range?: InputMaybe - replyTo?: InputMaybe - shout: Scalars['Int']['input'] -} - -export enum ReactionKind { - Accept = 'ACCEPT', - Agree = 'AGREE', - Ask = 'ASK', - Comment = 'COMMENT', - Disagree = 'DISAGREE', - Dislike = 'DISLIKE', - Disproof = 'DISPROOF', - Footnote = 'FOOTNOTE', - Like = 'LIKE', - Proof = 'PROOF', - Propose = 'PROPOSE', - Quote = 'QUOTE', - Reject = 'REJECT', - Remark = 'REMARK', -} - -export enum ReactionStatus { - Changed = 'CHANGED', - Deleted = 'DELETED', - Explained = 'EXPLAINED', - New = 'NEW', - Updated = 'UPDATED', -} - -export type ReactionUpdating = { - error?: Maybe - reaction?: Maybe - status?: Maybe -} - -export type Resource = { - id: Scalars['Int']['output'] - name: Scalars['String']['output'] -} - -export type Result = { - author?: Maybe - authors?: Maybe>> - chat?: Maybe - chats?: Maybe>> - communities?: Maybe>> - community?: Maybe - error?: Maybe - members?: Maybe>> - message?: Maybe - messages?: Maybe>> - reaction?: Maybe - reactions?: Maybe>> - shout?: Maybe - shouts?: Maybe>> - slugs?: Maybe>> - topic?: Maybe - topics?: Maybe>> -} - -export type Role = { - community: Scalars['String']['output'] - desc?: Maybe - id: Scalars['Int']['output'] - name: Scalars['String']['output'] - permissions: Array -} - -export type Shout = { - authors?: Maybe>> - body: Scalars['String']['output'] - community?: Maybe - cover?: Maybe - createdAt: Scalars['DateTime']['output'] - deletedAt?: Maybe - deletedBy?: Maybe - description?: Maybe - id: Scalars['Int']['output'] - lang?: Maybe - layout?: Maybe - lead?: Maybe - mainTopic?: Maybe - media?: Maybe - publishedAt?: Maybe - slug: Scalars['String']['output'] - stat?: Maybe - subtitle?: Maybe - title?: Maybe - topics?: Maybe>> - updatedAt?: Maybe - updatedBy?: Maybe - versionOf?: Maybe - visibility?: Maybe -} - -export type ShoutInput = { - authors?: InputMaybe>> - body?: InputMaybe - community?: InputMaybe - cover?: InputMaybe - description?: InputMaybe - layout?: InputMaybe - lead?: InputMaybe - mainTopic?: InputMaybe - media?: InputMaybe - slug?: InputMaybe - subtitle?: InputMaybe - title?: InputMaybe - topics?: InputMaybe>> -} - -export type Stat = { - commented?: Maybe - ranking?: Maybe - rating?: Maybe - reacted?: Maybe - viewed?: Maybe -} - -export type Token = { - createdAt: Scalars['DateTime']['output'] - expiresAt?: Maybe - id: Scalars['Int']['output'] - ownerId: Scalars['Int']['output'] - usedAt?: Maybe - value: Scalars['String']['output'] -} - -export type Topic = { - body?: Maybe - id: Scalars['Int']['output'] - oid?: Maybe - pic?: Maybe - slug: Scalars['String']['output'] - stat?: Maybe - title?: Maybe -} - -export type TopicInput = { - body?: InputMaybe - id?: InputMaybe - pic?: InputMaybe - slug: Scalars['String']['input'] - title?: InputMaybe -} - -export type TopicStat = { - authors: Scalars['Int']['output'] - followers: Scalars['Int']['output'] - shouts: Scalars['Int']['output'] -} - -export type User = { - about?: Maybe - bio?: Maybe - communities?: Maybe>> - createdAt: Scalars['DateTime']['output'] - email?: Maybe - emailConfirmed?: Maybe - id: Scalars['Int']['output'] - lastSeen?: Maybe - links?: Maybe>> - muted?: Maybe - name?: Maybe - oauth?: Maybe - oid?: Maybe - password?: Maybe - ratings?: Maybe>> - slug: Scalars['String']['output'] - updatedAt?: Maybe - username: Scalars['String']['output'] - userpic?: Maybe -} diff --git a/src/stores/zine/authors.ts b/src/stores/zine/authors.ts index 099d4e18..db3f0627 100644 --- a/src/stores/zine/authors.ts +++ b/src/stores/zine/authors.ts @@ -1,5 +1,5 @@ import { createLazyMemo } from '@solid-primitives/memo' -import { createMemo, createSignal } from 'solid-js' +import { createSignal } from 'solid-js' import { apiClient } from '../../graphql/client/core' import { Author, QueryLoad_Authors_ByArgs } from '../../graphql/schema/core.gen' diff --git a/src/utils/apiClient.ts b/src/utils/apiClient.ts deleted file mode 100644 index ed0dbcc1..00000000 --- a/src/utils/apiClient.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { searchUrl } from './config' - -type ApiErrorCode = - | 'unknown' - | 'email_not_confirmed' - | 'user_not_found' - | 'user_already_exists' - | 'token_expired' - | 'token_invalid' - | 'duplicate_slug' - -export class ApiError extends Error { - code: ApiErrorCode - - constructor(code: ApiErrorCode, message?: string) { - super(message) - this.code = code - } -} - -export const apiClient = { - getSearchResults: async (searchValue: string) => { - return await fetch(`${searchUrl}/search?q=${searchValue}`, { - method: 'GET', - headers: { - accept: 'application/json', - 'content-type': 'application/json; charset=utf-8', - }, - }) - }, -} From f77d7b28df2ccaf851cfa32490404c059584fab3 Mon Sep 17 00:00:00 2001 From: Untone Date: Thu, 25 Jan 2024 22:16:38 +0300 Subject: [PATCH 53/88] postmerge-2 --- src/components/Editor/Editor.tsx | 2 +- .../Nav/SearchModal/SearchModal.tsx | 76 +++++++++---------- .../_shared/InviteMembers/InviteMembers.tsx | 4 +- src/stores/zine/articles.ts | 2 +- src/utils/sortby.ts | 10 +++ 5 files changed, 50 insertions(+), 44 deletions(-) diff --git a/src/components/Editor/Editor.tsx b/src/components/Editor/Editor.tsx index dafaa7f0..211d22e8 100644 --- a/src/components/Editor/Editor.tsx +++ b/src/components/Editor/Editor.tsx @@ -356,7 +356,7 @@ export const Editor = (props: Props) => { }) onCleanup(() => { - editor().destroy() + editor()?.destroy() }) return ( diff --git a/src/components/Nav/SearchModal/SearchModal.tsx b/src/components/Nav/SearchModal/SearchModal.tsx index a0295f5f..3c786608 100644 --- a/src/components/Nav/SearchModal/SearchModal.tsx +++ b/src/components/Nav/SearchModal/SearchModal.tsx @@ -3,7 +3,6 @@ import type { Shout } from '../../../graphql/schema/core.gen' import { createSignal, Show, For } from 'solid-js' import { useLocalize } from '../../../context/localize' -import { apiClient } from '../../../graphql/client/core' import { Button } from '../../_shared/Button' import { Icon } from '../../_shared/Icon' import { FEED_PAGE_SIZE } from '../../Views/Feed/Feed' @@ -11,6 +10,9 @@ import { FEED_PAGE_SIZE } from '../../Views/Feed/Feed' import { SearchResultItem } from './SearchResultItem' import styles from './SearchModal.module.scss' +import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll' +import { loadShoutsSearch, useArticlesStore } from '../../../stores/zine/articles' +import { byScore } from '../../../utils/sortby' // @@TODO handle empty article options after backend support (subtitle, cover, etc.) // @@TODO implement load more @@ -48,40 +50,38 @@ const prepareSearchResults = (list, searchValue) => export const SearchModal = () => { const { t } = useLocalize() - + const { sortedArticles } = useArticlesStore() + const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) + const [offset, setOffset] = createSignal(0) const [inputValue, setInputValue] = createSignal('') - const [searchResultsList, setSearchResultsList] = createSignal<[] | null>([]) + //const [searchResultsList, setSearchResultsList] = createSignal<[] | null>([]) const [isLoading, setIsLoading] = createSignal(false) // const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) - const handleSearch = async () => { - const searchValue = inputValue() || '' + let searchEl: HTMLInputElement + const handleQueryChange = async (_ev) => { + setInputValue(searchEl.value) - if (Boolean(searchValue) && searchValue.length > 2) { - setIsLoading(true) + if (inputValue() && inputValue().length > 2) await loadMore() + } - try { - // TODO: use offset to load more - const response = await apiClient.getShoutsSearch({ - text: searchValue, - limit: FEED_PAGE_SIZE, - offset: 0, - }) - const searchResult = await response.json() - - if (searchResult.length > 0) { - const preparedSearchResultsList = prepareSearchResults(searchResult, searchValue) - - setSearchResultsList(preparedSearchResultsList) - } else { - setSearchResultsList(null) - } - } catch (error) { - console.log('search request failed', error) - } finally { - setIsLoading(false) - } + const loadMore = async () => { + setIsLoading(true) + saveScrollPosition() + if (inputValue() && inputValue().length > 2) { + console.log(inputValue()) + const { hasMore } = await loadShoutsSearch({ + text: inputValue(), + offset: offset(), + limit: FEED_PAGE_SIZE, + }) + setIsLoadMoreButtonVisible(hasMore) + setOffset(offset() + FEED_PAGE_SIZE) + } else { + console.warn('[SaerchView] no query found') } + restoreScrollPosition() + setIsLoading(false) } return ( @@ -90,16 +90,13 @@ export const SearchModal = () => { type="search" placeholder={t('Site search')} class={styles.searchInput} - onInput={(event) => { - setInputValue(event.target.value) - - handleSearch() - }} + onInput={handleQueryChange} + ref={searchEl} />

    - */} + - +

    diff --git a/src/components/_shared/InviteMembers/InviteMembers.tsx b/src/components/_shared/InviteMembers/InviteMembers.tsx index 408ffbdd..62940bde 100644 --- a/src/components/_shared/InviteMembers/InviteMembers.tsx +++ b/src/components/_shared/InviteMembers/InviteMembers.tsx @@ -60,8 +60,8 @@ export const InviteMembers = (props: Props) => { }) const start = page * PAGE_SIZE const end = start + PAGE_SIZE - const authors = authorsToInvite().map((author) => ({ ...author, selected: false })) - return authors.slice(start, end) + const authors = authorsToInvite()?.map((author) => ({ ...author, selected: false })) + return authors?.slice(start, end) } const [pages, infiniteScrollLoader, { end }] = createInfiniteScroll(fetcher) diff --git a/src/stores/zine/articles.ts b/src/stores/zine/articles.ts index c2293a27..f7cb9ae6 100644 --- a/src/stores/zine/articles.ts +++ b/src/stores/zine/articles.ts @@ -22,7 +22,7 @@ const [topMonthArticles, setTopMonthArticles] = createSignal([]) const articlesByAuthor = createLazyMemo(() => { return Object.values(articleEntities()).reduce( (acc, article) => { - article.authors.forEach((author) => { + article.authors?.forEach((author) => { if (!acc[author.slug]) { acc[author.slug] = [] } diff --git a/src/utils/sortby.ts b/src/utils/sortby.ts index 99112afd..f6d88df6 100644 --- a/src/utils/sortby.ts +++ b/src/utils/sortby.ts @@ -40,6 +40,16 @@ export const byTopicStatDesc = (metric: keyof TopicStat) => { } } +export const byScore = () => { + return (a, b) => { + const x = a?.score || 0 + const y = b?.score || 0 + if (x > y) return -1 + if (x < y) return 1 + return 0 + } +} + export const sortBy = (data, metric) => { const x = [...data] x.sort(typeof metric === 'function' ? metric : byStat(metric)) From a2d72409f240e69dc3a519aa3c6b852f5d16f5f2 Mon Sep 17 00:00:00 2001 From: Untone Date: Fri, 26 Jan 2024 03:22:36 +0300 Subject: [PATCH 54/88] inbox-provider-rewrap --- src/components/App.tsx | 5 ++++- src/pages/inbox.page.tsx | 5 +---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index dfc2be5d..d04fef14 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -42,6 +42,7 @@ import { SearchPage } from '../pages/search.page' import { TopicPage } from '../pages/topic.page' import { ROUTES, useRouter } from '../stores/router' import { hideModal, MODALS, showModal } from '../stores/ui' +import { InboxProvider } from '../context/inbox' // TODO: lazy load // const SomePage = lazy(() => import('./Pages/SomePage')) @@ -124,7 +125,9 @@ export const App = (props: Props) => { - + + + diff --git a/src/pages/inbox.page.tsx b/src/pages/inbox.page.tsx index 5b9a9b42..7bde26df 100644 --- a/src/pages/inbox.page.tsx +++ b/src/pages/inbox.page.tsx @@ -5,7 +5,6 @@ import { createSignal, onMount } from 'solid-js' import { PageLayout } from '../components/_shared/PageLayout' import { ShowOnlyOnClient } from '../components/_shared/ShowOnlyOnClient' import { InboxView } from '../components/Views/Inbox/Inbox' -import { InboxProvider } from '../context/inbox' import { useLocalize } from '../context/localize' import { loadAllAuthors } from '../stores/zine/authors' @@ -24,9 +23,7 @@ export const InboxPage = (props: PageProps) => { return ( - - - + ) From 1094a2de6f12fc9f12c601d47d5269797adb4153 Mon Sep 17 00:00:00 2001 From: Untone Date: Fri, 26 Jan 2024 03:50:04 +0300 Subject: [PATCH 55/88] edit-fix --- src/components/Views/Edit.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Views/Edit.tsx b/src/components/Views/Edit.tsx index 499b0a9d..4110971f 100644 --- a/src/components/Views/Edit.tsx +++ b/src/components/Views/Edit.tsx @@ -182,7 +182,7 @@ export const EditView = (props: Props) => { const hasChanges = !deepEqual(form, prevForm) if (hasChanges) { setSaving(true) - if (props.shout.visibility === ShoutVisibility.Authors) { + if (props.shout?.visibility === ShoutVisibility.Authors) { await saveDraft(form) } else { saveDraftToLocalStorage(form) From 5a47db8430378b036c100681227d74297e782f71 Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Sat, 27 Jan 2024 09:21:48 +0300 Subject: [PATCH 56/88] Fix modal window --- public/locales/en/translation.json | 1 + public/locales/ru/translation.json | 1 + src/components/App.tsx | 4 +-- src/components/Article/CommentsTree.tsx | 4 +-- .../Author/AuthorCard/AuthorCard.tsx | 4 +-- src/components/Nav/AuthModal/LoginForm.tsx | 8 ++--- .../AuthModal/PasswordField/PasswordField.tsx | 7 ++-- src/components/Nav/AuthModal/RegisterForm.tsx | 32 +++++++++++++------ src/components/Nav/HeaderAuth.tsx | 2 +- src/components/Nav/ProfilePopup.tsx | 2 +- .../_shared/InviteMembers/InviteMembers.tsx | 8 +++-- src/pages/types.ts | 2 +- src/stores/router.ts | 5 +++ src/stores/ui.ts | 7 ++-- 14 files changed, 57 insertions(+), 30 deletions(-) diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 336a8237..62db14b5 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -405,6 +405,7 @@ "Upload userpic": "Upload userpic", "Upload video": "Upload video", "Uploading image": "Uploading image", + "User with this email already exists": "User with this email already exists", "Username": "Username", "Userpic": "Userpic", "Users": "Users", diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index a06c7c81..b90b3abb 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -427,6 +427,7 @@ "Upload userpic": "Загрузить аватар", "Upload video": "Загрузить видео", "Uploading image": "Загружаем изображение", + "User with this email already exists": "Пользователь с таким email уже существует", "Username": "Имя пользователя", "Userpic": "Аватар", "Users": "Пользователи", diff --git a/src/components/App.tsx b/src/components/App.tsx index dfc2be5d..5aee1855 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -92,11 +92,11 @@ export const App = (props: Props) => { let is404 = props.is404 createEffect(() => { - if (!searchParams().modal) { + if (!searchParams().m) { hideModal() } - const modal = MODALS[searchParams().modal] + const modal = MODALS[searchParams().m] if (modal) { showModal(modal) } diff --git a/src/components/Article/CommentsTree.tsx b/src/components/Article/CommentsTree.tsx index b0bb86f4..436b5988 100644 --- a/src/components/Article/CommentsTree.tsx +++ b/src/components/Article/CommentsTree.tsx @@ -172,11 +172,11 @@ export const CommentsTree = (props: Props) => { fallback={

    {t('To write a comment, you must')}{' '} - + {t('sign up')} {' '} {t('or')}  - + {t('sign in')}
    diff --git a/src/components/Author/AuthorCard/AuthorCard.tsx b/src/components/Author/AuthorCard/AuthorCard.tsx index f8100e00..587dd564 100644 --- a/src/components/Author/AuthorCard/AuthorCard.tsx +++ b/src/components/Author/AuthorCard/AuthorCard.tsx @@ -142,7 +142,7 @@ export const AuthorCard = (props: Props) => { > - handlePasswordInput(value)} /> + handlePasswordInput(value)} />
    - +
    {error()}
    diff --git a/src/components/Nav/AuthModal/RegisterForm.tsx b/src/components/Nav/AuthModal/RegisterForm.tsx index 7ce83e3e..24d1477d 100644 --- a/src/components/Nav/AuthModal/RegisterForm.tsx +++ b/src/components/Nav/AuthModal/RegisterForm.tsx @@ -118,13 +118,29 @@ export const RegisterForm = () => { setIsSuccess(true) } catch (error) { console.error(error) - - // TODO: move to context/session - if (error?.code === 'user_already_exists') { - return + if (error) { + if (error.message.includes('has already signed up')) { + setValidationErrors((errors) => ({ + ...errors, + email: ( + <> + {t('User with this email already exists')},{' '} + + changeSearchParams({ + mode: 'login', + }) + } + > + {t('sign in')} + + + ), + })) + } + console.error(error) } - - setSubmitError(error.message) } finally { setIsSubmitting(false) } @@ -138,9 +154,7 @@ export const RegisterForm = () => {
    -
      -
    • {submitError()}
    • -
    +
    {submitError()}
    { when={isAuthenticatedControlsVisible()} fallback={
    - + {t('Enter')} {/**/} diff --git a/src/components/Nav/ProfilePopup.tsx b/src/components/Nav/ProfilePopup.tsx index 56f1a5e3..736a763a 100644 --- a/src/components/Nav/ProfilePopup.tsx +++ b/src/components/Nav/ProfilePopup.tsx @@ -29,7 +29,7 @@ export const ProfilePopup = (props: ProfilePopupProps) => { {t('Drafts')}
  • - + {t('Subscriptions')}
  • diff --git a/src/components/_shared/InviteMembers/InviteMembers.tsx b/src/components/_shared/InviteMembers/InviteMembers.tsx index 408ffbdd..fae439a4 100644 --- a/src/components/_shared/InviteMembers/InviteMembers.tsx +++ b/src/components/_shared/InviteMembers/InviteMembers.tsx @@ -41,7 +41,9 @@ export const InviteMembers = (props: Props) => { ] const { sortedAuthors } = useAuthorsStore({ sortBy: 'name' }) - const { actions } = useInbox() + const { + actions: { loadChats, createChat }, + } = useInbox() const [authorsToInvite, setAuthorsToInvite] = createSignal() const [searchResultAuthors, setSearchResultAuthors] = createSignal() @@ -99,10 +101,10 @@ export const InviteMembers = (props: Props) => { const handleCreate = async () => { try { - const initChat = await actions.createChat(collectionToInvite(), 'chat Title') + const initChat = await createChat(collectionToInvite(), 'chat Title') console.debug('[components.Inbox] create chat result:', initChat) hideModal() - await actions.loadChats() + await loadChats() } catch (error) { console.error('handleCreate chat', error) } diff --git a/src/pages/types.ts b/src/pages/types.ts index 627b5bda..c54208c1 100644 --- a/src/pages/types.ts +++ b/src/pages/types.ts @@ -23,7 +23,7 @@ export type PageProps = { } export type RootSearchParams = { - modal: string + m: string // modal lang: string } diff --git a/src/stores/router.ts b/src/stores/router.ts index a9409c68..be197bd1 100644 --- a/src/stores/router.ts +++ b/src/stores/router.ts @@ -152,9 +152,14 @@ export const useRouter = = Record< searchParamsStore.open(newSearchParams, replace) } + const clearSearchParams = (replace = false) => { + searchParamsStore.open({}, replace) + } + return { page, searchParams, changeSearchParams, + clearSearchParams, } } diff --git a/src/stores/ui.ts b/src/stores/ui.ts index 4c8fadc1..039176d4 100644 --- a/src/stores/ui.ts +++ b/src/stores/ui.ts @@ -46,7 +46,7 @@ export const MODALS: Record = { const [modal, setModal] = createSignal(null) -const { changeSearchParams } = useRouter< +const { changeSearchParams, clearSearchParams } = useRouter< AuthModalSearchParams & ConfirmEmailSearchParams & RootSearchParams >() @@ -60,7 +60,10 @@ export const showModal = (modalType: ModalType, modalSource?: AuthModalSource) = setModal(modalType) } -export const hideModal = () => setModal(null) +export const hideModal = () => { + clearSearchParams() + setModal(null) +} export const useModalStore = () => { return { From 2b1342bff0b897e9b66045aa8cf6ab5a17feb7c8 Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Sat, 27 Jan 2024 09:23:01 +0300 Subject: [PATCH 57/88] Fix modal window --- src/components/AuthGuard/AuthGuard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AuthGuard/AuthGuard.tsx b/src/components/AuthGuard/AuthGuard.tsx index a7ef1ff8..86b10f95 100644 --- a/src/components/AuthGuard/AuthGuard.tsx +++ b/src/components/AuthGuard/AuthGuard.tsx @@ -26,7 +26,7 @@ export const AuthGuard = (props: Props) => { changeSearchParams( { source: 'authguard', - modal: 'auth', + m: 'auth', }, true, ) From 796072eb184d8be9fa2013c23dc676b468f6ac5d Mon Sep 17 00:00:00 2001 From: kvakazyambra Date: Sat, 27 Jan 2024 13:19:01 +0300 Subject: [PATCH 58/88] Fixed link selection height in the editor (#379) --- src/components/Editor/Prosemirror.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Editor/Prosemirror.scss b/src/components/Editor/Prosemirror.scss index ca78c9f1..a28ee8db 100644 --- a/src/components/Editor/Prosemirror.scss +++ b/src/components/Editor/Prosemirror.scss @@ -316,5 +316,5 @@ footnote { background: var(--selection-background); color: var(--selection-color); border: solid var(--selection-background); - border-width: 5px 0; + border-width: 0; } From ef49e4b971f78949c758f9b191ea90ec03c3cde9 Mon Sep 17 00:00:00 2001 From: dog Date: Sat, 27 Jan 2024 14:41:00 +0300 Subject: [PATCH 59/88] limit cropper container height & fix t --- public/locales/ru/translation.json | 2 +- src/components/_shared/ImageCropper/ImageCropper.module.scss | 4 ++++ src/components/_shared/ImageCropper/ImageCropper.tsx | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index ab5481e8..971e2067 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -109,7 +109,7 @@ "Create gallery": "Создать галерею", "Create post": "Создать публикацию", "Create video": "Создать видео", - "Crop image": "Скадрируйте изображение", + "Crop image": "Кадрировать изображение", "Culture": "Культура", "Date of Birth": "Дата рождения", "Decline": "Отмена", diff --git a/src/components/_shared/ImageCropper/ImageCropper.module.scss b/src/components/_shared/ImageCropper/ImageCropper.module.scss index 19d5ff12..51e4dd01 100644 --- a/src/components/_shared/ImageCropper/ImageCropper.module.scss +++ b/src/components/_shared/ImageCropper/ImageCropper.module.scss @@ -1,3 +1,7 @@ +.cropperContainer { + max-height: 55vh; +} + .cropperControls { display: flex; justify-content: space-between; diff --git a/src/components/_shared/ImageCropper/ImageCropper.tsx b/src/components/_shared/ImageCropper/ImageCropper.tsx index 1d5caded..6e2646f8 100644 --- a/src/components/_shared/ImageCropper/ImageCropper.tsx +++ b/src/components/_shared/ImageCropper/ImageCropper.tsx @@ -34,6 +34,7 @@ export const ImageCropper = (props: CropperProps) => { guides: false, background: false, rotatable: false, + autoCropArea: 1, modal: true, }), ) @@ -42,7 +43,7 @@ export const ImageCropper = (props: CropperProps) => { return (
    -
    +
    (imageTagRef.current = el)} src={props.uploadFile.source} From 0bca6d73b18d6d34740838b16010b66cb9476112 Mon Sep 17 00:00:00 2001 From: Untone Date: Sun, 28 Jan 2024 08:57:05 +0300 Subject: [PATCH 60/88] search-using-resource --- .../Nav/SearchModal/SearchModal.tsx | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/src/components/Nav/SearchModal/SearchModal.tsx b/src/components/Nav/SearchModal/SearchModal.tsx index 3c786608..85176702 100644 --- a/src/components/Nav/SearchModal/SearchModal.tsx +++ b/src/components/Nav/SearchModal/SearchModal.tsx @@ -1,8 +1,12 @@ import type { Shout } from '../../../graphql/schema/core.gen' -import { createSignal, Show, For } from 'solid-js' +import { createResource, createSignal, For, Show } from 'solid-js' +import { debounce } from 'throttle-debounce' import { useLocalize } from '../../../context/localize' +import { loadShoutsSearch } from '../../../stores/zine/articles' +// import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll' +import { byScore } from '../../../utils/sortby' import { Button } from '../../_shared/Button' import { Icon } from '../../_shared/Icon' import { FEED_PAGE_SIZE } from '../../Views/Feed/Feed' @@ -10,13 +14,11 @@ import { FEED_PAGE_SIZE } from '../../Views/Feed/Feed' import { SearchResultItem } from './SearchResultItem' import styles from './SearchModal.module.scss' -import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll' -import { loadShoutsSearch, useArticlesStore } from '../../../stores/zine/articles' -import { byScore } from '../../../utils/sortby' // @@TODO handle empty article options after backend support (subtitle, cover, etc.) // @@TODO implement load more // @@TODO implement FILTERS & TOPICS +// @@TODO use save/restoreScrollPosition if needed const getSearchCoincidences = ({ str, intersection }: { str: string; intersection: string }) => `${str.replaceAll( @@ -24,16 +26,16 @@ const getSearchCoincidences = ({ str, intersection }: { str: string; intersectio (casePreservedMatch) => `${casePreservedMatch}`, )}` -const prepareSearchResults = (list, searchValue) => - list.map((article, index) => ({ +const prepareSearchResults = (list: Shout[], searchValue: string) => + list.sort(byScore()).map((article, index) => ({ ...article, - body: '', - cover: '', - createdAt: '', + body: article.body, + cover: article.cover, + created_at: article.created_at, id: index, slug: article.slug, - authors: [], - topics: [], + authors: article.authors, + topics: article.topics, title: article.title ? getSearchCoincidences({ str: article.title, @@ -50,38 +52,35 @@ const prepareSearchResults = (list, searchValue) => export const SearchModal = () => { const { t } = useLocalize() - const { sortedArticles } = useArticlesStore() const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) - const [offset, setOffset] = createSignal(0) const [inputValue, setInputValue] = createSignal('') - //const [searchResultsList, setSearchResultsList] = createSignal<[] | null>([]) const [isLoading, setIsLoading] = createSignal(false) - // const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) - - let searchEl: HTMLInputElement - const handleQueryChange = async (_ev) => { - setInputValue(searchEl.value) - - if (inputValue() && inputValue().length > 2) await loadMore() - } - - const loadMore = async () => { - setIsLoading(true) - saveScrollPosition() - if (inputValue() && inputValue().length > 2) { - console.log(inputValue()) - const { hasMore } = await loadShoutsSearch({ - text: inputValue(), - offset: offset(), + const [searchResultsList, { refetch: loadSearchResults, mutate: setSearchResultsList }] = createResource< + Shout[] + >( + async () => { + setIsLoading(true) + const { hasMore, newShouts } = await loadShoutsSearch({ limit: FEED_PAGE_SIZE, + text: inputValue(), + offset: searchResultsList().length, }) setIsLoadMoreButtonVisible(hasMore) - setOffset(offset() + FEED_PAGE_SIZE) - } else { - console.warn('[SaerchView] no query found') - } - restoreScrollPosition() - setIsLoading(false) + return newShouts + }, + { + ssrLoadFrom: 'initial', + initialValue: [], + }, + ) + + let searchEl: HTMLInputElement + const debouncedLoadMore = debounce(500, loadSearchResults) + const handleQueryInput = () => { + const inp = searchEl.value + setInputValue(inp) + if (inp?.length > 2) debouncedLoadMore() + else setSearchResultsList([]) } return ( @@ -90,13 +89,14 @@ export const SearchModal = () => { type="search" placeholder={t('Site search')} class={styles.searchInput} - onInput={handleQueryChange} + onInput={handleQueryInput} + onChange={debouncedLoadMore} ref={searchEl} />

    - +

    From b866af2ff79537b6b57be4eb002f611e32f84a85 Mon Sep 17 00:00:00 2001 From: Untone Date: Sun, 28 Jan 2024 10:06:31 +0300 Subject: [PATCH 61/88] reasource-based-search-results-load --- .../Feed/ArticleCard/ArticleCard.tsx | 1 + src/components/Nav/Header/Header.tsx | 3 -- src/components/Nav/HeaderAuth.tsx | 2 +- .../Nav/SearchModal/SearchModal.tsx | 41 +++++++++++++++---- src/utils/apiClient.ts | 0 5 files changed, 34 insertions(+), 13 deletions(-) delete mode 100644 src/utils/apiClient.ts diff --git a/src/components/Feed/ArticleCard/ArticleCard.tsx b/src/components/Feed/ArticleCard/ArticleCard.tsx index a6a9939d..d2c15c13 100644 --- a/src/components/Feed/ArticleCard/ArticleCard.tsx +++ b/src/components/Feed/ArticleCard/ArticleCard.tsx @@ -2,6 +2,7 @@ import type { Author, Shout, Topic } from '../../../graphql/schema/core.gen' import { getPagePath, openPage } from '@nanostores/router' import { clsx } from 'clsx' +import { createMemo, createSignal, For, Show } from 'solid-js' import { useLocalize } from '../../../context/localize' import { useSession } from '../../../context/session' diff --git a/src/components/Nav/Header/Header.tsx b/src/components/Nav/Header/Header.tsx index 0b6a75ee..fb597f05 100644 --- a/src/components/Nav/Header/Header.tsx +++ b/src/components/Nav/Header/Header.tsx @@ -4,8 +4,6 @@ import { getPagePath, redirectPage } from '@nanostores/router' import { clsx } from 'clsx' import { Show, createSignal, createEffect, onMount, onCleanup, For } from 'solid-js' -import { apiClient } from '../../../utils/apiClient' - import { useLocalize } from '../../../context/localize' import { useSession } from '../../../context/session' import { apiClient } from '../../../graphql/client/core' @@ -22,7 +20,6 @@ import { HeaderAuth } from '../HeaderAuth' import { Modal } from '../Modal' import { SearchModal } from '../SearchModal/SearchModal' import { Snackbar } from '../Snackbar' -import { SearchModal } from '../SearchModal/SearchModal' import { Link } from './Link' diff --git a/src/components/Nav/HeaderAuth.tsx b/src/components/Nav/HeaderAuth.tsx index fb8ee22a..d8ca5f6b 100644 --- a/src/components/Nav/HeaderAuth.tsx +++ b/src/components/Nav/HeaderAuth.tsx @@ -128,7 +128,7 @@ export const HeaderAuth = (props: Props) => {

    - + diff --git a/src/components/Nav/SearchModal/SearchModal.tsx b/src/components/Nav/SearchModal/SearchModal.tsx index 85176702..781dea50 100644 --- a/src/components/Nav/SearchModal/SearchModal.tsx +++ b/src/components/Nav/SearchModal/SearchModal.tsx @@ -1,6 +1,6 @@ import type { Shout } from '../../../graphql/schema/core.gen' -import { createResource, createSignal, For, Show } from 'solid-js' +import { createEffect, createResource, createSignal, For, onCleanup, Show } from 'solid-js' import { debounce } from 'throttle-debounce' import { useLocalize } from '../../../context/localize' @@ -55,6 +55,7 @@ export const SearchModal = () => { const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) const [inputValue, setInputValue] = createSignal('') const [isLoading, setIsLoading] = createSignal(false) + const [offset, setOffset] = createSignal(0) const [searchResultsList, { refetch: loadSearchResults, mutate: setSearchResultsList }] = createResource< Shout[] >( @@ -63,8 +64,10 @@ export const SearchModal = () => { const { hasMore, newShouts } = await loadShoutsSearch({ limit: FEED_PAGE_SIZE, text: inputValue(), - offset: searchResultsList().length, + offset: offset(), }) + setIsLoading(false) + setOffset(newShouts.length) setIsLoadMoreButtonVisible(hasMore) return newShouts }, @@ -76,13 +79,33 @@ export const SearchModal = () => { let searchEl: HTMLInputElement const debouncedLoadMore = debounce(500, loadSearchResults) - const handleQueryInput = () => { - const inp = searchEl.value - setInputValue(inp) - if (inp?.length > 2) debouncedLoadMore() - else setSearchResultsList([]) + + const handleQueryInput = async () => { + setInputValue(searchEl.value) + if (searchEl.value?.length > 2) { + await debouncedLoadMore() + } else { + setIsLoading(false) + setSearchResultsList([]) + } } + const enterQuery = async (ev: KeyboardEvent) => { + setIsLoading(true) + if (ev.key === 'Enter' && inputValue().length > 2) { + await debouncedLoadMore() + } else { + setIsLoading(false) + setSearchResultsList([]) + } + } + + // Cleanup the debounce timer when the component unmounts + onCleanup(() => { + debouncedLoadMore.cancel() + console.log('cleanup search') + }) + return (
    { placeholder={t('Site search')} class={styles.searchInput} onInput={handleQueryInput} - onChange={debouncedLoadMore} + onKeyDown={enterQuery} ref={searchEl} /> {props.following.length} -
  • - @@ -300,7 +285,7 @@ export const AuthorCard = (props: Props) => {
    - + {(subscription) => isAuthor(subscription) ? ( diff --git a/src/components/Feed/Row2.tsx b/src/components/Feed/Row2.tsx index 73c5fa70..5fa5a6be 100644 --- a/src/components/Feed/Row2.tsx +++ b/src/components/Feed/Row2.tsx @@ -1,15 +1,10 @@ import type { Shout } from '../../graphql/schema/core.gen' -import { createComputed, createSignal, Show, For } from 'solid-js' +import { createSignal, createEffect, For, Show } from 'solid-js' import { ArticleCard } from './ArticleCard' -import { ArticleCardProps } from './ArticleCard/ArticleCard' -const x = [ - ['12', '12'], - ['8', '16'], - ['16', '8'], -] +const columnSizes = ['col-md-12', 'col-md-8', 'col-md-16'] export const Row2 = (props: { articles: Shout[] @@ -18,10 +13,10 @@ export const Row2 = (props: { noAuthorLink?: boolean noauthor?: boolean }) => { - const [y, setY] = createSignal(0) + const [columnIndex, setColumnIndex] = createSignal(0) - // FIXME: random can break hydration - createComputed(() => setY(Math.floor(Math.random() * x.length))) + // Update column index on component mount + createEffect(() => setColumnIndex(Math.floor(Math.random() * columnSizes.length))) return ( 0}> @@ -29,31 +24,16 @@ export const Row2 = (props: {
    - {(a, i) => { - // FIXME: refactor this, too ugly now - const className = `col-md-${props.isEqual ? '12' : x[y()][i()]}` - let desktopCoverSize: ArticleCardProps['desktopCoverSize'] - - switch (className) { - case 'col-md-8': { - desktopCoverSize = 'S' - break - } - case 'col-md-12': { - desktopCoverSize = 'M' - break - } - default: { - desktopCoverSize = 'L' - } - } - + {(article, _idx) => { + const className = columnSizes[props.isEqual ? 0 : columnIndex() % columnSizes.length] + const big = className === 'col-md-12' ? 'M' : 'L' + const desktopCoverSize = className === 'col-md-8' ? 'S' : big return (
    { const { t } = useLocalize() const { seen } = useSeenStore() - const { subscriptions } = useSession() + const { subscriptions } = useFollowing() const { page } = useRouter() const { articlesByTopic } = useArticlesStore() const [isSubscriptionsVisible, setSubscriptionsVisible] = createSignal(true) @@ -27,7 +28,6 @@ export const Sidebar = () => { const checkAuthorIsSeen = (authorSlug: string) => { return Boolean(seen()[authorSlug]) } - return (
      @@ -111,7 +111,7 @@ export const Sidebar = () => {
    - 0 || subscriptions().topics.length > 0}> + 0 || subscriptions.topics.length > 0}>

    { @@ -122,22 +122,19 @@ export const Sidebar = () => {

      - - {(author) => ( + + {(a: Author) => (
    • - +
      - -
      {author.name}
      + +
      {a.name}
    • )}
      - + {(topic) => (
    • { } onMount(async () => { - const topics = await apiClient.getRandomTopics({ amount: RANDOM_TOPICS_COUNT }) - setRandomTopics(topics) + if (window.location.pathname === '/' || window.location.pathname === '') { + const topics = await apiClient.getRandomTopics({ amount: RANDOM_TOPICS_COUNT }) + setRandomTopics(topics) + } }) const handleToggleMenuByLink = (event: MouseEvent, route: keyof typeof ROUTES) => { diff --git a/src/components/ProfileSettings/ProfileSettings.tsx b/src/components/ProfileSettings/ProfileSettings.tsx index 490c289a..29382f3b 100644 --- a/src/components/ProfileSettings/ProfileSettings.tsx +++ b/src/components/ProfileSettings/ProfileSettings.tsx @@ -38,7 +38,7 @@ export const ProfileSettings = () => { const [addLinkForm, setAddLinkForm] = createSignal(false) const [incorrectUrl, setIncorrectUrl] = createSignal(false) const [isUserpicUpdating, setIsUserpicUpdating] = createSignal(false) - const [userpicFile, setUserpicFile] = createSignal(null) + const [userpicFile, setUserpicFile] = createSignal(null) const [uploadError, setUploadError] = createSignal(false) const [isFloatingPanelVisible, setIsFloatingPanelVisible] = createSignal(false) const [hostname, setHostname] = createSignal(null) diff --git a/src/components/Topic/Card.tsx b/src/components/Topic/Card.tsx index 23dd980e..917aa396 100644 --- a/src/components/Topic/Card.tsx +++ b/src/components/Topic/Card.tsx @@ -1,12 +1,10 @@ -import type { Topic } from '../../graphql/schema/core.gen' - import { clsx } from 'clsx' import { createMemo, createSignal, Show } from 'solid-js' +import { useFollowing } from '../../context/following' import { useLocalize } from '../../context/localize' import { useSession } from '../../context/session' -import { FollowingEntity } from '../../graphql/schema/core.gen' -import { follow, unfollow } from '../../stores/zine/common' +import { FollowingEntity, type Topic } from '../../graphql/schema/core.gen' import { capitalize } from '../../utils/capitalize' import { Button } from '../_shared/Button' import { CheckButton } from '../_shared/CheckButton' @@ -36,32 +34,21 @@ interface TopicProps { export const TopicCard = (props: TopicProps) => { const { t, lang } = useLocalize() + const title = createMemo(() => + capitalize(lang() === 'en' ? props.topic.slug.replaceAll('-', ' ') : props.topic.title || ''), + ) const { - subscriptions, - isSessionLoaded, - actions: { loadSubscriptions, requireAuthentication }, + author, + actions: { requireAuthentication }, } = useSession() + const { setFollowing, loading: subLoading } = useFollowing() + const [followed, setFollowed] = createSignal() - const [isSubscribing, setIsSubscribing] = createSignal(false) - - const subscribed = createMemo(() => { - return subscriptions().topics.some((topic) => topic.slug === props.topic.slug) - }) - - const subscribe = async (really = true) => { - setIsSubscribing(true) - - await (really - ? follow({ what: FollowingEntity.Topic, slug: props.topic.slug }) - : unfollow({ what: FollowingEntity.Topic, slug: props.topic.slug })) - - await loadSubscriptions() - setIsSubscribing(false) - } - - const handleSubscribe = () => { + const handleFollowClick = () => { + const value = !followed() requireAuthentication(() => { - subscribe(!subscribed()) + setFollowed(value) + setFollowing(FollowingEntity.Topic, props.topic.slug, value) }, 'subscribe') } @@ -69,12 +56,12 @@ export const TopicCard = (props: TopicProps) => { return ( <> - + - + {t('Unfollow')} {t('Following')} @@ -83,10 +70,6 @@ export const TopicCard = (props: TopicProps) => { ) } - const title = createMemo(() => - capitalize(lang() === 'en' ? props.topic.slug.replaceAll('-', ' ') : props.topic.title || ''), - ) - return (
      { }} > - + + } >
    • -
    • -
    • diff --git a/src/components/Views/PublishSettings/PublishSettings.tsx b/src/components/Views/PublishSettings/PublishSettings.tsx index b5a144e4..1fe168be 100644 --- a/src/components/Views/PublishSettings/PublishSettings.tsx +++ b/src/components/Views/PublishSettings/PublishSettings.tsx @@ -1,6 +1,6 @@ import { redirectPage } from '@nanostores/router' import { clsx } from 'clsx' -import { createEffect, createSignal, lazy, onMount, Show } from 'solid-js' +import { createEffect, createMemo, createSignal, lazy, onMount, Show } from 'solid-js' import { createStore } from 'solid-js/store' import { ShoutForm, useEditorContext } from '../../../context/editor' @@ -16,7 +16,6 @@ import { Icon } from '../../_shared/Icon' import { Image } from '../../_shared/Image' import { TopicSelect, UploadModalContent } from '../../Editor' import { Modal } from '../../Nav/Modal' -import { EMPTY_TOPIC } from '../Edit' import styles from './PublishSettings.module.scss' import stylesBeside from '../../Feed/Beside.module.scss' @@ -36,21 +35,26 @@ const shorten = (str: string, maxLen: number) => { return `${result}...` } +const EMPTY_TOPIC: Topic = { + id: -1, + slug: '', +} +const emptyConfig = { + coverImageUrl: '', + mainTopic: EMPTY_TOPIC, + slug: '', + title: '', + subtitle: '', + description: '', + selectedTopics: [], +} + export const PublishSettings = (props: Props) => { const { t } = useLocalize() const { author } = useSession() const { sortedTopics } = useTopicsStore() - const [topics, setTopics] = createSignal(sortedTopics()) - onMount(async () => { - await loadAllTopics() - }) - - createEffect(() => { - setTopics(sortedTopics()) - }) - const composeDescription = () => { if (!props.form.description) { const cleanFootnotes = props.form.body.replaceAll(/.*?<\/footnote>/g, '') @@ -60,23 +64,32 @@ export const PublishSettings = (props: Props) => { return props.form.description } - const initialData: Partial = { - coverImageUrl: props.form.coverImageUrl, - mainTopic: props.form.mainTopic || EMPTY_TOPIC, - slug: props.form.slug, - title: props.form.title, - subtitle: props.form.subtitle, - description: composeDescription(), - selectedTopics: [], - } + const initialData = createMemo(() => { + return { + coverImageUrl: props.form?.coverImageUrl, + mainTopic: props.form?.mainTopic || EMPTY_TOPIC, + slug: props.form?.slug, + title: props.form?.title, + subtitle: props.form?.subtitle, + description: composeDescription(), + selectedTopics: [], + } + }) + + const [settingsForm, setSettingsForm] = createStore(emptyConfig) + + onMount(() => { + setSettingsForm(initialData()) + loadAllTopics() + }) + + createEffect(() => setTopics(sortedTopics())) const { formErrors, actions: { setForm, setFormErrors, saveShout, publishShout }, } = useEditorContext() - const [settingsForm, setSettingsForm] = createStore(initialData) - const handleUploadModalContentCloseSetCover = (image: UploadedFile) => { hideModal() setSettingsForm('coverImageUrl', image.url) @@ -110,7 +123,7 @@ export const PublishSettings = (props: Props) => { }) } const handleCancelClick = () => { - setSettingsForm(initialData) + setSettingsForm(initialData()) handleBackClick() } const handlePublishSubmit = () => { @@ -149,9 +162,9 @@ export const PublishSettings = (props: Props) => { [styles.hasImage]: settingsForm.coverImageUrl, })} > - +
      - {initialData.title} + {initialData().title}
      diff --git a/src/components/Views/Topic.tsx b/src/components/Views/Topic.tsx index a6702147..1b3d059a 100644 --- a/src/components/Views/Topic.tsx +++ b/src/components/Views/Topic.tsx @@ -2,7 +2,7 @@ import type { Shout, Topic } from '../../graphql/schema/core.gen' import { Meta } from '@solidjs/meta' import { clsx } from 'clsx' -import { For, Show, createMemo, onMount, createSignal } from 'solid-js' +import { For, Show, createMemo, onMount, createSignal, createEffect } from 'solid-js' import { useLocalize } from '../../context/localize' import { useRouter } from '../../stores/router' @@ -39,23 +39,27 @@ const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3 export const TopicView = (props: Props) => { const { t, lang } = useLocalize() const { searchParams, changeSearchParams } = useRouter() - const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) - const { sortedArticles } = useArticlesStore({ shouts: props.shouts }) const { topicEntities } = useTopicsStore({ topics: [props.topic] }) - const { authorsByTopic } = useAuthorsStore() - const topic = createMemo(() => - props.topic?.slug in topicEntities() ? topicEntities()[props.topic.slug] : props.topic, + const [topic, setTopic] = createSignal() + createEffect(() => { + const topics = topicEntities() + if (props.topicSlug && !topic() && topics) { + setTopic(topics[props.topicSlug]) + } + }) + const title = createMemo( + () => + `#${capitalize( + lang() === 'en' + ? topic()?.slug.replace(/-/, ' ') + : topic()?.title || topic()?.slug.replace(/-/, ' '), + true, + )}`, ) - const title = () => - `#${capitalize( - lang() === 'en' ? topic()?.slug.replace(/-/, ' ') : topic()?.title || topic()?.slug.replace(/-/, ' '), - true, - )}` - onMount(() => (document.title = title())) const loadMore = async () => { saveScrollPosition() diff --git a/src/context/following.tsx b/src/context/following.tsx new file mode 100644 index 00000000..2246485f --- /dev/null +++ b/src/context/following.tsx @@ -0,0 +1,127 @@ +import { createEffect, createSignal, createContext, Accessor, useContext, JSX, onMount } from 'solid-js' +import { createStore } from 'solid-js/store' + +import { apiClient } from '../graphql/client/core' +import { Author, Community, FollowingEntity, Topic } from '../graphql/schema/core.gen' + +import { useSession } from './session' + +type SubscriptionsData = { + topics?: Topic[] + authors?: Author[] + communities?: Community[] +} + +interface FollowingContextType { + loading: Accessor + subscriptions: SubscriptionsData + setSubscriptions: (subscriptions: SubscriptionsData) => void + setFollowing: (what: FollowingEntity, slug: string, value: boolean) => void + loadSubscriptions: () => void + follow: (what: FollowingEntity, slug: string) => Promise + unfollow: (what: FollowingEntity, slug: string) => Promise +} + +const FollowingContext = createContext() + +export function useFollowing() { + return useContext(FollowingContext) +} + +const EMPTY_SUBSCRIPTIONS = { + topics: [], + authors: [], + communities: [], +} + +export const FollowingProvider = (props: { children: JSX.Element }) => { + const [loading, setLoading] = createSignal(false) + const [subscriptions, setSubscriptions] = createStore(EMPTY_SUBSCRIPTIONS) + const { author } = useSession() + + const fetchData = async () => { + setLoading(true) + try { + if (apiClient.private) { + console.debug('[context.following] fetching subs data...') + const result = await apiClient.getMySubscriptions() + setSubscriptions(result || EMPTY_SUBSCRIPTIONS) + console.info('[context.following] subs:', subscriptions) + } + } catch (error) { + console.info('[context.following] cannot get subs', error) + } finally { + setLoading(false) + } + } + + const follow = async (what: FollowingEntity, slug: string) => { + if (!author()) return + try { + await apiClient.follow({ what, slug }) + setSubscriptions((prevSubscriptions) => { + const updatedSubs = { ...prevSubscriptions } + if (!updatedSubs[what]) updatedSubs[what] = [] + const exists = updatedSubs[what]?.some((entity) => entity.slug === slug) + if (!exists) updatedSubs[what].push(slug) + return updatedSubs + }) + } catch (error) { + console.error(error) + } + } + + const unfollow = async (what: FollowingEntity, slug: string) => { + if (!author()) return + try { + await apiClient.unfollow({ what, slug }) + } catch (error) { + console.error(error) + } + } + + const loadData = (_a?: Author) => { + // console.debug('[context.following] current subs:', subscriptions) + if (!subscriptions?.authors?.length && !subscriptions?.topics?.length) { + // && subscriptions.communites?.length + fetchData() + } + } + createEffect(() => { + if (author()) loadData() + }) + onMount(loadData) + + const setFollowing = (what: FollowingEntity, slug: string, value = true) => { + setSubscriptions((prevSubscriptions) => { + const updatedSubs = { ...prevSubscriptions } + if (!updatedSubs[what]) updatedSubs[what] = [] + if (value) { + const exists = updatedSubs[what]?.some((entity) => entity.slug === slug) + if (!exists) updatedSubs[what].push(slug) + } else { + updatedSubs[what] = (updatedSubs[what] || []).filter((x) => x !== slug) + } + return updatedSubs + }) + try { + ;(value ? follow : unfollow)(what, slug) + } catch (error) { + console.error(error) + } finally { + fetchData() + } + } + + const value: FollowingContextType = { + loading, + subscriptions, + setSubscriptions, + setFollowing, + loadSubscriptions: fetchData, + follow, + unfollow, + } + + return {props.children} +} diff --git a/src/context/reactions.tsx b/src/context/reactions.tsx index c98ebcaa..5af22fe2 100644 --- a/src/context/reactions.tsx +++ b/src/context/reactions.tsx @@ -56,7 +56,7 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => { const createReaction = async (input: ReactionInput): Promise => { const reaction = await apiClient.createReaction(input) - + if (!reaction) return const changes = { [reaction.id]: reaction, } diff --git a/src/context/session.tsx b/src/context/session.tsx index 0b872ab4..d637edb9 100644 --- a/src/context/session.tsx +++ b/src/context/session.tsx @@ -1,5 +1,5 @@ import type { AuthModalSource } from '../components/Nav/AuthModal/types' -import type { Author, Result } from '../graphql/schema/core.gen' +import type { Author } from '../graphql/schema/core.gen' import type { Accessor, JSX, Resource } from 'solid-js' import { @@ -41,19 +41,17 @@ const defaultConfig: ConfigType = { } export type SessionContextType = { - config: ConfigType + config: Accessor session: Resource author: Resource authError: Accessor isSessionLoaded: Accessor - subscriptions: Accessor isAuthenticated: Accessor actions: { loadSession: () => AuthToken | Promise setSession: (token: AuthToken | null) => void // setSession loadAuthor: (info?: unknown) => Author | Promise setAuthor: (a: Author) => void - loadSubscriptions: () => Promise requireAuthentication: ( callback: (() => Promise) | (() => void), modalSource: AuthModalSource, @@ -77,11 +75,6 @@ export function useSession() { return useContext(SessionContext) } -const EMPTY_SUBSCRIPTIONS = { - topics: [], - authors: [], -} - export const SessionProvider = (props: { onStateChangeCallback(state: AuthToken): unknown children: JSX.Element @@ -91,12 +84,12 @@ export const SessionProvider = (props: { actions: { showSnackbar }, } = useSnackbar() const { searchParams, changeSearchParams } = useRouter() - const [configuration, setConfig] = createSignal(defaultConfig) - const authorizer = createMemo(() => new Authorizer(configuration())) + const [config, setConfig] = createSignal(defaultConfig) + const authorizer = createMemo(() => new Authorizer(config())) const [oauthState, setOauthState] = createSignal() // handle callback's redirect_uri - createEffect(async () => { + createEffect(() => { // oauth const state = searchParams()?.state if (state) { @@ -120,43 +113,44 @@ export const SessionProvider = (props: { }) // load - let minuteLater + let minuteLater: NodeJS.Timeout | null const [isSessionLoaded, setIsSessionLoaded] = createSignal(false) const [authError, setAuthError] = createSignal('') - const [session, { refetch: loadSession, mutate: setSession }] = createResource( - async () => { - try { - const s = await authorizer().getSession() - console.info('[context.session] loading session', s) - // Set session expiration time in local storage - const expires_at = new Date(Date.now() + s.expires_in * 1000) - localStorage.setItem('expires_at', `${expires_at.getTime()}`) + // Function to load session data + const sessionData = async () => { + try { + const s = await authorizer().getSession() + console.info('[context.session] loading session', s) - // Set up session expiration check timer - minuteLater = setTimeout(checkSessionIsExpired, 60 * 1000) - console.info(`[context.session] will refresh in ${s.expires_in / 60} mins`) + // Set session expiration time in local storage + const expires_at = new Date(Date.now() + s.expires_in * 1000) + localStorage.setItem('expires_at', `${expires_at.getTime()}`) - // Set the session loaded flag - setIsSessionLoaded(true) + // Set up session expiration check timer + minuteLater = setTimeout(checkSessionIsExpired, 60 * 1000) + console.info(`[context.session] will refresh in ${s.expires_in / 60} mins`) - return s - } catch (error) { - console.info('[context.session] cannot refresh session', error) - setAuthError(error) + // Set the session loaded flag + setIsSessionLoaded(true) - // Set the session loaded flag even if there's an error - setIsSessionLoaded(true) + return s + } catch (error) { + console.info('[context.session] cannot refresh session', error) + setAuthError(error) - return null - } - }, - { - ssrLoadFrom: 'initial', - initialValue: null, - }, - ) + // Set the session loaded flag even if there's an error + setIsSessionLoaded(true) + + return null + } + } + + const [session, { refetch: loadSession, mutate: setSession }] = createResource(sessionData, { + ssrLoadFrom: 'initial', + initialValue: null, + }) const checkSessionIsExpired = () => { const expires_at_data = localStorage.getItem('expires_at') @@ -177,26 +171,17 @@ export const SessionProvider = (props: { } onCleanup(() => clearTimeout(minuteLater)) - - const [author, { refetch: loadAuthor, mutate: setAuthor }] = createResource( - async () => { - const u = session()?.user - return u ? (await apiClient.getAuthorId({ user: u.id.trim() })) || null : null - }, - { - ssrLoadFrom: 'initial', - initialValue: null, - }, - ) - - const [subscriptions, setSubscriptions] = createSignal(EMPTY_SUBSCRIPTIONS) - const loadSubscriptions = async (): Promise => { - const result = await apiClient.getMySubscriptions() - setSubscriptions(result || EMPTY_SUBSCRIPTIONS) + const authorData = async () => { + const u = session()?.user + return u ? (await apiClient.getAuthorId({ user: u.id.trim() })) || null : null } + const [author, { refetch: loadAuthor, mutate: setAuthor }] = createResource(authorData, { + ssrLoadFrom: 'initial', + initialValue: null, + }) // when session is loaded - createEffect(async () => { + createEffect(() => { if (session()) { const token = session()?.access_token if (token) { @@ -206,23 +191,24 @@ export const SessionProvider = (props: { notifierClient.connect(token) inboxClient.connect(token) } - if (!author()) { - const a = await loadAuthor() - if (a) { - await loadSubscriptions() - addAuthors([a]) - } else { - reset() - } - } + if (!author()) loadAuthor() + setIsSessionLoaded(true) } } }) + // when author is loaded + createEffect(() => { + if (author()) { + addAuthors([author()]) + } else { + reset() + } + }) + const reset = () => { setIsSessionLoaded(true) - setSubscriptions(EMPTY_SUBSCRIPTIONS) setSession(null) setAuthor(null) } @@ -252,10 +238,10 @@ export const SessionProvider = (props: { ) const [authCallback, setAuthCallback] = createSignal<() => void>(() => {}) - const requireAuthentication = async (callback: () => void, modalSource: AuthModalSource) => { + const requireAuthentication = (callback: () => void, modalSource: AuthModalSource) => { setAuthCallback((_cb) => callback) if (!session()) { - await loadSession() + loadSession() if (!session()) { showModal('auth', modalSource) } @@ -323,7 +309,6 @@ export const SessionProvider = (props: { const isAuthenticated = createMemo(() => Boolean(author())) const actions = { loadSession, - loadSubscriptions, requireAuthentication, signUp, signIn, @@ -339,9 +324,8 @@ export const SessionProvider = (props: { } const value: SessionContextType = { authError, - config: configuration(), + config, session, - subscriptions, isSessionLoaded, author, actions, diff --git a/src/graphql/client/core.ts b/src/graphql/client/core.ts index 38ed9705..04e8acf6 100644 --- a/src/graphql/client/core.ts +++ b/src/graphql/client/core.ts @@ -12,6 +12,7 @@ import type { QueryLoad_Authors_ByArgs, QueryLoad_Shouts_SearchArgs, QueryLoad_Shouts_Random_TopArgs, + Community, } from '../schema/core.gen' import { createGraphQLClient } from '../createGraphQLClient' @@ -37,20 +38,24 @@ import authorBy from '../query/core/author-by' import authorFollowers from '../query/core/author-followers' import authorId from '../query/core/author-id' import authorsAll from '../query/core/authors-all' -import authorFollowed from '../query/core/authors-followed-by' import authorsLoadBy from '../query/core/authors-load-by' import mySubscriptions from '../query/core/my-followed' import reactionsLoadBy from '../query/core/reactions-load-by' import topicBySlug from '../query/core/topic-by-slug' import topicsAll from '../query/core/topics-all' -import userFollowedTopics from '../query/core/topics-by-author' +import authorFollowedAuthors from '../query/core/authors-followed-by' +import authorFollowedTopics from '../query/core/topics-followed-by' +import authorFollowedCommunities from '../query/core/communities-followed-by' import topicsRandomQuery from '../query/core/topics-random' const publicGraphQLClient = createGraphQLClient('core') export const apiClient = { private: null, - connect: (token: string) => (apiClient.private = createGraphQLClient('core', token)), // NOTE: use it after token appears + connect: (token: string) => { + // NOTE: use it after token appears + apiClient.private = createGraphQLClient('core', token) + }, getRandomTopShouts: async (params: QueryLoad_Shouts_Random_TopArgs) => { const response = await publicGraphQLClient.query(loadShoutsTopRandom, params).toPromise() @@ -119,14 +124,18 @@ export const apiClient = { const response = await publicGraphQLClient.query(authorFollowers, { slug }).toPromise() return response.data.get_author_followers }, - getAuthorFollowingUsers: async ({ slug }: { slug: string }): Promise => { - const response = await publicGraphQLClient.query(authorFollowed, { slug }).toPromise() + getAuthorFollowingAuthors: async ({ slug }: { slug: string }): Promise => { + const response = await publicGraphQLClient.query(authorFollowedAuthors, { slug }).toPromise() return response.data.get_author_followed }, getAuthorFollowingTopics: async ({ slug }: { slug: string }): Promise => { - const response = await publicGraphQLClient.query(userFollowedTopics, { slug }).toPromise() + const response = await publicGraphQLClient.query(authorFollowedTopics, { slug }).toPromise() return response.data.get_topics_by_author }, + getAuthorFollowingCommunities: async ({ slug }: { slug: string }): Promise => { + const response = await publicGraphQLClient.query(authorFollowedCommunities, { slug }).toPromise() + return response.data.get_communities_by_author + }, updateProfile: async (input: ProfileInput) => { const response = await apiClient.private.mutation(updateProfile, { profile: input }).toPromise() return response.data.update_profile @@ -200,7 +209,7 @@ export const apiClient = { const resp = await publicGraphQLClient.query(shoutsLoadBy, { options }).toPromise() if (resp.error) console.error(resp) - return resp.data.load_shouts_by + return resp.data?.load_shouts_by }, getShoutsSearch: async ({ text, limit, offset }: QueryLoad_Shouts_SearchArgs) => { diff --git a/src/graphql/mutation/core/reaction-create.ts b/src/graphql/mutation/core/reaction-create.ts index c85d3353..72852d97 100644 --- a/src/graphql/mutation/core/reaction-create.ts +++ b/src/graphql/mutation/core/reaction-create.ts @@ -8,7 +8,6 @@ export default gql` id body kind - range created_at reply_to stat { diff --git a/src/graphql/query/core/authors-load-by.ts b/src/graphql/query/core/authors-load-by.ts index 11e11be2..427889c4 100644 --- a/src/graphql/query/core/authors-load-by.ts +++ b/src/graphql/query/core/authors-load-by.ts @@ -1,7 +1,7 @@ import { gql } from '@urql/core' export default gql` - query AuthorsAllQuery($by: AuthorsBy, $limit: Int, $offset: Int) { + query AuthorsAllQuery($by: AuthorsBy!, $limit: Int, $offset: Int) { load_authors_by(by: $by, limit: $limit, offset: $offset) { id slug diff --git a/src/graphql/query/core/communities-followed-by.ts b/src/graphql/query/core/communities-followed-by.ts new file mode 100644 index 00000000..d5d33128 --- /dev/null +++ b/src/graphql/query/core/communities-followed-by.ts @@ -0,0 +1,17 @@ +import { gql } from '@urql/core' + +export default gql` + query LoadCommunitiesFollowedBy($slug: String, $user: String, $author_id: Int) { + get_communities_by_author(slug: $slug, user: $user, author_id: $author_id) { + id + slug + title + pic + stat { + shouts + followers + authors + } + } + } +` diff --git a/src/graphql/query/core/topics-by-author.ts b/src/graphql/query/core/topics-followed-by.ts similarity index 77% rename from src/graphql/query/core/topics-by-author.ts rename to src/graphql/query/core/topics-followed-by.ts index b5d7db23..b5299177 100644 --- a/src/graphql/query/core/topics-by-author.ts +++ b/src/graphql/query/core/topics-followed-by.ts @@ -1,7 +1,7 @@ import { gql } from '@urql/core' export default gql` - query UserFollowingTopicsQuery($slug: String, $user: String, $author_id: Int) { + query LoadTopicsFollowedBy($slug: String, $user: String, $author_id: Int) { get_topics_by_author(slug: $slug, user: $user, author_id: $author_id) { id slug diff --git a/src/pages/types.ts b/src/pages/types.ts index c54208c1..b36a7612 100644 --- a/src/pages/types.ts +++ b/src/pages/types.ts @@ -50,4 +50,4 @@ export type UploadedFile = { originalFilename?: string } -export type SubscriptionFilter = 'all' | 'users' | 'topics' +export type SubscriptionFilter = 'all' | 'authors' | 'topics' | 'communities' diff --git a/src/stores/zine/common.ts b/src/stores/zine/common.ts deleted file mode 100644 index c874816b..00000000 --- a/src/stores/zine/common.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { apiClient } from '../../graphql/client/core' -import { FollowingEntity } from '../../graphql/schema/core.gen' - -export const follow = async ({ what, slug }: { what: FollowingEntity; slug: string }) => { - await apiClient.follow({ what, slug }) -} -export const unfollow = async ({ what, slug }: { what: FollowingEntity; slug: string }) => { - await apiClient.unfollow({ what, slug }) -} diff --git a/src/utils/getImageUrl.ts b/src/utils/getImageUrl.ts index ef59e6d8..6f249115 100644 --- a/src/utils/getImageUrl.ts +++ b/src/utils/getImageUrl.ts @@ -15,7 +15,7 @@ export const getImageUrl = ( src: string, options: { width?: number; height?: number; noSizeUrlPart?: boolean } = {}, ) => { - const filename = src.split('/').pop() + const filename = src?.split('/').pop() const isAudio = src.toLowerCase().split('.').pop() in ['wav', 'mp3', 'ogg', 'aif', 'flac'] const base = isAudio ? cdnUrl : `${thumborUrl}/unsafe/` const sizeUrlPart = isAudio ? '' : getSizeUrlPart(options) diff --git a/src/utils/useEscKeyDownHandler.ts b/src/utils/useEscKeyDownHandler.ts index 3e19f505..b3430c31 100644 --- a/src/utils/useEscKeyDownHandler.ts +++ b/src/utils/useEscKeyDownHandler.ts @@ -1,9 +1,9 @@ import { onCleanup, onMount } from 'solid-js' -export const useEscKeyDownHandler = (onEscKeyDown: () => void) => { +export const useEscKeyDownHandler = (onEscKeyDown: (ev) => void) => { const keydownHandler = (e: KeyboardEvent) => { if (e.key === 'Escape') { - onEscKeyDown() + onEscKeyDown(e) } } From 0b443804bd4cafead7354e6a7154df3f4583efed Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 15:55:18 +0300 Subject: [PATCH 72/88] authorizer-upgrade --- package-lock.json | 14 ++++---------- package.json | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index bc331cb5..5fb127b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,11 +10,10 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@authorizerdev/authorizer-js": "1.2.11", + "@authorizerdev/authorizer-js": "2.0.0", "@solid-primitives/pagination": "0.2.10", "cropperjs": "1.6.1", "form-data": "4.0.0", - "ga-gtag": "1.2.0", "i18next": "22.4.15", "i18next-icu": "2.3.0", "idb": "7.1.1", @@ -387,9 +386,9 @@ } }, "node_modules/@authorizerdev/authorizer-js": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.11.tgz", - "integrity": "sha512-onATswFYM0QCmhFPJmjS+S7Z0GNqlekqkDdFK6Bj3OeMBDQufARRHmVIGVI+0IlB7TWW38D1l6WbTZin0ct+aA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-2.0.0.tgz", + "integrity": "sha512-PTVuCrCkZkVPoo+l0+9PVFyP9frLp/L3FUtQDtAaN+ERuqx97DNF20tIH8khSvnXrkKv3lTJ/5iFWddy+dTAwg==", "dependencies": { "cross-fetch": "^3.1.5" }, @@ -9532,11 +9531,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ga-gtag": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ga-gtag/-/ga-gtag-1.2.0.tgz", - "integrity": "sha512-j9gxutMdpGMdwaX1SzOG31Ddm+IGFjeNf+N3Z5g+BBpS8FSXOALlrM+ORIGc/QKszGJEDlw+6PfIsJZICsqsGQ==" - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", diff --git a/package.json b/package.json index 1bce74a2..006bd345 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "typecheck:watch": "tsc --noEmit --watch" }, "dependencies": { - "@authorizerdev/authorizer-js": "1.2.11", + "@authorizerdev/authorizer-js": "2.0.0", "@solid-primitives/pagination": "0.2.10", "cropperjs": "1.6.1", "form-data": "4.0.0", From 103e73a870fa1f706b21036d74342fcd6fc6d021 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 16:08:25 +0300 Subject: [PATCH 73/88] authorizer 2.0 code adaptation --- src/context/session.tsx | 57 +++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/context/session.tsx b/src/context/session.tsx index d637edb9..5cdd03e8 100644 --- a/src/context/session.tsx +++ b/src/context/session.tsx @@ -10,6 +10,8 @@ import { ConfigType, SignupInput, AuthorizeResponse, + ApiResponse, + GenericResponse, // GraphqlQueryInput, } from '@authorizerdev/authorizer-js' import { @@ -121,21 +123,31 @@ export const SessionProvider = (props: { // Function to load session data const sessionData = async () => { try { - const s = await authorizer().getSession() - console.info('[context.session] loading session', s) + const s: ApiResponse = await authorizer().getSession() + if (s?.data) { + console.info('[context.session] loading session', s) - // Set session expiration time in local storage - const expires_at = new Date(Date.now() + s.expires_in * 1000) - localStorage.setItem('expires_at', `${expires_at.getTime()}`) + // Set session expiration time in local storage + const expires_at = new Date(Date.now() + s.data.expires_in * 1000) + localStorage.setItem('expires_at', `${expires_at.getTime()}`) - // Set up session expiration check timer - minuteLater = setTimeout(checkSessionIsExpired, 60 * 1000) - console.info(`[context.session] will refresh in ${s.expires_in / 60} mins`) + // Set up session expiration check timer + minuteLater = setTimeout(checkSessionIsExpired, 60 * 1000) + console.info(`[context.session] will refresh in ${s.data.expires_in / 60} mins`) - // Set the session loaded flag - setIsSessionLoaded(true) + // Set the session loaded flag + setIsSessionLoaded(true) - return s + return s.data + } else { + console.info('[context.session] cannot refresh session', s.errors) + setAuthError(s.errors.pop().message) + + // Set the session loaded flag even if there's an error + setIsSessionLoaded(true) + + return null + } } catch (error) { console.info('[context.session] cannot refresh session', error) setAuthError(error) @@ -258,17 +270,20 @@ export const SessionProvider = (props: { // authorizer api proxy methods const signUp = async (params: SignupInput) => { - const authResult: void | AuthToken = await authorizer().signup(params) - if (authResult) setSession(authResult) + const authResult: ApiResponse = await authorizer().signup(params) + if (authResult?.data) setSession(authResult.data) + if (authResult?.errors) console.error(authResult.errors) } const signIn = async (params: LoginInput) => { - const authResult: AuthToken | void = await authorizer().login(params) - if (authResult) setSession(authResult) + const authResult: ApiResponse = await authorizer().login(params) + if (authResult?.data) setSession(authResult.data) + if (authResult?.errors) console.error(authResult.errors) } const signOut = async () => { - await authorizer().logout() + const authResult: ApiResponse = await authorizer().logout() + console.debug(authResult) reset() showSnackbar({ body: t("You've successfully logged out") }) } @@ -281,9 +296,13 @@ export const SessionProvider = (props: { const confirmEmail = async (input: VerifyEmailInput) => { console.debug(`[context.session] calling authorizer's verify email with`, input) try { - const at: void | AuthToken = await authorizer().verifyEmail(input) - if (at) setSession(at) - return at + const at: ApiResponse = await authorizer().verifyEmail(input) + if (at?.data) { + setSession(at.data) + return at.data + } else { + console.warn(at?.errors) + } } catch (error) { console.warn(error) } From cf19cdd39bddf6d7236229b2e91deaadb2b536e0 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 16:12:59 +0300 Subject: [PATCH 74/88] authorizer-upgrade --- src/components/Nav/AuthModal/ForgotPasswordForm.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/Nav/AuthModal/ForgotPasswordForm.tsx b/src/components/Nav/AuthModal/ForgotPasswordForm.tsx index 8dc12583..5fae5e8e 100644 --- a/src/components/Nav/AuthModal/ForgotPasswordForm.tsx +++ b/src/components/Nav/AuthModal/ForgotPasswordForm.tsx @@ -12,6 +12,7 @@ import { validateEmail } from '../../../utils/validateEmail' import { email, setEmail } from './sharedLogic' import styles from './AuthModal.module.scss' +import { ApiResponse, ForgotPasswordResponse } from '@authorizerdev/authorizer-js' type FormFields = { email: string @@ -61,12 +62,15 @@ export const ForgotPasswordForm = () => { setIsSubmitting(true) try { - const response = await authorizer().forgotPassword({ + const response: ApiResponse = await authorizer().forgotPassword({ email: email(), redirect_uri: window.location.origin, }) console.debug('[ForgotPasswordForm] authorizer response:', response) - if (response && response.message) setMessage(response.message) + if (response?.data) setMessage(response.data.message) + else { + console.warn(response.errors) + } } catch (error) { console.error(error) if (error?.code === 'user_not_found') { From 5a95e7490ecfaf4122570c9d9c863fd7df4c8ba7 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 16:24:40 +0300 Subject: [PATCH 75/88] authorizer-upgrade-3 --- .../Nav/AuthModal/ForgotPasswordForm.tsx | 29 +++++++++++-------- src/context/session.tsx | 13 ++++++++- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/components/Nav/AuthModal/ForgotPasswordForm.tsx b/src/components/Nav/AuthModal/ForgotPasswordForm.tsx index 5fae5e8e..1bf2b12d 100644 --- a/src/components/Nav/AuthModal/ForgotPasswordForm.tsx +++ b/src/components/Nav/AuthModal/ForgotPasswordForm.tsx @@ -12,7 +12,6 @@ import { validateEmail } from '../../../utils/validateEmail' import { email, setEmail } from './sharedLogic' import styles from './AuthModal.module.scss' -import { ApiResponse, ForgotPasswordResponse } from '@authorizerdev/authorizer-js' type FormFields = { email: string @@ -28,7 +27,7 @@ export const ForgotPasswordForm = () => { setEmail(newEmail.toLowerCase()) } const { - actions: { authorizer }, + actions: { forgotPassword }, } = useSession() const [submitError, setSubmitError] = createSignal('') const [isSubmitting, setIsSubmitting] = createSignal(false) @@ -62,22 +61,28 @@ export const ForgotPasswordForm = () => { setIsSubmitting(true) try { - const response: ApiResponse = await authorizer().forgotPassword({ + const { data, errors } = await forgotPassword({ email: email(), redirect_uri: window.location.origin, }) - console.debug('[ForgotPasswordForm] authorizer response:', response) - if (response?.data) setMessage(response.data.message) - else { - console.warn(response.errors) + if (data) { + console.debug('[ForgotPasswordForm] authorizer response:', data) + setMessage(data.message) + } + if (errors) { + console.warn(errors) + if (errors) { + const error: Error = errors[0] + if (error.cause === 'user_not_found') { + setIsUserNotFound(true) + return + } else { + setSubmitError(error.message) + } + } } } catch (error) { console.error(error) - if (error?.code === 'user_not_found') { - setIsUserNotFound(true) - return - } - setSubmitError(error?.message) } finally { setIsSubmitting(false) } diff --git a/src/context/session.tsx b/src/context/session.tsx index 5cdd03e8..c2b8b8f7 100644 --- a/src/context/session.tsx +++ b/src/context/session.tsx @@ -12,7 +12,8 @@ import { AuthorizeResponse, ApiResponse, GenericResponse, - // GraphqlQueryInput, + ForgotPasswordResponse, + ForgotPasswordInput, } from '@authorizerdev/authorizer-js' import { createContext, @@ -62,6 +63,9 @@ export type SessionContextType = { signIn: (params: LoginInput) => Promise signOut: () => Promise oauth: (provider: string) => Promise + forgotPassword: ( + params: ForgotPasswordInput, + ) => Promise<{ data: ForgotPasswordResponse; errors: Error[] }> changePassword: (password: string, token: string) => void confirmEmail: (input: VerifyEmailInput) => Promise // email confirm callback is in auth.discours.io setIsSessionLoaded: (loaded: boolean) => void @@ -293,6 +297,12 @@ export const SessionProvider = (props: { console.debug('[context.session] change password response:', resp) } + const forgotPassword = async (params: ForgotPasswordInput) => { + const resp = await authorizer().forgotPassword(params) + console.debug('[context.session] change password response:', resp) + return { data: resp?.data, errors: resp.errors } + } + const confirmEmail = async (input: VerifyEmailInput) => { console.debug(`[context.session] calling authorizer's verify email with`, input) try { @@ -338,6 +348,7 @@ export const SessionProvider = (props: { setAuthor, authorizer, loadAuthor, + forgotPassword, changePassword, oauth, } From af95e81c47396936478ece503489b21d543449a5 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 16:42:59 +0300 Subject: [PATCH 76/88] package-lock-fix --- package.json | 1 - src/components/Views/Author/Author.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/package.json b/package.json index 006bd345..09854bd3 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ "@solid-primitives/pagination": "0.2.10", "cropperjs": "1.6.1", "form-data": "4.0.0", - "ga-gtag": "1.2.0", "i18next": "22.4.15", "i18next-icu": "2.3.0", "idb": "7.1.1", diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index b1eeebec..2742637b 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -127,7 +127,6 @@ export const AuthorView = (props: Props) => { // pagination if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) { - fetchData() loadMore() } }) From 90cf0a9e10b7189315bf70481a149dd98db3254d Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 16:45:04 +0300 Subject: [PATCH 77/88] package-lock-fix-2 --- package-lock.json | 6 ++++++ package.json | 1 + 2 files changed, 7 insertions(+) diff --git a/package-lock.json b/package-lock.json index 5fb127b8..a56a55f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@solid-primitives/pagination": "0.2.10", "cropperjs": "1.6.1", "form-data": "4.0.0", + "ga-gtag": "1.2.0", "i18next": "22.4.15", "i18next-icu": "2.3.0", "idb": "7.1.1", @@ -9531,6 +9532,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/ga-gtag": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ga-gtag/-/ga-gtag-1.2.0.tgz", + "integrity": "sha512-j9gxutMdpGMdwaX1SzOG31Ddm+IGFjeNf+N3Z5g+BBpS8FSXOALlrM+ORIGc/QKszGJEDlw+6PfIsJZICsqsGQ==" + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", diff --git a/package.json b/package.json index 09854bd3..006bd345 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@solid-primitives/pagination": "0.2.10", "cropperjs": "1.6.1", "form-data": "4.0.0", + "ga-gtag": "1.2.0", "i18next": "22.4.15", "i18next-icu": "2.3.0", "idb": "7.1.1", From 27711d7e99d2367d5f6447d85a54d16289905d21 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 16:54:43 +0300 Subject: [PATCH 78/88] forgot-form-fox --- .../Nav/AuthModal/ForgotPasswordForm.tsx | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/components/Nav/AuthModal/ForgotPasswordForm.tsx b/src/components/Nav/AuthModal/ForgotPasswordForm.tsx index 1bf2b12d..4e147d92 100644 --- a/src/components/Nav/AuthModal/ForgotPasswordForm.tsx +++ b/src/components/Nav/AuthModal/ForgotPasswordForm.tsx @@ -65,21 +65,16 @@ export const ForgotPasswordForm = () => { email: email(), redirect_uri: window.location.origin, }) - if (data) { - console.debug('[ForgotPasswordForm] authorizer response:', data) - setMessage(data.message) - } - if (errors) { - console.warn(errors) - if (errors) { - const error: Error = errors[0] - if (error.cause === 'user_not_found') { - setIsUserNotFound(true) - return - } else { - setSubmitError(error.message) - } - } + console.debug('[ForgotPasswordForm] authorizer response:', data) + setMessage(data.message) + + console.warn(errors) + if (errors.some((e) => e.cause === 'user_not_found')) { + setIsUserNotFound(true) + return + } else { + const errorText = errors.map((e) => e.message).join(' ') // FIXME + setSubmitError(errorText) } } catch (error) { console.error(error) From cfca2dbbabc56871fb8e18f5f0b450f4399dcd82 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 17:59:03 +0300 Subject: [PATCH 79/88] debug-subs --- src/context/following.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/context/following.tsx b/src/context/following.tsx index 2246485f..b22f8db1 100644 --- a/src/context/following.tsx +++ b/src/context/following.tsx @@ -80,17 +80,13 @@ export const FollowingProvider = (props: { children: JSX.Element }) => { } } - const loadData = (_a?: Author) => { - // console.debug('[context.following] current subs:', subscriptions) - if (!subscriptions?.authors?.length && !subscriptions?.topics?.length) { + createEffect(() => { + if (author() && !subscriptions?.authors?.length && !subscriptions?.topics?.length) { // && subscriptions.communites?.length + console.debug('[context.following] author with no subs detected') fetchData() } - } - createEffect(() => { - if (author()) loadData() }) - onMount(loadData) const setFollowing = (what: FollowingEntity, slug: string, value = true) => { setSubscriptions((prevSubscriptions) => { From 2103db3ebd03fdc33f9eaa661c34d1d9d871dcf0 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 18:15:23 +0300 Subject: [PATCH 80/88] load-comments-fix --- src/components/Views/Author/Author.tsx | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 2742637b..b8813adb 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -144,22 +144,16 @@ export const AuthorView = (props: Props) => { } const [commented, setCommented] = createSignal([]) - createEffect( - on( - author, - (a: Author) => { - if (getPage().route === 'authorComments') { - console.debug('[components.Author] routed to comments') - try { - if (a) fetchComments(a) - } catch (error) { - console.error('[components.Author] fetch error', error) - } - } - }, - { defer: true }, - ), - ) + createEffect(() => { + if (author() && getPage().route === 'authorComments') { + console.debug('[components.Author] routed to comments') + try { + fetchComments(author()) + } catch (error) { + console.error('[components.Author] fetch error', error) + } + } + }) const ogImage = createMemo(() => author()?.pic From c234ab1c2bdbb10afc8e0d6079d678552806770c Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 18:35:40 +0300 Subject: [PATCH 81/88] debug-detect --- src/context/following.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/context/following.tsx b/src/context/following.tsx index b22f8db1..163fd030 100644 --- a/src/context/following.tsx +++ b/src/context/following.tsx @@ -81,10 +81,13 @@ export const FollowingProvider = (props: { children: JSX.Element }) => { } createEffect(() => { - if (author() && !subscriptions?.authors?.length && !subscriptions?.topics?.length) { - // && subscriptions.communites?.length - console.debug('[context.following] author with no subs detected') - fetchData() + if (author()) { + console.debug('[context.following] author detect') + if (!subscriptions?.authors?.length && !subscriptions?.topics?.length) { + // && subscriptions.communites?.length + console.debug('[context.following] no subs detected') + fetchData() + } } }) From 8caa4f823a020bade6f0b21aea8db331f3b54aae Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 18:46:34 +0300 Subject: [PATCH 82/88] detect-fix --- src/context/following.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/context/following.tsx b/src/context/following.tsx index 163fd030..c826740b 100644 --- a/src/context/following.tsx +++ b/src/context/following.tsx @@ -82,12 +82,8 @@ export const FollowingProvider = (props: { children: JSX.Element }) => { createEffect(() => { if (author()) { - console.debug('[context.following] author detect') - if (!subscriptions?.authors?.length && !subscriptions?.topics?.length) { - // && subscriptions.communites?.length - console.debug('[context.following] no subs detected') - fetchData() - } + console.debug('[context.following] author update detect') + fetchData() } }) From f6c64b1d46e5262eaa94d0f056df6d1bf3e0fe3c Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 19:09:42 +0300 Subject: [PATCH 83/88] fetch-comments-fix --- src/components/Views/Author/Author.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index b8813adb..5d1e417e 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -25,6 +25,7 @@ import { Row3 } from '../../Feed/Row3' import styles from './Author.module.scss' import stylesArticle from '../../Article/Article.module.scss' +import { useFollowing } from '../../../context/following' type Props = { shouts: Shout[] @@ -37,6 +38,7 @@ const LOAD_MORE_PAGE_SIZE = 9 export const AuthorView = (props: Props) => { const { t } = useLocalize() + const { loadSubscriptions } = useFollowing() const { sortedArticles } = useArticlesStore({ shouts: props.shouts }) const { authorEntities } = useAuthorsStore({ authors: [props.author] }) const { page: getPage } = useRouter() @@ -128,6 +130,7 @@ export const AuthorView = (props: Props) => { // pagination if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) { loadMore() + loadSubscriptions() } }) @@ -145,13 +148,9 @@ export const AuthorView = (props: Props) => { const [commented, setCommented] = createSignal([]) createEffect(() => { - if (author() && getPage().route === 'authorComments') { - console.debug('[components.Author] routed to comments') - try { - fetchComments(author()) - } catch (error) { - console.error('[components.Author] fetch error', error) - } + const a = author() + if (a) { + fetchComments(a) } }) From 7e46bbdd9ebaed558cace80bd533b557666f39ac Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 20:38:00 +0300 Subject: [PATCH 84/88] subs-fix --- src/components/Views/Author/Author.tsx | 2 +- src/context/inbox.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 5d1e417e..2de280a3 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -5,6 +5,7 @@ import { Meta } from '@solidjs/meta' import { clsx } from 'clsx' import { Show, createMemo, createSignal, Switch, onMount, For, Match, createEffect, on } from 'solid-js' +import { useFollowing } from '../../../context/following' import { useLocalize } from '../../../context/localize' import { apiClient } from '../../../graphql/client/core' import { router, useRouter } from '../../../stores/router' @@ -25,7 +26,6 @@ import { Row3 } from '../../Feed/Row3' import styles from './Author.module.scss' import stylesArticle from '../../Article/Article.module.scss' -import { useFollowing } from '../../../context/following' type Props = { shouts: Shout[] diff --git a/src/context/inbox.tsx b/src/context/inbox.tsx index f518929c..22cbf22d 100644 --- a/src/context/inbox.tsx +++ b/src/context/inbox.tsx @@ -34,13 +34,13 @@ export const InboxProvider = (props: { children: JSX.Element }) => { const { sortedAuthors } = useAuthorsStore() const handleMessage = (sseMessage: SSEMessage) => { - console.log('[context.inbox]:', sseMessage) - // handling all action types: create update delete join left seen if (sseMessage.entity === 'message') { + console.debug('[context.inbox]:', sseMessage.payload) const relivedMessage = sseMessage.payload setMessages((prev) => [...prev, relivedMessage]) } else if (sseMessage.entity === 'chat') { + console.debug('[context.inbox]:', sseMessage.payload) const relivedChat = sseMessage.payload setChats((prev) => [...prev, relivedChat]) } From 504eb98cd78355c0a5787368e7ca3db4b50069a8 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 20:41:49 +0300 Subject: [PATCH 85/88] delete-debug --- src/graphql/client/core.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/graphql/client/core.ts b/src/graphql/client/core.ts index 04e8acf6..e14bdad2 100644 --- a/src/graphql/client/core.ts +++ b/src/graphql/client/core.ts @@ -163,8 +163,11 @@ export const apiClient = { console.debug('[graphql.client.core] updateArticle:', response.data) return response.data.update_shout.shout }, - deleteShout: async ({ shoutId }: { shoutId: number }): Promise => { - const response = await apiClient.private.mutation(deleteShout, { shout_id: shoutId }).toPromise() + deleteShout: async (params): Promise => { + console.debug(params) + const response = await apiClient.private + .mutation(deleteShout, { shout_id: params?.shoutId }) + .toPromise() console.debug('[graphql.client.core] deleteShout:', response) }, getDrafts: async (): Promise => { From 0a9b70bfb7125d88643750d0239d4374c7ea306c Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 21:15:08 +0300 Subject: [PATCH 86/88] delete-shout-fix --- src/graphql/client/core.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/graphql/client/core.ts b/src/graphql/client/core.ts index e14bdad2..ad149d8b 100644 --- a/src/graphql/client/core.ts +++ b/src/graphql/client/core.ts @@ -13,6 +13,7 @@ import type { QueryLoad_Shouts_SearchArgs, QueryLoad_Shouts_Random_TopArgs, Community, + MutationDelete_ShoutArgs, } from '../schema/core.gen' import { createGraphQLClient } from '../createGraphQLClient' @@ -163,11 +164,8 @@ export const apiClient = { console.debug('[graphql.client.core] updateArticle:', response.data) return response.data.update_shout.shout }, - deleteShout: async (params): Promise => { - console.debug(params) - const response = await apiClient.private - .mutation(deleteShout, { shout_id: params?.shoutId }) - .toPromise() + deleteShout: async (params: MutationDelete_ShoutArgs): Promise => { + const response = await apiClient.private.mutation(deleteShout, params).toPromise() console.debug('[graphql.client.core] deleteShout:', response) }, getDrafts: async (): Promise => { From 5e5291d7e85d787aa5a0a2e8bda6c15f64a074c3 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 21:41:20 +0300 Subject: [PATCH 87/88] delete-shout-fix-2 --- src/context/editor.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/context/editor.tsx b/src/context/editor.tsx index 41975d52..6d7c550b 100644 --- a/src/context/editor.tsx +++ b/src/context/editor.tsx @@ -218,10 +218,10 @@ export const EditorProvider = (props: { children: JSX.Element }) => { } } - const deleteShout = async (shoutId: number) => { + const deleteShout = async (shout_id: number) => { try { await apiClient.deleteShout({ - shoutId, + shout_id, }) return true } catch { From 9b1f3c993cd57a3ff6989b62c3c6c666c74da6da Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 31 Jan 2024 22:06:29 +0300 Subject: [PATCH 88/88] delete-fix --- src/graphql/mutation/core/article-delete.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/graphql/mutation/core/article-delete.ts b/src/graphql/mutation/core/article-delete.ts index 9aa22fc1..6ac5578e 100644 --- a/src/graphql/mutation/core/article-delete.ts +++ b/src/graphql/mutation/core/article-delete.ts @@ -1,8 +1,8 @@ import { gql } from '@urql/core' export default gql` - mutation DeleteShoutMutation($shoutId: Int!) { - delete_shout(shout_id: $shoutId) { + mutation DeleteShoutMutation($shout_id: Int!) { + delete_shout(shout_id: $shout_id) { error } }