From 70469dbe33808d7cafac66d17fc7a402ec44b1f6 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Sun, 9 Oct 2022 12:56:39 +0200 Subject: [PATCH 01/15] fixes, loading icon --- astro.config.ts | 56 ++++++++++++------------- public/icons/arrows-rotate.svg | 5 +++ src/components/Article/FullArticle.tsx | 14 +++++-- src/components/Loading.module.scss | 27 ++++++++++++ src/components/Loading.tsx | 9 ++++ src/components/Nav/AuthModal.tsx | 29 ++++++++----- src/components/Nav/Header.tsx | 2 +- src/components/Pages/AllAuthorsPage.tsx | 4 +- src/components/Pages/AllTopicsPage.tsx | 4 +- src/components/Pages/ArticlePage.tsx | 4 +- src/components/Pages/AuthorPage.tsx | 4 +- src/components/Pages/FeedPage.tsx | 4 +- src/components/Pages/HomePage.tsx | 4 +- src/components/Pages/SearchPage.tsx | 4 +- src/components/Pages/TopicPage.tsx | 4 +- src/components/Views/Author.tsx | 50 +++++++++++----------- src/components/Views/Topic.tsx | 49 ++++++++++------------ src/graphql/query/authors-all.ts | 2 +- src/styles/app.scss | 2 + 19 files changed, 164 insertions(+), 113 deletions(-) create mode 100644 public/icons/arrows-rotate.svg create mode 100644 src/components/Loading.module.scss create mode 100644 src/components/Loading.tsx diff --git a/astro.config.ts b/astro.config.ts index 472928ed..d0c2d3ec 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -43,34 +43,34 @@ const astroConfig: AstroUserConfig = { // eslint-disable-next-line sonarjs/cognitive-complexity manualChunks(id) { if (id.includes('node_modules')) { - let chunkid = 'vendor' - if (id.includes('solid')) { - chunkid = 'solid' - } - if (id.includes('acorn')) { - chunkid = 'acorn' - } - if (id.includes('simple-peer')) { - chunkid = 'simple-peer' - } - if (id.includes('prosemirror')) { - chunkid = 'prosemirror' - } - if (id.includes('markdown') || id.includes('mdurl')) { - chunkid = 'markdown' - } - if (id.includes('swiper')) { - chunkid = 'swiper' - } - if ( - id.includes('yjs') || - id.includes('y-prosemirror') || - id.includes('y-protocols') || - id.includes('y-webrtc') - ) { - chunkid = 'yjs' - } - return chunkid + // FIXME: doesn't work in production + // if (id.includes('solid')) { + // chunkid = 'solid' + // } + // if (id.includes('acorn')) { + // chunkid = 'acorn' + // } + // if (id.includes('simple-peer')) { + // chunkid = 'simple-peer' + // } + // if (id.includes('prosemirror')) { + // chunkid = 'prosemirror' + // } + // if (id.includes('markdown') || id.includes('mdurl')) { + // chunkid = 'markdown' + // } + // if (id.includes('swiper')) { + // chunkid = 'swiper' + // } + // if ( + // id.includes('yjs') || + // id.includes('y-prosemirror') || + // id.includes('y-protocols') || + // id.includes('y-webrtc') + // ) { + // chunkid = 'yjs' + // } + return 'vendor' } } }, diff --git a/public/icons/arrows-rotate.svg b/public/icons/arrows-rotate.svg new file mode 100644 index 00000000..4fc42bf3 --- /dev/null +++ b/public/icons/arrows-rotate.svg @@ -0,0 +1,5 @@ + + + diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx index a499adc4..512cdac9 100644 --- a/src/components/Article/FullArticle.tsx +++ b/src/components/Article/FullArticle.tsx @@ -37,7 +37,6 @@ const formatDate = (date: Date) => { } export const FullArticle = (props: ArticleProps) => { - const body = createMemo(() => props.article.body.toString().trim()) const { session } = useAuthStore() onMount(() => { @@ -93,9 +92,16 @@ export const FullArticle = (props: ArticleProps) => {
-
- -
+ +
+ } + > + + +
+
diff --git a/src/components/Loading.module.scss b/src/components/Loading.module.scss new file mode 100644 index 00000000..de09f09b --- /dev/null +++ b/src/components/Loading.module.scss @@ -0,0 +1,27 @@ +.container { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } +} + +.icon { + animation-name: spin; + width: 64px; + height: 64px; + background-image: url(/icons/arrows-rotate.svg); + background-repeat: no-repeat; + animation-duration: 2s; + animation-iteration-count: infinite; + animation-timing-function: linear; +} diff --git a/src/components/Loading.tsx b/src/components/Loading.tsx new file mode 100644 index 00000000..252c0f52 --- /dev/null +++ b/src/components/Loading.tsx @@ -0,0 +1,9 @@ +import styles from './Loading.module.scss' + +export const Loading = () => { + return ( +
+
+
+ ) +} diff --git a/src/components/Nav/AuthModal.tsx b/src/components/Nav/AuthModal.tsx index 9f1729ba..e26ad6b2 100644 --- a/src/components/Nav/AuthModal.tsx +++ b/src/components/Nav/AuthModal.tsx @@ -9,6 +9,7 @@ import { useAuthStore, signIn, register } from '../../stores/auth' import { useValidator } from '../../utils/validators' import { baseUrl } from '../../graphql/publicGraphQLClient' import { ApiError } from '../../utils/apiClient' +import { handleClientRouteLinkClick } from '../../stores/router' type AuthMode = 'sign-in' | 'sign-up' | 'forget' | 'reset' | 'resend' | 'password' @@ -30,9 +31,16 @@ const titles = { // const isProperEmail = (email) => email && email.length > 5 && email.includes('@') && email.includes('.') +// 3rd party provider auth handler +const oauth = (provider: string): void => { + const popup = window.open(`${baseUrl}/oauth/${provider}`, provider, 'width=740, height=420') + popup?.focus() + hideModal() +} + // FIXME !!! // eslint-disable-next-line sonarjs/cognitive-complexity -export default (props: { code?: string; mode?: string }) => { +export default (props: { code?: string; mode?: AuthMode }) => { const { session } = useAuthStore() const [handshaking] = createSignal(false) const { getModal } = useModalStore() @@ -45,13 +53,6 @@ export default (props: { code?: string; mode?: string }) => { let passElement: HTMLInputElement | undefined let codeElement: HTMLInputElement | undefined - // 3rd party provider auth handler - const oauth = (provider: string): void => { - const popup = window.open(`${baseUrl}/oauth/${provider}`, provider, 'width=740, height=420') - popup?.focus() - hideModal() - } - // FIXME: restore logic // const usedEmails = {} // const checkEmailAsync = async (email: string) => { @@ -179,9 +180,15 @@ export default (props: { code?: string; mode?: string }) => { {t('New stories every day and even more!')}

- {t('By signing up you agree with our')} - - {' ' + t('terms of use')} + {t('By signing up you agree with our')}{' '} + { + hideModal() + handleClientRouteLinkClick(event) + }} + > + {t('terms of use')} , {t('personal data usage and email notifications')}.

diff --git a/src/components/Nav/Header.tsx b/src/components/Nav/Header.tsx index 0d0a08f2..802db235 100644 --- a/src/components/Nav/Header.tsx +++ b/src/components/Nav/Header.tsx @@ -116,7 +116,7 @@ export const Header = (props: Props) => { > {(r) => ( -
  • +
  • {r.name} diff --git a/src/components/Pages/AllAuthorsPage.tsx b/src/components/Pages/AllAuthorsPage.tsx index 78e95682..5a6e380c 100644 --- a/src/components/Pages/AllAuthorsPage.tsx +++ b/src/components/Pages/AllAuthorsPage.tsx @@ -3,7 +3,7 @@ import { AllAuthorsView } from '../Views/AllAuthors' import type { PageProps } from '../types' import { createSignal, onMount, Show } from 'solid-js' import { loadAllAuthors } from '../../stores/zine/authors' -import { t } from '../../utils/intl' +import { Loading } from '../Loading' export const AllAuthorsPage = (props: PageProps) => { const [isLoaded, setIsLoaded] = createSignal(Boolean(props.allAuthors)) @@ -19,7 +19,7 @@ export const AllAuthorsPage = (props: PageProps) => { return ( - + }> diff --git a/src/components/Pages/AllTopicsPage.tsx b/src/components/Pages/AllTopicsPage.tsx index 2e371ba6..ae5e3230 100644 --- a/src/components/Pages/AllTopicsPage.tsx +++ b/src/components/Pages/AllTopicsPage.tsx @@ -2,8 +2,8 @@ import { MainLayout } from '../Layouts/MainLayout' import { AllTopicsView } from '../Views/AllTopics' import type { PageProps } from '../types' import { createSignal, onMount, Show } from 'solid-js' -import { t } from '../../utils/intl' import { loadAllTopics } from '../../stores/zine/topics' +import { Loading } from '../Loading' export const AllTopicsPage = (props: PageProps) => { const [isLoaded, setIsLoaded] = createSignal(Boolean(props.allTopics)) @@ -19,7 +19,7 @@ export const AllTopicsPage = (props: PageProps) => { return ( - + }> diff --git a/src/components/Pages/ArticlePage.tsx b/src/components/Pages/ArticlePage.tsx index cc7fb918..357c5494 100644 --- a/src/components/Pages/ArticlePage.tsx +++ b/src/components/Pages/ArticlePage.tsx @@ -3,9 +3,9 @@ import { ArticleView } from '../Views/Article' import type { PageProps } from '../types' import { loadArticle, useArticlesStore } from '../../stores/zine/articles' import { createMemo, onMount, Show } from 'solid-js' -import { t } from '../../utils/intl' import type { Shout } from '../../graphql/types.gen' import { useRouter } from '../../stores/router' +import { Loading } from '../Loading' export const ArticlePage = (props: PageProps) => { const sortedArticles = props.article ? [props.article] : [] @@ -38,7 +38,7 @@ export const ArticlePage = (props: PageProps) => { return ( - + }> diff --git a/src/components/Pages/AuthorPage.tsx b/src/components/Pages/AuthorPage.tsx index aa825fd9..1d159773 100644 --- a/src/components/Pages/AuthorPage.tsx +++ b/src/components/Pages/AuthorPage.tsx @@ -4,8 +4,8 @@ import type { PageProps } from '../types' import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js' import { loadArticlesForAuthors, resetSortedArticles } from '../../stores/zine/articles' import { useRouter } from '../../stores/router' -import { t } from '../../utils/intl' import { loadAuthor } from '../../stores/zine/authors' +import { Loading } from '../Loading' export const AuthorPage = (props: PageProps) => { const [isLoaded, setIsLoaded] = createSignal(Boolean(props.authorArticles) && Boolean(props.author)) @@ -37,7 +37,7 @@ export const AuthorPage = (props: PageProps) => { return ( - + }> diff --git a/src/components/Pages/FeedPage.tsx b/src/components/Pages/FeedPage.tsx index 1e015e69..13c18136 100644 --- a/src/components/Pages/FeedPage.tsx +++ b/src/components/Pages/FeedPage.tsx @@ -3,7 +3,7 @@ import { FeedView } from '../Views/Feed' import type { PageProps } from '../types' import { createSignal, onCleanup, onMount, Show } from 'solid-js' import { loadRecentArticles, resetSortedArticles } from '../../stores/zine/articles' -import { t } from '../../utils/intl' +import { Loading } from '../Loading' export const FeedPage = (props: PageProps) => { const [isLoaded, setIsLoaded] = createSignal(Boolean(props.feedArticles)) @@ -22,7 +22,7 @@ export const FeedPage = (props: PageProps) => { return ( - + }> diff --git a/src/components/Pages/HomePage.tsx b/src/components/Pages/HomePage.tsx index cbfb9d10..f8430e03 100644 --- a/src/components/Pages/HomePage.tsx +++ b/src/components/Pages/HomePage.tsx @@ -2,9 +2,9 @@ import { HomeView } from '../Views/Home' import { MainLayout } from '../Layouts/MainLayout' import type { PageProps } from '../types' import { createSignal, onCleanup, onMount, Show } from 'solid-js' -import { t } from '../../utils/intl' import { loadPublishedArticles, resetSortedArticles } from '../../stores/zine/articles' import { loadRandomTopics } from '../../stores/zine/topics' +import { Loading } from '../Loading' export const HomePage = (props: PageProps) => { const [isLoaded, setIsLoaded] = createSignal(Boolean(props.homeArticles) && Boolean(props.randomTopics)) @@ -24,7 +24,7 @@ export const HomePage = (props: PageProps) => { return ( - + }> diff --git a/src/components/Pages/SearchPage.tsx b/src/components/Pages/SearchPage.tsx index b7668cf9..ff636018 100644 --- a/src/components/Pages/SearchPage.tsx +++ b/src/components/Pages/SearchPage.tsx @@ -3,8 +3,8 @@ import { SearchView } from '../Views/Search' import type { PageProps } from '../types' import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js' import { loadSearchResults, resetSortedArticles } from '../../stores/zine/articles' -import { t } from '../../utils/intl' import { useRouter } from '../../stores/router' +import { Loading } from '../Loading' export const SearchPage = (props: PageProps) => { const [isLoaded, setIsLoaded] = createSignal(Boolean(props.searchResults)) @@ -34,7 +34,7 @@ export const SearchPage = (props: PageProps) => { return ( - + }> diff --git a/src/components/Pages/TopicPage.tsx b/src/components/Pages/TopicPage.tsx index 198be0a0..a92e1d3f 100644 --- a/src/components/Pages/TopicPage.tsx +++ b/src/components/Pages/TopicPage.tsx @@ -4,8 +4,8 @@ import type { PageProps } from '../types' import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js' import { loadArticlesForTopics, resetSortedArticles } from '../../stores/zine/articles' import { useRouter } from '../../stores/router' -import { t } from '../../utils/intl' import { loadTopic } from '../../stores/zine/topics' +import { Loading } from '../Loading' export const TopicPage = (props: PageProps) => { const [isLoaded, setIsLoaded] = createSignal(Boolean(props.authorArticles) && Boolean(props.author)) @@ -37,7 +37,7 @@ export const TopicPage = (props: PageProps) => { return ( - + }> diff --git a/src/components/Views/Author.tsx b/src/components/Views/Author.tsx index d4afed8b..9fb5fb51 100644 --- a/src/components/Views/Author.tsx +++ b/src/components/Views/Author.tsx @@ -9,8 +9,9 @@ import { useAuthorsStore } from '../../stores/zine/authors' import { useArticlesStore } from '../../stores/zine/articles' import '../../styles/Topic.scss' -// import { useTopicsStore } from '../../stores/zine/topics' +import { useTopicsStore } from '../../stores/zine/topics' import { useRouter } from '../../stores/router' +import Beside from '../Feed/Beside' // TODO: load reactions on client type AuthorProps = { @@ -30,6 +31,7 @@ export const AuthorView = (props: AuthorProps) => { sortedArticles: props.authorArticles }) const { authorEntities } = useAuthorsStore({ authors: [props.author] }) + const { topicsByAuthor } = useTopicsStore() const author = createMemo(() => authorEntities()[props.authorSlug]) const { getSearchParams, changeSearchParam } = useRouter() @@ -54,21 +56,22 @@ export const AuthorView = (props: AuthorProps) => { {t('Recent')}
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • + {/*TODO: server sort*/} + {/*
  • */} + {/* */} + {/*
  • */} + {/*
  • */} + {/* */} + {/*
  • */} + {/*
  • */} + {/* */} + {/*
  • */}
    @@ -83,14 +86,13 @@ export const AuthorView = (props: AuthorProps) => {

    {title()}

    0}> - {/*FIXME*/} - {/**/} + diff --git a/src/components/Views/Topic.tsx b/src/components/Views/Topic.tsx index 727c31f5..2f270c24 100644 --- a/src/components/Views/Topic.tsx +++ b/src/components/Views/Topic.tsx @@ -32,14 +32,6 @@ export const TopicView = (props: TopicProps) => { const topic = createMemo(() => topicEntities()[props.topicSlug]) - /* - const slug = createMemo(() => { - let slug = props?.slug - if (props?.slug.startsWith('@')) slug = slug.replace('@', '') - return slug - }) - */ - const title = createMemo(() => { const m = getSearchParams().by if (m === 'viewed') return t('Top viewed') @@ -60,21 +52,22 @@ export const TopicView = (props: TopicProps) => { {t('Recent')} -
  • - -
  • -
  • - -
  • -
  • - -
  • + {/*TODO: server sort*/} + {/*
  • */} + {/* */} + {/*
  • */} + {/*
  • */} + {/* */} + {/*
  • */} + {/*
  • */} + {/* */} + {/*
  • */}
    @@ -108,11 +101,11 @@ export const TopicView = (props: TopicProps) => { beside={sortedArticles()[6]} wrapper={'author'} /> - - - - - + + + + +
    diff --git a/src/graphql/query/authors-all.ts b/src/graphql/query/authors-all.ts index 7afef282..4570a611 100644 --- a/src/graphql/query/authors-all.ts +++ b/src/graphql/query/authors-all.ts @@ -11,7 +11,7 @@ export default gql` communities links createdAt - wasOnlineAt + lastSeen ratings { _id: rater rater diff --git a/src/styles/app.scss b/src/styles/app.scss index 276c43dd..9123f966 100644 --- a/src/styles/app.scss +++ b/src/styles/app.scss @@ -38,6 +38,7 @@ body { &.fixed { overflow: hidden; position: fixed; + width: 100%; } } @@ -534,6 +535,7 @@ astro-island { .main-content { flex: 1 100%; padding-top: 100px; + position: relative; transition: all 1s ease; } From d07050dff5358dd4691f2b35897540135bb5c694 Mon Sep 17 00:00:00 2001 From: kvakazyambra Date: Fri, 14 Oct 2022 21:33:06 +0300 Subject: [PATCH 02/15] Rewrite several components style to css-modules --- public/icons/instagram-white.svg | 4 + .../Author/{Card.scss => Card.module.scss} | 92 +++++- src/components/Author/Card.tsx | 42 ++- src/components/Author/Full.scss | 61 ---- src/components/Author/Full.tsx | 2 +- .../{Userpic.scss => Userpic.module.scss} | 14 + src/components/Author/Userpic.tsx | 9 +- .../Feed/{Beside.scss => Beside.module.scss} | 19 +- src/components/Feed/Beside.tsx | 16 +- .../Feed/{Card.scss => Card.module.scss} | 310 +++++++++--------- src/components/Feed/Card.tsx | 85 +++-- src/components/Feed/CardTopic.module.scss | 26 ++ src/components/Feed/CardTopic.tsx | 20 ++ src/components/Feed/Group.tsx | 36 +- src/components/Feed/Row2.tsx | 7 +- src/components/Feed/Row5.tsx | 6 +- src/components/Feed/RowShort.tsx | 7 +- src/components/Feed/Slider.scss | 14 - src/components/Feed/Slider.tsx | 7 +- src/components/Nav/Private.tsx | 5 - .../Topic/{Card.scss => Card.module.scss} | 30 +- src/components/Topic/Card.tsx | 39 ++- src/components/Views/Author.tsx | 36 +- src/components/Views/Topic.tsx | 5 +- src/styles/app.scss | 58 ++-- 25 files changed, 557 insertions(+), 393 deletions(-) create mode 100644 public/icons/instagram-white.svg rename src/components/Author/{Card.scss => Card.module.scss} (59%) rename src/components/Author/{Userpic.scss => Userpic.module.scss} (72%) rename src/components/Feed/{Beside.scss => Beside.module.scss} (81%) rename src/components/Feed/{Card.scss => Card.module.scss} (66%) create mode 100644 src/components/Feed/CardTopic.module.scss create mode 100644 src/components/Feed/CardTopic.tsx rename src/components/Topic/{Card.scss => Card.module.scss} (77%) diff --git a/public/icons/instagram-white.svg b/public/icons/instagram-white.svg new file mode 100644 index 00000000..baf59f63 --- /dev/null +++ b/public/icons/instagram-white.svg @@ -0,0 +1,4 @@ + + + diff --git a/src/components/Author/Card.scss b/src/components/Author/Card.module.scss similarity index 59% rename from src/components/Author/Card.scss rename to src/components/Author/Card.module.scss index ef1dfa4c..8400502f 100644 --- a/src/components/Author/Card.scss +++ b/src/components/Author/Card.module.scss @@ -8,30 +8,30 @@ } } -.author__details { +.authorDetails { display: flex; flex: 1; padding-right: 1.2rem; width: max-content; } -.author__details-wrapper { +.authorDetailsWrapper { flex: 1; } -.author__name { +.authorName { border: none !important; font-size: 1.7rem; font-weight: 500; margin-bottom: 0.8rem; } -.author__about { +.authorAbout { font-size: 1.5rem; color: rgb(0 0 0 / 60%); } -.author__subscribe { +.authorSubscribe { @include media-breakpoint-down(lg) { padding: 0 0 0 42px; } @@ -43,6 +43,7 @@ height: 32px; margin-right: 0.4rem; position: relative; + transition: background-color 0.2s; vertical-align: middle; width: 32px; @@ -57,8 +58,17 @@ position: absolute; top: 50%; transform: translate(-50%, -50%); + transition: filter 0.2s; width: 18px; } + + &:hover { + background: #000; + + &::before { + filter: invert(0); + } + } } a[href*='facebook.com/'] { @@ -90,9 +100,15 @@ background-image: url(/icons/tumblr-white.svg); } } + + a[href*='instagram.com/'] { + &::before { + background-image: url(/icons/instagram-white.svg); + } + } } -.button--subscribe { +.buttonSubscribe { align-items: center; aspect-ratio: 1/1; background: #f6f6f6; @@ -105,14 +121,15 @@ } } -.button__label { +.buttonLabel { display: none; } -.button--write { +.buttonWrite { background: #f7f7f7; color: #000; display: inline-flex; + @include font-size(1.5rem); .icon { @@ -123,3 +140,62 @@ height: 15px; } } + +.authorPage { + .authorName { + @include font-size(3.4rem); + + font-weight: 500; + margin-bottom: 0.2em; + } + + .authorAbout { + color: #696969; + @include font-size(1.7rem); + } + + .authorSubscribe { + display: flex; + margin-top: 2rem; + } + + .authorDetails { + display: block; + } + + .buttonLabel { + display: block; + } + + .buttonSubscribe { + aspect-ratio: auto; + background-color: #000; + border-radius: 2px; + float: none; + padding-bottom: 0.6rem; + padding-top: 0.6rem; + + .icon { + margin-right: 0.5em; + + img { + filter: invert(1); + } + } + + &:hover { + .icon img { + filter: invert(0.7); + } + } + } + + .buttonSubscribe img { + vertical-align: text-top; + } + + .button { + margin-right: 1.6rem; + vertical-align: middle; + } +} diff --git a/src/components/Author/Card.tsx b/src/components/Author/Card.tsx index 60f2275e..4931f4b3 100644 --- a/src/components/Author/Card.tsx +++ b/src/components/Author/Card.tsx @@ -2,13 +2,14 @@ import { For, Show } from 'solid-js/web' import type { Author } from '../../graphql/types.gen' import Userpic from './Userpic' import { Icon } from '../Nav/Icon' -import './Card.scss' +import style from './Card.module.scss' import { createMemo } from 'solid-js' import { translit } from '../../utils/ru2en' import { t } from '../../utils/intl' import { useAuthStore } from '../../stores/auth' import { locale } from '../../stores/ui' import { follow, unfollow } from '../../stores/zine/common' +import { clsx } from 'clsx' interface AuthorCardProps { compact?: boolean @@ -17,6 +18,7 @@ interface AuthorCardProps { hasLink?: boolean subscribed?: boolean author: Author + isAuthorPage?: boolean } export const AuthorCard = (props: AuthorCardProps) => { @@ -34,45 +36,51 @@ export const AuthorCard = (props: AuthorCardProps) => { } // TODO: reimplement AuthorCard return ( -
    - +
    + -
    -
    +
    +
    - + {name()} -
    {name()}
    +
    {name()}
    -
    {bio()}
    +
    {bio()}
    -