From 3d454793688c206a875c1534684db80230299b12 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Thu, 22 Sep 2022 11:37:49 +0200 Subject: [PATCH] client-routing, fixes --- .eslintrc.js | 11 +- astro.config.ts | 19 +- package.json | 3 + src/components/Article/Comment.tsx | 2 +- src/components/Article/FullArticle.tsx | 33 ++- src/components/Author/Card.tsx | 2 +- src/components/Discours/Footer.tsx | 2 +- src/components/Feed/Beside.tsx | 2 +- src/components/Feed/Card.tsx | 139 +++++----- src/components/Feed/Row5.tsx | 34 ++- src/components/Feed/Sidebar.tsx | 2 +- src/components/Feed/Slider.tsx | 2 +- src/components/Layouts/MainLayout.tsx | 20 ++ src/components/Nav/AuthModal.tsx | 4 +- src/components/Nav/Header.tsx | 58 ++-- src/components/Nav/Icon.tsx | 2 +- src/components/Nav/Private.tsx | 13 +- src/components/Nav/Topics.tsx | 7 +- src/components/Pages/AllAuthorsPage.tsx | 14 + src/components/Pages/AllTopicsPage.tsx | 14 + src/components/Pages/ArticlePage.tsx | 46 ++++ src/components/Pages/AuthorPage.tsx | 14 + src/components/Pages/FeedPage.tsx | 14 + src/components/Pages/FourOuFourPage.tsx | 13 + src/components/Pages/HomePage.tsx | 14 + src/components/Pages/SearchPage.tsx | 14 + src/components/Pages/TopicPage.tsx | 14 + src/components/Root.tsx | 64 +++++ src/components/Topic/FloorHeader.tsx | 2 +- src/components/Views/AllAuthors.tsx | 34 ++- src/components/Views/AllTopics.tsx | 66 ++--- .../Views/{ArticlePage.tsx => Article.tsx} | 18 +- src/components/Views/Author.tsx | 51 ++-- src/components/Views/Community.tsx | 21 -- src/components/Views/Connect.tsx | 2 +- src/components/Views/Create.tsx | 2 +- src/components/Views/Feed.tsx | 21 +- src/components/Views/FeedSettings.tsx | 17 +- src/components/Views/FourOuFour.tsx | 4 +- src/components/Views/Home.tsx | 234 ++++++++-------- src/components/Views/Inbox.tsx | 14 +- src/components/Views/Search.tsx | 36 ++- src/components/Views/Topic.tsx | 37 +-- .../providers/ServerRouterProvider.tsx | 15 -- src/components/types.ts | 16 ++ src/graphql/auth.ts | 105 -------- src/graphql/privateGraphQLClient.ts | 6 +- src/graphql/publicGraphQLClient.ts | 4 +- src/graphql/types.gen.ts | 21 +- src/layouts/zine.astro | 43 ++- src/pages/404.astro | 5 +- src/pages/[...slug].astro | 7 +- src/pages/author/[slug]/index.astro | 8 +- .../{reactions.astro => reactions.astro.bak} | 0 src/pages/authors.astro | 10 +- src/pages/create.astro | 4 +- src/pages/feed/index.astro | 10 +- .../{settings.astro => settings.astro.bak} | 0 src/pages/{inbox.astro => inbox.astro.bak} | 0 src/pages/index.astro | 19 +- src/pages/search.astro | 6 +- src/pages/topic/[slug].astro | 8 +- src/pages/topics.astro | 11 +- src/stores/router.ts | 92 ++++--- src/stores/zine/articles.ts | 98 ++++--- src/stores/zine/authors.ts | 17 +- src/stores/zine/currentArticle.ts | 25 -- src/stores/zine/topAuthors.ts | 37 +++ src/stores/zine/topics.ts | 66 +++-- src/utils/apiClient.ts | 17 +- src/utils/config.ts | 1 + src/utils/intl.ts | 2 +- src/utils/logger.ts | 4 +- src/utils/sortby.ts | 14 +- ssr/server.mjs | 46 ---- yarn.lock | 252 +++++++++++++++++- 76 files changed, 1252 insertions(+), 852 deletions(-) create mode 100644 src/components/Layouts/MainLayout.tsx create mode 100644 src/components/Pages/AllAuthorsPage.tsx create mode 100644 src/components/Pages/AllTopicsPage.tsx create mode 100644 src/components/Pages/ArticlePage.tsx create mode 100644 src/components/Pages/AuthorPage.tsx create mode 100644 src/components/Pages/FeedPage.tsx create mode 100644 src/components/Pages/FourOuFourPage.tsx create mode 100644 src/components/Pages/HomePage.tsx create mode 100644 src/components/Pages/SearchPage.tsx create mode 100644 src/components/Pages/TopicPage.tsx create mode 100644 src/components/Root.tsx rename src/components/Views/{ArticlePage.tsx => Article.tsx} (68%) delete mode 100644 src/components/Views/Community.tsx delete mode 100644 src/components/providers/ServerRouterProvider.tsx create mode 100644 src/components/types.ts delete mode 100644 src/graphql/auth.ts rename src/pages/author/[slug]/{reactions.astro => reactions.astro.bak} (100%) rename src/pages/feed/{settings.astro => settings.astro.bak} (100%) rename src/pages/{inbox.astro => inbox.astro.bak} (100%) delete mode 100644 src/stores/zine/currentArticle.ts create mode 100644 src/stores/zine/topAuthors.ts create mode 100644 src/utils/config.ts delete mode 100644 ssr/server.mjs diff --git a/.eslintrc.js b/.eslintrc.js index d535701b..c0284d22 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -27,7 +27,13 @@ module.exports = { // 'plugin:@typescript-eslint/recommended-requiring-type-checking' ], rules: { - '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], + '@typescript-eslint/no-unused-vars': [ + 'warn', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^log$' + } + ], // TODO: Remove any usage and enable '@typescript-eslint/no-explicit-any': 'off', // TODO: Fix errors and enable this rule @@ -45,9 +51,6 @@ module.exports = { }, globals: {}, rules: { - // FIXME: turn on - 'import/no-default-export': 'off', - // FIXME 'unicorn/prefer-dom-node-append': 'off', diff --git a/astro.config.ts b/astro.config.ts index 4b91f8b2..f96f43f9 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -10,11 +10,20 @@ import type { CSSOptions } from 'vite' // const dev = process.env.NODE_ENV != 'production' +const css: CSSOptions = { + preprocessorOptions: { + scss: { + additionalData: '@import "src/styles/imports";\n' + } + } +} + const astroConfig: AstroUserConfig = { site: 'https://new.discours.io', // Enable Solid to support Solid JSX components. // experimental: { integrations: true }, - integrations: [solidJs(), mdx()], // sitemap({ + integrations: [solidJs(), mdx()], + // sitemap({ /* customPages: [ '', '/feed', @@ -39,13 +48,7 @@ const astroConfig: AstroUserConfig = { '@': './src' } }, - css: { - preprocessorOptions: { - scss: { - additionalData: '@import "src/styles/imports";\n' - } - } - } as CSSOptions + css } } diff --git a/package.json b/package.json index 36dae1d1..6dac40a2 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,8 @@ "@graphql-codegen/urql-introspection": "^2.2.1", "@graphql-typed-document-node/core": "^3.1.1", "@popperjs/core": "^2.11.5", + "@solid-devtools/debugger": "^0.9.0", + "@solid-devtools/logger": "^0.4.7", "@solid-primitives/clipboard": "^1.3.0", "@solid-primitives/event-listener": "^2.2.0", "@solid-primitives/intersection-observer": "^2.0.0", @@ -124,6 +126,7 @@ "prosemirror-view": "^1.26.2", "rollup": "~2.5.0", "sass": "^1.54.0", + "solid-devtools": "^0.16.2", "solid-js": "^1.5.3", "solid-js-form": "^0.1.5", "solid-jsx": "^0.9.0", diff --git a/src/components/Article/Comment.tsx b/src/components/Article/Comment.tsx index 6ebfe41c..491857be 100644 --- a/src/components/Article/Comment.tsx +++ b/src/components/Article/Comment.tsx @@ -1,5 +1,5 @@ import './Comment.scss' -import Icon from '../Nav/Icon' +import { Icon } from '../Nav/Icon' import { AuthorCard } from '../Author/Card' import { Show } from 'solid-js/web' import { clsx } from 'clsx' diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx index b5fce7aa..317acc88 100644 --- a/src/components/Article/FullArticle.tsx +++ b/src/components/Article/FullArticle.tsx @@ -1,17 +1,17 @@ import { capitalize } from '../../utils' import './Full.scss' -import Icon from '../Nav/Icon' +import { Icon } from '../Nav/Icon' import ArticleComment from './Comment' import { AuthorCard } from '../Author/Card' -import { createMemo, createSignal, For, onMount, Show } from 'solid-js' +import { createEffect, createMemo, createSignal, For, onMount, Show } from 'solid-js' import type { Author, Reaction, Shout } from '../../graphql/types.gen' import { t } from '../../utils/intl' import { showModal } from '../../stores/ui' -import { renderMarkdown } from '@astrojs/markdown-remark' -import { markdownOptions } from '../../../mdx.config' import { useStore } from '@nanostores/solid' import { session } from '../../stores/auth' -import { incrementView, loadArticle } from '../../stores/zine/articles' +import { incrementView } from '../../stores/zine/articles' +import { renderMarkdown } from '@astrojs/markdown-remark' +import { markdownOptions } from '../../../mdx.config' const MAX_COMMENT_LEVEL = 6 @@ -39,25 +39,22 @@ const formatDate = (date: Date) => { } export const FullArticle = (props: ArticleProps) => { - const [body, setBody] = createSignal('') + const [body, setBody] = createSignal(props.article.body?.startsWith('<') ? props.article.body : '') const auth = useStore(session) - onMount(() => { - if (!props.article.body) { - loadArticle({ slug: props.article.slug }) + createEffect(() => { + if (body() || !props.article.body) { + return + } + + if (props.article.body.startsWith('<')) { + setBody(props.article.body) + } else { + renderMarkdown(props.article.body, markdownOptions).then(({ code }) => setBody(code)) } }) - // onMount(() => { - // const b: string = props.article?.body - // if (b?.toString().startsWith('<')) { - // setBody(b) - // } else { - // renderMarkdown(b, markdownOptions).then(({ code }) => setBody(code)) - // } - // }) - onMount(() => { incrementView({ articleSlug: props.article.slug }) }) diff --git a/src/components/Author/Card.tsx b/src/components/Author/Card.tsx index 091dcf74..a953ae9a 100644 --- a/src/components/Author/Card.tsx +++ b/src/components/Author/Card.tsx @@ -1,7 +1,7 @@ import { For, Show } from 'solid-js/web' import type { Author } from '../../graphql/types.gen' import Userpic from './Userpic' -import Icon from '../Nav/Icon' +import { Icon } from '../Nav/Icon' import './Card.scss' import { createMemo } from 'solid-js' import { translit } from '../../utils/ru2en' diff --git a/src/components/Discours/Footer.tsx b/src/components/Discours/Footer.tsx index e3f6d116..e2283c5a 100644 --- a/src/components/Discours/Footer.tsx +++ b/src/components/Discours/Footer.tsx @@ -1,6 +1,6 @@ import { createMemo, For } from 'solid-js' import './Footer.scss' -import Icon from '../Nav/Icon' +import { Icon } from '../Nav/Icon' import Subscribe from './Subscribe' import { t } from '../../utils/intl' import { locale as locstore } from '../../stores/ui' diff --git a/src/components/Feed/Beside.tsx b/src/components/Feed/Beside.tsx index e2d9e28f..bfa3a8c3 100644 --- a/src/components/Feed/Beside.tsx +++ b/src/components/Feed/Beside.tsx @@ -6,7 +6,7 @@ import { AuthorCard } from '../Author/Card' import { TopicCard } from '../Topic/Card' import './Beside.scss' import type { Author, Shout, Topic, User } from '../../graphql/types.gen' -import Icon from '../Nav/Icon' +import { Icon } from '../Nav/Icon' import { t } from '../../utils/intl' interface BesideProps { diff --git a/src/components/Feed/Card.tsx b/src/components/Feed/Card.tsx index 6a1687ae..49d4bdd1 100644 --- a/src/components/Feed/Card.tsx +++ b/src/components/Feed/Card.tsx @@ -1,13 +1,17 @@ import { t } from '../../utils/intl' -import { createEffect, createMemo, createSignal, onMount } from 'solid-js' +import { createMemo } from 'solid-js' import { For, Show } from 'solid-js/web' -import type { Author, Shout, Topic } from '../../graphql/types.gen' +import type { Shout } from '../../graphql/types.gen' import { capitalize } from '../../utils' import { translit } from '../../utils/ru2en' -import Icon from '../Nav/Icon' +import { Icon } from '../Nav/Icon' import './Card.scss' import { locale as localestore } from '../../stores/ui' import { useStore } from '@nanostores/solid' +import { handleClientRouteLinkClick } from '../../stores/router' +import { getLogger } from '../../utils/logger' + +const log = getLogger('card component') interface ArticleCardProps { settings?: { @@ -24,45 +28,43 @@ interface ArticleCardProps { article: Shout } -export const ArticleCard = (props: ArticleCardProps) => { - const locale = useStore(localestore) +const getTitleAndSubtitle = (article: Shout): { title: string; subtitle: string } => { + let title = article.title + let subtitle = article.subtitle - const [title, setTitle] = createSignal('') - const [subtitle, setSubtitle] = createSignal('') + if (!subtitle) { + let tt = article.title?.split('. ') || [] - const article = createMemo(() => props.article) - const authors = createMemo(() => article().authors) - const mainTopic = createMemo(() => - props.article.topics.find((articleTopic) => articleTopic.slug === props.article.mainTopic) - ) + if (tt?.length === 1) { + tt = article.title?.split(/{!|\?|:|;}\s/) || [] + } - const detectSubtitle = () => { - const a = article() - setTitle(a.title || '') - if (!a.subtitle) { - let tt: string[] = a.title?.split('. ') || [] - if (tt?.length === 1) tt = a.title?.split(/{!|\?|:|;}\s/) || [] - if (tt && tt.length > 1) { - const sep = a.title?.replace(tt[0], '').split(' ', 1)[0] - setTitle(tt[0] + (!(sep === '.' || sep === ':') ? sep : '')) - setSubtitle(capitalize(a.title?.replace(tt[0] + sep, ''), true)) - } - } else { - setSubtitle(a.subtitle || '') + if (tt && tt.length > 1) { + const sep = article.title?.replace(tt[0], '').split(' ', 1)[0] + title = tt[0] + (!(sep === '.' || sep === ':') ? sep : '') + subtitle = capitalize(article.title?.replace(tt[0] + sep, ''), true) } } - // FIXME: move this to store action - const translateAuthors = () => { - const aaa = new Set(article().authors) - aaa.forEach((a) => { - a.name = - a.name === 'Дискурс' && locale() !== 'ru' ? 'Discours' : translit(a.name || '', locale() || 'ru') - }) - return [...aaa] - } - createEffect(translateAuthors, [article(), locale()]) - onMount(detectSubtitle) + return { title, subtitle } +} + +export const ArticleCard = (props: ArticleCardProps) => { + const locale = useStore(localestore) + + const mainTopic = props.article.topics.find( + (articleTopic) => articleTopic.slug === props.article.mainTopic + ) + + const formattedDate = createMemo(() => { + return new Date(props.article.createdAt) + .toLocaleDateString(locale(), { month: 'long', day: 'numeric', year: 'numeric' }) + .replace(' г.', '') + }) + + const { title, subtitle } = getTitleAndSubtitle(props.article) + + const { cover, layout, slug, authors, stat } = props.article return (
{ 'shout-card--feed': props.settings?.isFeedMode }} > - - + +
- {props.article.title + {title
- +
- {title()} + {title}
- +
- {subtitle()} + {subtitle}
@@ -125,23 +121,26 @@ export const ArticleCard = (props: ArticleCardProps) => {
- - {(a: Author) => ( - <> - 0}>, - {a.name} - - )} + + {(author, index) => { + const name = + author.name === 'Дискурс' && locale() !== 'ru' + ? 'Discours' + : translit(author.name || '', locale() || 'ru') + + return ( + <> + 0}>, + {name} + + ) + }}
-
- {new Date(props.article.createdAt) - .toLocaleDateString(locale(), { month: 'long', day: 'numeric', year: 'numeric' }) - .replace(' г.', '')} -
+
{formattedDate()}
@@ -151,17 +150,17 @@ export const ArticleCard = (props: ArticleCardProps) => {
- {props.article.stat?.rating || ''} + {stat?.rating || ''}
- {props.article.stat?.viewed} + {stat?.viewed}
diff --git a/src/components/Feed/Row5.tsx b/src/components/Feed/Row5.tsx index 8e95b695..232176ad 100644 --- a/src/components/Feed/Row5.tsx +++ b/src/components/Feed/Row5.tsx @@ -1,19 +1,25 @@ -import { For } from 'solid-js' import type { Shout } from '../../graphql/types.gen' import { ArticleCard } from './Card' +import { getLogger } from '../../utils/logger' -export default (props: { articles: Shout[] }) => ( -
-
-
- {(a) => } -
-
- {(a) => } -
-
- {(a) => } +const log = getLogger('Row5') + +export const Row5 = (props: { articles: Shout[] }) => { + return ( +
+
+
+ + +
+
+ +
+
+ + +
-
-) + ) +} diff --git a/src/components/Feed/Sidebar.tsx b/src/components/Feed/Sidebar.tsx index a89f648c..09cfc0ca 100644 --- a/src/components/Feed/Sidebar.tsx +++ b/src/components/Feed/Sidebar.tsx @@ -4,7 +4,7 @@ import type { Author } from '../../graphql/types.gen' import { session } from '../../stores/auth' import { useAuthorsStore } from '../../stores/zine/authors' import { t } from '../../utils/intl' -import Icon from '../Nav/Icon' +import { Icon } from '../Nav/Icon' import { useTopicsStore } from '../../stores/zine/topics' import { useArticlesStore } from '../../stores/zine/articles' import { useSeenStore } from '../../stores/zine/seen' diff --git a/src/components/Feed/Slider.tsx b/src/components/Feed/Slider.tsx index 7391aa40..3278e7ac 100644 --- a/src/components/Feed/Slider.tsx +++ b/src/components/Feed/Slider.tsx @@ -8,7 +8,7 @@ import 'swiper/scss/pagination' import './Slider.scss' import type { Shout } from '../../graphql/types.gen' import { createEffect, createMemo, createSignal, Show } from 'solid-js' -import Icon from '../Nav/Icon' +import { Icon } from '../Nav/Icon' interface SliderProps { title?: string diff --git a/src/components/Layouts/MainLayout.tsx b/src/components/Layouts/MainLayout.tsx new file mode 100644 index 00000000..4a0e8c49 --- /dev/null +++ b/src/components/Layouts/MainLayout.tsx @@ -0,0 +1,20 @@ +import type { JSX } from 'solid-js' +import { Header } from '../Nav/Header' +import { Footer } from '../Discours/Footer' + +import '../../styles/app.scss' + +type Props = { + headerTitle?: string + children: JSX.Element +} + +export const MainLayout = (props: Props) => { + return ( + <> +
+
{props.children}
+