refactoring-wpi
This commit is contained in:
parent
e6a14c6fa1
commit
28f52ba745
|
@ -2,7 +2,7 @@ import { defineConfig, AstroUserConfig } from 'astro/config'
|
||||||
import vercel from '@astrojs/vercel/serverless'
|
import vercel from '@astrojs/vercel/serverless'
|
||||||
import solidJs from '@astrojs/solid-js'
|
import solidJs from '@astrojs/solid-js'
|
||||||
import type { CSSOptions } from 'vite'
|
import type { CSSOptions } from 'vite'
|
||||||
import { generateScopedNameDefault } from 'postcss-modules/build/scoping'
|
import defaultGenerateScopedName from 'postcss-modules/build/generateScopedName'
|
||||||
import { isDev } from './src/utils/config'
|
import { isDev } from './src/utils/config'
|
||||||
import { visualizer } from 'rollup-plugin-visualizer'
|
import { visualizer } from 'rollup-plugin-visualizer'
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ const getDevCssClassPrefix = (filename: string): string => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const devGenerateScopedName = (name: string, filename: string, css: string) =>
|
const devGenerateScopedName = (name: string, filename: string, css: string) =>
|
||||||
getDevCssClassPrefix(filename) + '_' + generateScopedNameDefault(name, filename, css)
|
getDevCssClassPrefix(filename) + '_' + defaultGenerateScopedName(name, filename, css)
|
||||||
|
|
||||||
const css: CSSOptions = {
|
const css: CSSOptions = {
|
||||||
preprocessorOptions: {
|
preprocessorOptions: {
|
||||||
|
@ -25,7 +25,7 @@ const css: CSSOptions = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modules: {
|
modules: {
|
||||||
generateScopedName: isDev ? devGenerateScopedName : generateScopedNameDefault,
|
generateScopedName: isDev ? devGenerateScopedName : defaultGenerateScopedName,
|
||||||
localsConvention: null
|
localsConvention: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ const astroConfig: AstroUserConfig = {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
},
|
},
|
||||||
external: ['@aws-sdk/clients/s3']
|
external: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
css
|
css
|
||||||
|
|
|
@ -94,7 +94,7 @@
|
||||||
"nanostores": "^0.7.0",
|
"nanostores": "^0.7.0",
|
||||||
"orderedmap": "^2.1.0",
|
"orderedmap": "^2.1.0",
|
||||||
"postcss": "^8.4.19",
|
"postcss": "^8.4.19",
|
||||||
"postcss-modules": "^6.0.0",
|
"postcss-modules": "5.0.0",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"prettier-eslint": "^15.0.1",
|
"prettier-eslint": "^15.0.1",
|
||||||
"prosemirror-commands": "^1.3.1",
|
"prosemirror-commands": "^1.3.1",
|
||||||
|
|
|
@ -63,7 +63,7 @@ specifiers:
|
||||||
nanostores: ^0.7.0
|
nanostores: ^0.7.0
|
||||||
orderedmap: ^2.1.0
|
orderedmap: ^2.1.0
|
||||||
postcss: ^8.4.19
|
postcss: ^8.4.19
|
||||||
postcss-modules: ^6.0.0
|
postcss-modules: 5.0.0
|
||||||
prettier: ^2.7.1
|
prettier: ^2.7.1
|
||||||
prettier-eslint: ^15.0.1
|
prettier-eslint: ^15.0.1
|
||||||
prosemirror-commands: ^1.3.1
|
prosemirror-commands: ^1.3.1
|
||||||
|
@ -173,7 +173,7 @@ devDependencies:
|
||||||
nanostores: 0.7.0
|
nanostores: 0.7.0
|
||||||
orderedmap: 2.1.0
|
orderedmap: 2.1.0
|
||||||
postcss: 8.4.19
|
postcss: 8.4.19
|
||||||
postcss-modules: 6.0.0_postcss@8.4.19
|
postcss-modules: 5.0.0_postcss@8.4.19
|
||||||
prettier: 2.7.1
|
prettier: 2.7.1
|
||||||
prettier-eslint: 15.0.1
|
prettier-eslint: 15.0.1
|
||||||
prosemirror-commands: 1.3.1
|
prosemirror-commands: 1.3.1
|
||||||
|
@ -6087,6 +6087,10 @@ packages:
|
||||||
safer-buffer: 2.1.2
|
safer-buffer: 2.1.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/icss-replace-symbols/1.1.0:
|
||||||
|
resolution: {integrity: sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/icss-utils/5.1.0_postcss@8.4.19:
|
/icss-utils/5.1.0_postcss@8.4.19:
|
||||||
resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==}
|
resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==}
|
||||||
engines: {node: ^10 || ^12 || >= 14}
|
engines: {node: ^10 || ^12 || >= 14}
|
||||||
|
@ -8577,13 +8581,13 @@ packages:
|
||||||
postcss: 8.4.19
|
postcss: 8.4.19
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/postcss-modules/6.0.0_postcss@8.4.19:
|
/postcss-modules/5.0.0_postcss@8.4.19:
|
||||||
resolution: {integrity: sha512-7DGfnlyi/ju82BRzTIjWS5C4Tafmzl3R79YP/PASiocj+aa6yYphHhhKUOEoXQToId5rgyFgJ88+ccOUydjBXQ==}
|
resolution: {integrity: sha512-rGvpTDOM3//3Ysn3Xtvhzaj8ab984wKCpP02TEF559tLbUjNay3RQDpPxb7BREmfBtJm3/1WbQOZ7fSXwYLZ/w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
postcss: ^8.0.0
|
postcss: ^8.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
generic-names: 4.0.0
|
generic-names: 4.0.0
|
||||||
icss-utils: 5.1.0_postcss@8.4.19
|
icss-replace-symbols: 1.1.0
|
||||||
lodash.camelcase: 4.3.0
|
lodash.camelcase: 4.3.0
|
||||||
postcss: 8.4.19
|
postcss: 8.4.19
|
||||||
postcss-modules-extract-imports: 3.0.0_postcss@8.4.19
|
postcss-modules-extract-imports: 3.0.0_postcss@8.4.19
|
||||||
|
|
4
public/icons/audio.svg
Normal file
4
public/icons/audio.svg
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="13" height="14" viewBox="0 0 13 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M11.1853 7.68061L11.1746 2.64865L5.05266 3.68025C5.04861 8.28981 5.04659 10.9099 5.04659 11.5405L5.04077 11.5326C4.95203 12.9109 3.85883 14 2.52329 14C1.12972 14 0 12.8142 0 11.3514C0 9.88854 1.12972 8.7027 2.52329 8.7027C2.77381 8.7027 3.0158 8.74102 3.24423 8.81239V1.7027L12.9769 0C13.0077 6.85087 13.0077 10.3193 12.9769 10.4054L12.9711 10.398C12.8821 11.776 11.789 12.8649 10.4536 12.8649C9.06007 12.8649 7.93035 11.679 7.93035 10.2162C7.93035 8.75341 9.06007 7.56757 10.4536 7.56757C10.7081 7.56757 10.9537 7.60709 11.1853 7.68061Z" fill="currentColor"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 675 B |
1
public/icons/literature.svg
Normal file
1
public/icons/literature.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg width="12" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3.969 1.688l6.181 2.18v12.88H12V2.722L4.2 0 0 1.47v13.668L7.436 18H8.55V4.532L2.147 2.265l1.822-.577z" fill="currentColor"/></svg>
|
After Width: | Height: | Size: 216 B |
|
@ -1,10 +1,10 @@
|
||||||
import { PageWrap } from '../Wraps/PageWrap'
|
import { PageWrap } from '../Wraps/PageWrap'
|
||||||
import { LayoutView } from '../Views/LayoutView'
|
import { LayoutType, LayoutView } from '../Views/LayoutView'
|
||||||
import type { PageProps } from '../types'
|
import type { PageProps } from '../types'
|
||||||
import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js'
|
import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js'
|
||||||
import { resetSortedArticles } from '../../stores/zine/articles'
|
import { resetSortedArticles } from '../../stores/zine/articles'
|
||||||
import { useRouter } from '../../stores/router'
|
import { useRouter } from '../../stores/router'
|
||||||
import { loadLayoutShouts } from '../../stores/zine/layouts'
|
import { loadRecentLayoutShouts } from '../../stores/zine/layouts'
|
||||||
import { Loading } from '../Loading'
|
import { Loading } from '../Loading'
|
||||||
|
|
||||||
const PER_PAGE = 50
|
const PER_PAGE = 50
|
||||||
|
@ -12,7 +12,7 @@ const PER_PAGE = 50
|
||||||
export const LayoutShoutsPage = (props: PageProps) => {
|
export const LayoutShoutsPage = (props: PageProps) => {
|
||||||
const [isLoaded, setIsLoaded] = createSignal(Boolean(props.shouts))
|
const [isLoaded, setIsLoaded] = createSignal(Boolean(props.shouts))
|
||||||
|
|
||||||
const layout = createMemo(() => {
|
const layout = createMemo<LayoutType>(() => {
|
||||||
const { page: getPage } = useRouter()
|
const { page: getPage } = useRouter()
|
||||||
|
|
||||||
const page = getPage()
|
const page = getPage()
|
||||||
|
@ -21,7 +21,7 @@ export const LayoutShoutsPage = (props: PageProps) => {
|
||||||
throw new Error('ts guard')
|
throw new Error('ts guard')
|
||||||
}
|
}
|
||||||
|
|
||||||
return page.params.layout
|
return page.params.layout as LayoutType
|
||||||
})
|
})
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
|
@ -29,7 +29,7 @@ export const LayoutShoutsPage = (props: PageProps) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await loadLayoutShouts({ layout: layout(), amount: PER_PAGE, offset: 0 })
|
await loadRecentLayoutShouts({ layout: layout(), amount: PER_PAGE, offset: 0 })
|
||||||
|
|
||||||
setIsLoaded(true)
|
setIsLoaded(true)
|
||||||
})
|
})
|
||||||
|
@ -39,7 +39,7 @@ export const LayoutShoutsPage = (props: PageProps) => {
|
||||||
return (
|
return (
|
||||||
<PageWrap>
|
<PageWrap>
|
||||||
<Show when={isLoaded()} fallback={<Loading />}>
|
<Show when={isLoaded()} fallback={<Loading />}>
|
||||||
<LayoutView layout={layout()} shouts={props.shouts} />
|
<LayoutView layout={layout() as LayoutType} shouts={props.shouts} />
|
||||||
</Show>
|
</Show>
|
||||||
</PageWrap>
|
</PageWrap>
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { handleClientRouteLinkClick } from '../../stores/router'
|
||||||
// by: '' | 'topics' | 'authors' | 'reacted'
|
// by: '' | 'topics' | 'authors' | 'reacted'
|
||||||
// }
|
// }
|
||||||
|
|
||||||
export const FeedSettingsView = () => {
|
export const FeedSettingsView = (_props) => {
|
||||||
return (
|
return (
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>{t('Feed settings')}</h1>
|
<h1>{t('Feed settings')}</h1>
|
||||||
|
|
|
@ -5,21 +5,18 @@ import { Row2 } from '../Feed/Row2'
|
||||||
import { Beside } from '../Feed/Beside'
|
import { Beside } from '../Feed/Beside'
|
||||||
import styles from '../../styles/Topic.module.scss'
|
import styles from '../../styles/Topic.module.scss'
|
||||||
import { t } from '../../utils/intl'
|
import { t } from '../../utils/intl'
|
||||||
import { useRouter } from '../../stores/router'
|
import { useLayoutsStore } from '../../stores/zine/layouts'
|
||||||
import { useArticlesStore } from '../../stores/zine/articles'
|
|
||||||
import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll'
|
import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll'
|
||||||
import { splitToPages } from '../../utils/splitToPages'
|
import { splitToPages } from '../../utils/splitToPages'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import Slider from '../Feed/Slider'
|
import Slider from '../Feed/Slider'
|
||||||
import { Row1 } from '../Feed/Row1'
|
import { Row1 } from '../Feed/Row1'
|
||||||
import { loadLayoutShouts } from '../../stores/zine/layouts'
|
import { loadRecentLayoutShouts } from '../../stores/zine/layouts'
|
||||||
|
|
||||||
type LayoutPageSearchParams = {
|
export type LayoutType = 'article' | 'audio' | 'video' | 'image' | 'literature'
|
||||||
layout: 'audio' | 'video' | 'image' | 'literature'
|
|
||||||
}
|
|
||||||
|
|
||||||
interface LayoutProps {
|
interface LayoutProps {
|
||||||
layout: string
|
layout: LayoutType
|
||||||
shouts: Shout[]
|
shouts: Shout[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,34 +24,30 @@ export const PRERENDERED_ARTICLES_COUNT = 21
|
||||||
const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3
|
const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3
|
||||||
|
|
||||||
export const LayoutView = (props: LayoutProps) => {
|
export const LayoutView = (props: LayoutProps) => {
|
||||||
const { searchParams, changeSearchParam } = useRouter<LayoutPageSearchParams>()
|
const layout = createMemo<LayoutType>(() => props.layout)
|
||||||
|
|
||||||
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
||||||
|
const { sortedLayoutShouts } = useLayoutsStore(layout(), props.shouts)
|
||||||
const { sortedArticles } = useArticlesStore({ sortedArticles: props.shouts })
|
const sortedArticles = createMemo(() => sortedLayoutShouts().get(layout()))
|
||||||
const layout = createMemo(() => props.layout)
|
const loadMoreLayout = async (kind: LayoutType) => {
|
||||||
|
|
||||||
const loadMoreLayout = async (kind: string) => {
|
|
||||||
saveScrollPosition()
|
saveScrollPosition()
|
||||||
|
|
||||||
const { hasMore } = await loadLayoutShouts({
|
const { hasMore } = await loadRecentLayoutShouts({
|
||||||
layout: kind,
|
layout: kind,
|
||||||
amount: LOAD_MORE_PAGE_SIZE,
|
amount: LOAD_MORE_PAGE_SIZE,
|
||||||
offset: sortedArticles().length
|
offset: sortedArticles().length
|
||||||
})
|
})
|
||||||
setIsLoadMoreButtonVisible(hasMore)
|
setIsLoadMoreButtonVisible(hasMore)
|
||||||
|
|
||||||
restoreScrollPosition()
|
restoreScrollPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) {
|
if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) {
|
||||||
loadMoreLayout(searchParams().layout)
|
loadMoreLayout(layout())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const title = createMemo(() => {
|
const title = createMemo(() => {
|
||||||
const l = searchParams().layout
|
const l = layout()
|
||||||
if (l === 'audio') return t('Audio')
|
if (l === 'audio') return t('Audio')
|
||||||
if (l === 'video') return t('Video')
|
if (l === 'video') return t('Video')
|
||||||
if (l === 'image') return t('Artworks')
|
if (l === 'image') return t('Artworks')
|
||||||
|
@ -70,16 +63,16 @@ export const LayoutView = (props: LayoutProps) => {
|
||||||
<div class={clsx(styles.groupControls, 'row group__controls')}>
|
<div class={clsx(styles.groupControls, 'row group__controls')}>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<ul class="view-switcher">
|
<ul class="view-switcher">
|
||||||
<li classList={{ selected: searchParams().layout === 'audio' }}>
|
<li classList={{ selected: layout() === 'audio' }}>
|
||||||
<a href="/expo/audio">{t('Audio')}</a>
|
<a href="/expo/audio">{t('Audio')}</a>
|
||||||
</li>
|
</li>
|
||||||
<li classList={{ selected: searchParams().layout === 'video' }}>
|
<li classList={{ selected: layout() === 'video' }}>
|
||||||
<a href="/expo/video">{t('Video')}</a>
|
<a href="/expo/video">{t('Video')}</a>
|
||||||
</li>
|
</li>
|
||||||
<li classList={{ selected: searchParams().layout === 'image' }}>
|
<li classList={{ selected: layout() === 'image' }}>
|
||||||
<a href="/expo/image">{t('Artworks')}</a>
|
<a href="/expo/image">{t('Artworks')}</a>
|
||||||
</li>
|
</li>
|
||||||
<li classList={{ selected: searchParams().layout === 'literature' || !searchParams().layout }}>
|
<li classList={{ selected: layout() === 'literature' }}>
|
||||||
<a href="/expo/literature">{t('Literature')}</a>
|
<a href="/expo/literature">{t('Literature')}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -129,7 +122,7 @@ export const LayoutView = (props: LayoutProps) => {
|
||||||
|
|
||||||
<Show when={isLoadMoreButtonVisible()}>
|
<Show when={isLoadMoreButtonVisible()}>
|
||||||
<p class="load-more-container">
|
<p class="load-more-container">
|
||||||
<button class="button" onClick={() => loadMoreLayout(searchParams().layout)}>
|
<button class="button" onClick={() => loadMoreLayout(layout())}>
|
||||||
{t('Load more')}
|
{t('Load more')}
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
|
|
40
src/graphql/query/layout-recent.ts
Normal file
40
src/graphql/query/layout-recent.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { gql } from '@urql/core'
|
||||||
|
|
||||||
|
export default gql`
|
||||||
|
query RecentShoutsForLayout($layout: String!, $amount: Int, $offset: Int) {
|
||||||
|
recentLayoutShouts(layout: $layout, amount: $amount, offset: $offset) {
|
||||||
|
_id: slug
|
||||||
|
title
|
||||||
|
subtitle
|
||||||
|
layout
|
||||||
|
slug
|
||||||
|
cover
|
||||||
|
# community
|
||||||
|
mainTopic
|
||||||
|
topics {
|
||||||
|
title
|
||||||
|
body
|
||||||
|
slug
|
||||||
|
stat {
|
||||||
|
_id: shouts
|
||||||
|
shouts
|
||||||
|
authors
|
||||||
|
followers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
authors {
|
||||||
|
_id: slug
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
userpic
|
||||||
|
}
|
||||||
|
createdAt
|
||||||
|
publishedAt
|
||||||
|
stat {
|
||||||
|
_id: viewed
|
||||||
|
viewed
|
||||||
|
reacted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
40
src/graphql/query/layout-top-month.ts
Normal file
40
src/graphql/query/layout-top-month.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { gql } from '@urql/core'
|
||||||
|
|
||||||
|
export default gql`
|
||||||
|
query TopMonthShoutsForLayout($layout: String!, $amount: Int, $offset: Int) {
|
||||||
|
topMonthLayoutShouts(layout: $layout, amount: $amount, offset: $offset) {
|
||||||
|
_id: slug
|
||||||
|
title
|
||||||
|
subtitle
|
||||||
|
layout
|
||||||
|
slug
|
||||||
|
cover
|
||||||
|
# community
|
||||||
|
mainTopic
|
||||||
|
topics {
|
||||||
|
title
|
||||||
|
body
|
||||||
|
slug
|
||||||
|
stat {
|
||||||
|
_id: shouts
|
||||||
|
shouts
|
||||||
|
authors
|
||||||
|
followers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
authors {
|
||||||
|
_id: slug
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
userpic
|
||||||
|
}
|
||||||
|
createdAt
|
||||||
|
publishedAt
|
||||||
|
stat {
|
||||||
|
_id: viewed
|
||||||
|
viewed
|
||||||
|
reacted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
|
@ -1,8 +1,8 @@
|
||||||
import { gql } from '@urql/core'
|
import { gql } from '@urql/core'
|
||||||
|
|
||||||
export default gql`
|
export default gql`
|
||||||
query ShoutsForLayoutQuery($amount: Int, $offset: Int, $layout: String) {
|
query TopShoutsForLayout($layout: String!, $amount: Int, $offset: Int) {
|
||||||
shoutsByLayout(amount: $amount, offset: $offset, layout: $layout) {
|
topLayoutShouts(layout: $layout, amount: $amount, offset: $offset) {
|
||||||
_id: slug
|
_id: slug
|
||||||
title
|
title
|
||||||
subtitle
|
subtitle
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import { setLocale } from './stores/ui';
|
import { setLocale } from './stores/ui'
|
||||||
import './styles/app.scss'
|
import './styles/app.scss'
|
||||||
import { t } from './utils/intl'
|
import { t } from './utils/intl'
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../main.astro'
|
import Prerendered from '../main.astro'
|
||||||
import { Root } from '../components/Root'
|
import { Root } from '../components/Root'
|
||||||
import { initRouter } from '../stores/router'
|
import { initRouter } from '../stores/router'
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
import { Root } from '../components/Root'
|
import { Root } from '../components/Root'
|
||||||
import Zine from '../main.astro'
|
import Prerendered from '../main.astro'
|
||||||
import { apiClient } from '../utils/apiClient'
|
import { apiClient } from '../utils/apiClient'
|
||||||
import { initRouter } from '../stores/router'
|
import { initRouter } from '../stores/router'
|
||||||
|
|
||||||
|
@ -20,6 +20,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root article={article} client:load />
|
<Root article={article} client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../../main.astro'
|
import Prerendered from '../../main.astro'
|
||||||
import { Root } from '../../components/Root'
|
import { Root } from '../../components/Root'
|
||||||
import { initRouter } from '../../stores/router'
|
import { initRouter } from '../../stores/router'
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../../main.astro'
|
import Prerendered from '../../main.astro'
|
||||||
import { Root } from '../../components/Root'
|
import { Root } from '../../components/Root'
|
||||||
import { initRouter } from '../../stores/router'
|
import { initRouter } from '../../stores/router'
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../../main.astro'
|
import Prerendered from '../../main.astro'
|
||||||
import { Root } from '../../components/Root'
|
import { Root } from '../../components/Root'
|
||||||
import { initRouter } from '../../stores/router'
|
import { initRouter } from '../../stores/router'
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../../main.astro'
|
import Prerendered from '../../main.astro'
|
||||||
import { Root } from '../../components/Root'
|
import { Root } from '../../components/Root'
|
||||||
import { initRouter } from '../../stores/router'
|
import { initRouter } from '../../stores/router'
|
||||||
|
|
||||||
|
@ -13,6 +13,6 @@ Astro.response.headers.set(
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../../main.astro'
|
import Prerendered from '../../main.astro'
|
||||||
import { Root } from '../../components/Root'
|
import { Root } from '../../components/Root'
|
||||||
import { initRouter } from '../../stores/router'
|
import { initRouter } from '../../stores/router'
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../../main.astro'
|
import Prerendered from '../../main.astro'
|
||||||
import { Root } from '../../components/Root'
|
import { Root } from '../../components/Root'
|
||||||
import { initRouter } from '../../stores/router'
|
import { initRouter } from '../../stores/router'
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../../main.astro'
|
import Prerendered from '../../main.astro'
|
||||||
import { Root } from '../../components/Root'
|
import { Root } from '../../components/Root'
|
||||||
import { initRouter } from '../../stores/router'
|
import { initRouter } from '../../stores/router'
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../../main.astro'
|
import Prerendered from '../../main.astro'
|
||||||
import { Root } from '../../components/Root'
|
import { Root } from '../../components/Root'
|
||||||
import { initRouter } from '../../stores/router'
|
import { initRouter } from '../../stores/router'
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../../main.astro'
|
import Prerendered from '../../main.astro'
|
||||||
import { Root } from '../../components/Root'
|
import { Root } from '../../components/Root'
|
||||||
import { initRouter } from '../../stores/router'
|
import { initRouter } from '../../stores/router'
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../../main.astro'
|
import Prerendered from '../../main.astro'
|
||||||
import { Root } from '../../components/Root'
|
import { Root } from '../../components/Root'
|
||||||
import { initRouter } from '../../stores/router'
|
import { initRouter } from '../../stores/router'
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
import { Root } from '../../../components/Root'
|
import { Root } from '../../../components/Root'
|
||||||
import Zine from '../../../main.astro'
|
import Prerendered from '../../../main.astro'
|
||||||
import { apiClient } from '../../../utils/apiClient'
|
import { apiClient } from '../../../utils/apiClient'
|
||||||
import { initRouter } from '../../../stores/router'
|
import { initRouter } from '../../../stores/router'
|
||||||
import { PRERENDERED_ARTICLES_COUNT } from '../../../components/Views/Author'
|
import { PRERENDERED_ARTICLES_COUNT } from '../../../components/Views/Author'
|
||||||
|
@ -15,6 +15,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root shouts={shouts} author={author} client:load />
|
<Root shouts={shouts} author={author} client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
import { Root } from '../components/Root'
|
import { Root } from '../components/Root'
|
||||||
import Zine from '../main.astro'
|
import Prerendered from '../main.astro'
|
||||||
import { apiClient } from '../utils/apiClient'
|
import { apiClient } from '../utils/apiClient'
|
||||||
import { initRouter } from '../stores/router'
|
import { initRouter } from '../stores/router'
|
||||||
|
|
||||||
|
@ -10,6 +10,6 @@ const { pathname, search } = Astro.url
|
||||||
initRouter(pathname, search)
|
initRouter(pathname, search)
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root allAuthors={authors} client:load />
|
<Root allAuthors={authors} client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../main.astro'
|
import Prerendered from '../main.astro'
|
||||||
import { Root } from '../components/Root'
|
import { Root } from '../components/Root'
|
||||||
import { initRouter } from '../stores/router'
|
import { initRouter } from '../stores/router'
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
import { Root } from '../components/Root'
|
import { Root } from '../components/Root'
|
||||||
import Zine from '../main.astro'
|
import Prerendered from '../main.astro'
|
||||||
import { initRouter } from '../stores/router'
|
import { initRouter } from '../stores/router'
|
||||||
|
|
||||||
const { pathname, search } = Astro.url
|
const { pathname, search } = Astro.url
|
||||||
|
@ -8,6 +8,6 @@ initRouter(pathname, search)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
import { Root } from '../../components/Root'
|
import { Root } from '../../components/Root'
|
||||||
import Zine from '../../main.astro'
|
import Prerendered from '../../main.astro'
|
||||||
import { apiClient } from '../../utils/apiClient'
|
import { apiClient } from '../../utils/apiClient'
|
||||||
import { initRouter } from '../../stores/router'
|
import { initRouter } from '../../stores/router'
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ const { pathname, search } = Astro.url
|
||||||
initRouter(pathname, search)
|
initRouter(pathname, search)
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root shouts={shouts} layout={layout} client:load />
|
<Root shouts={shouts} layout={layout} client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
---
|
---
|
||||||
import { Root } from '../../components/Root'
|
import { Root } from '../../components/Root'
|
||||||
import Zine from '../../main.astro'
|
import Prerendered from '../../main.astro'
|
||||||
import { initRouter } from '../../stores/router'
|
import { initRouter } from '../../stores/router'
|
||||||
|
|
||||||
const { pathname, search } = Astro.url
|
const { pathname, search } = Astro.url
|
||||||
initRouter(pathname, search)
|
initRouter(pathname, search)
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root client:load />
|
<Root client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
12
src/pages/feed/settings.astro
Normal file
12
src/pages/feed/settings.astro
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
import Prerendered from '../../main.astro'
|
||||||
|
import { Root } from '../../components/Root'
|
||||||
|
import { initRouter } from '../../stores/router'
|
||||||
|
|
||||||
|
const { pathname, search } = Astro.url
|
||||||
|
initRouter(pathname, search)
|
||||||
|
---
|
||||||
|
|
||||||
|
<Prerendered>
|
||||||
|
<Root client:load />
|
||||||
|
</Prerendered>
|
|
@ -1,13 +0,0 @@
|
||||||
---
|
|
||||||
import Zine from '../../main.astro'
|
|
||||||
import { FeedSettings } from '../../components/Views/FeedSettings'
|
|
||||||
|
|
||||||
import { initRouter } from '../../stores/router'
|
|
||||||
|
|
||||||
const { pathname, search } = Astro.url
|
|
||||||
initRouter(pathname, search)
|
|
||||||
---
|
|
||||||
|
|
||||||
<Zine>
|
|
||||||
<FeedSettings client:load />
|
|
||||||
</Zine>
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../main.astro'
|
import Prerendered from '../main.astro'
|
||||||
import { Root } from '../components/Root'
|
import { Root } from '../components/Root'
|
||||||
import { apiClient } from '../utils/apiClient'
|
import { apiClient } from '../utils/apiClient'
|
||||||
import { initRouter } from '../stores/router'
|
import { initRouter } from '../stores/router'
|
||||||
|
@ -10,6 +10,6 @@ const { pathname, search } = Astro.url
|
||||||
initRouter(pathname, search)
|
initRouter(pathname, search)
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root chats={chatrooms} client:load />
|
<Root chats={chatrooms} client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import Zine from '../main.astro'
|
import Prerendered from '../main.astro'
|
||||||
import { Root } from '../components/Root'
|
import { Root } from '../components/Root'
|
||||||
import { apiClient } from '../utils/apiClient'
|
import { apiClient } from '../utils/apiClient'
|
||||||
import { initRouter } from '../stores/router'
|
import { initRouter } from '../stores/router'
|
||||||
|
@ -14,7 +14,7 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root randomTopics={randomTopics} shouts={articles} client:load />
|
<Root randomTopics={randomTopics} shouts={articles} client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
import { Root } from '../components/Root'
|
import { Root } from '../components/Root'
|
||||||
import Zine from '../main.astro'
|
import Prerendered from '../main.astro'
|
||||||
import { apiClient } from '../utils/apiClient'
|
import { apiClient } from '../utils/apiClient'
|
||||||
import { initRouter } from '../stores/router'
|
import { initRouter } from '../stores/router'
|
||||||
|
|
||||||
|
@ -12,6 +12,6 @@ const { pathname, search } = Astro.url
|
||||||
initRouter(pathname, search)
|
initRouter(pathname, search)
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root searchResults={searchResults} client:load />
|
<Root searchResults={searchResults} client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
import { Root } from '../../components/Root'
|
import { Root } from '../../components/Root'
|
||||||
import Zine from '../../main.astro'
|
import Prerendered from '../../main.astro'
|
||||||
import { apiClient } from '../../utils/apiClient'
|
import { apiClient } from '../../utils/apiClient'
|
||||||
import { PRERENDERED_ARTICLES_COUNT } from '../../components/Views/Topic'
|
import { PRERENDERED_ARTICLES_COUNT } from '../../components/Views/Topic'
|
||||||
|
|
||||||
|
@ -16,6 +16,6 @@ initRouter(pathname, search)
|
||||||
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate')
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root shouts={shouts} topic={topic} client:load />
|
<Root shouts={shouts} topic={topic} client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
import { Root } from '../components/Root'
|
import { Root } from '../components/Root'
|
||||||
import Zine from '../main.astro'
|
import Prerendered from '../main.astro'
|
||||||
import { apiClient } from '../utils/apiClient'
|
import { apiClient } from '../utils/apiClient'
|
||||||
import { initRouter } from '../stores/router'
|
import { initRouter } from '../stores/router'
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ const { pathname, search } = Astro.url
|
||||||
initRouter(pathname, search)
|
initRouter(pathname, search)
|
||||||
---
|
---
|
||||||
|
|
||||||
<Zine>
|
<Prerendered>
|
||||||
<Root allTopics={topics} client:load />
|
<Root allTopics={topics} client:load />
|
||||||
</Zine>
|
</Prerendered>
|
||||||
|
|
||||||
|
|
|
@ -1,196 +1,99 @@
|
||||||
import type { Author, Shout, ShoutInput, Topic } from '../../graphql/types.gen'
|
import type { Shout } from '../../graphql/types.gen'
|
||||||
import { apiClient } from '../../utils/apiClient'
|
import { apiClient } from '../../utils/apiClient'
|
||||||
import { addAuthorsByTopic } from './authors'
|
import { useArticlesStore } from './articles'
|
||||||
import { addTopicsByAuthor } from './topics'
|
|
||||||
import { byStat } from '../../utils/sortby'
|
|
||||||
import { createSignal } from 'solid-js'
|
import { createSignal } from 'solid-js'
|
||||||
import { createLazyMemo } from '@solid-primitives/memo'
|
import type { LayoutType } from '../../components/Views/LayoutView'
|
||||||
|
import { byCreated } from '../../utils/sortby'
|
||||||
|
|
||||||
const [sortedArticles, setSortedArticles] = createSignal<Shout[]>([])
|
const [sortedLayoutShouts, setSortedLayoutShouts] = createSignal<Map<LayoutType, Shout[]>>(new Map())
|
||||||
const [articleEntities, setArticleEntities] = createSignal<{ [articleSlug: string]: Shout }>({})
|
|
||||||
|
|
||||||
const [topArticles, setTopArticles] = createSignal<Shout[]>([])
|
const addLayoutShouts = (layout: LayoutType, shouts: Shout[]) => {
|
||||||
const [topMonthArticles, setTopMonthArticles] = createSignal<Shout[]>([])
|
setSortedLayoutShouts((prevSorted: Map<LayoutType, Shout[]>) => {
|
||||||
|
const siblings = prevSorted.get(layout)
|
||||||
const articlesByLayout = createLazyMemo(() => {
|
if (Boolean(siblings)) {
|
||||||
return Object.values(articleEntities()).reduce((acc, article) => {
|
const uniqued = Array.from(new Set([...siblings, ...shouts]))
|
||||||
if (!acc[article.layout]) {
|
prevSorted.set(layout, uniqued)
|
||||||
acc[article.layout] = []
|
}
|
||||||
|
return prevSorted
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
acc[article.layout].push(article)
|
export const resetSortedLayoutShouts = () => {
|
||||||
|
setSortedLayoutShouts(new Map())
|
||||||
return acc
|
|
||||||
}, {} as { [layout: string]: Shout[] })
|
|
||||||
})
|
|
||||||
|
|
||||||
const topViewedArticles = createLazyMemo(() => {
|
|
||||||
const result = Object.values(articleEntities())
|
|
||||||
result.sort(byStat('viewed'))
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
|
|
||||||
const topCommentedArticles = createLazyMemo(() => {
|
|
||||||
const result = Object.values(articleEntities())
|
|
||||||
result.sort(byStat('commented'))
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
|
|
||||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
||||||
const addArticles = (...args: Shout[][]) => {
|
|
||||||
const allArticles = args.flatMap((articles) => articles || [])
|
|
||||||
|
|
||||||
const newArticleEntities = allArticles.reduce((acc, article) => {
|
|
||||||
acc[article.slug] = article
|
|
||||||
return acc
|
|
||||||
}, {} as { [articleSLug: string]: Shout })
|
|
||||||
|
|
||||||
setArticleEntities((prevArticleEntities) => {
|
|
||||||
return {
|
|
||||||
...prevArticleEntities,
|
|
||||||
...newArticleEntities
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const authorsByTopic = allArticles.reduce((acc, article) => {
|
|
||||||
const { authors, topics } = article
|
|
||||||
|
|
||||||
topics.forEach((topic) => {
|
|
||||||
if (!acc[topic.slug]) {
|
|
||||||
acc[topic.slug] = []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
authors.forEach((author) => {
|
export const loadRecentLayoutShouts = async ({
|
||||||
if (!acc[topic.slug].some((a) => a.slug === author.slug)) {
|
|
||||||
acc[topic.slug].push(author)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
return acc
|
|
||||||
}, {} as { [topicSlug: string]: Author[] })
|
|
||||||
|
|
||||||
addAuthorsByTopic(authorsByTopic)
|
|
||||||
|
|
||||||
const topicsByAuthor = allArticles.reduce((acc, article) => {
|
|
||||||
const { authors, topics } = article
|
|
||||||
|
|
||||||
authors.forEach((author) => {
|
|
||||||
if (!acc[author.slug]) {
|
|
||||||
acc[author.slug] = []
|
|
||||||
}
|
|
||||||
|
|
||||||
topics.forEach((topic) => {
|
|
||||||
if (!acc[author.slug].some((t) => t.slug === topic.slug)) {
|
|
||||||
acc[author.slug].push(topic)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
return acc
|
|
||||||
}, {} as { [authorSlug: string]: Topic[] })
|
|
||||||
|
|
||||||
addTopicsByAuthor(topicsByAuthor)
|
|
||||||
}
|
|
||||||
|
|
||||||
const addSortedArticles = (articles: Shout[]) => {
|
|
||||||
setSortedArticles((prevSortedArticles) => [...prevSortedArticles, ...articles])
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loadLayoutShouts = async ({
|
|
||||||
layout,
|
layout,
|
||||||
amount,
|
amount,
|
||||||
offset
|
offset
|
||||||
}: {
|
}: {
|
||||||
layout: string
|
layout: LayoutType
|
||||||
amount: number
|
amount: number
|
||||||
offset?: number
|
offset?: number
|
||||||
}): Promise<{ hasMore: boolean }> => {
|
}): Promise<{ hasMore: boolean }> => {
|
||||||
const layoutShouts: Shout[] = await apiClient.getLayoutShouts({ layout, amount, offset })
|
const layoutShouts: Shout[] = await apiClient.getRecentLayoutShouts({ layout, amount, offset })
|
||||||
const hasMore = layoutShouts.length > amount
|
const hasMore = layoutShouts.length < amount
|
||||||
|
if (hasMore) layoutShouts.splice(-1)
|
||||||
if (hasMore) {
|
const sortedArticles = layoutShouts.sort(byCreated)
|
||||||
layoutShouts.splice(-1)
|
const { articlesByLayout } = useArticlesStore({ sortedArticles })
|
||||||
}
|
addLayoutShouts(layout, articlesByLayout()[layout])
|
||||||
|
|
||||||
addArticles(layoutShouts)
|
|
||||||
addSortedArticles(layoutShouts)
|
|
||||||
|
|
||||||
return { hasMore }
|
return { hasMore }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const resetSortedArticles = () => {
|
export const loadTopMonthLayoutShouts = async (
|
||||||
setSortedArticles([])
|
layout: LayoutType,
|
||||||
|
amount: number,
|
||||||
|
offset: number
|
||||||
|
): Promise<{ hasMore: boolean }> => {
|
||||||
|
const shouts = await apiClient.getTopMonthLayoutShouts({ layout })
|
||||||
|
const hasMore = shouts.length < amount
|
||||||
|
if (hasMore) shouts.splice(-1)
|
||||||
|
addLayoutShouts(layout, shouts)
|
||||||
|
return { hasMore }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadTopMonthArticles = async (): Promise<void> => {
|
export const loadTopLayoutShouts = async (
|
||||||
const articles = await apiClient.getTopMonthArticles()
|
layout: LayoutType,
|
||||||
addArticles(articles)
|
amount,
|
||||||
setTopMonthArticles(articles)
|
offset
|
||||||
}
|
): Promise<{ hasMore: boolean }> => {
|
||||||
|
const shouts = await apiClient.getTopLayoutShouts({ layout })
|
||||||
export const loadTopArticles = async (): Promise<void> => {
|
const hasMore = shouts.length < amount
|
||||||
const articles = await apiClient.getTopArticles()
|
if (hasMore) shouts.splice(-1)
|
||||||
addArticles(articles)
|
addLayoutShouts(layout, shouts)
|
||||||
setTopArticles(articles)
|
return { hasMore }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadSearchResults = async ({
|
export const loadSearchResults = async ({
|
||||||
|
layout,
|
||||||
query,
|
query,
|
||||||
limit,
|
limit,
|
||||||
offset
|
offset
|
||||||
}: {
|
}: {
|
||||||
|
layout: LayoutType
|
||||||
query: string
|
query: string
|
||||||
limit?: number
|
limit?: number
|
||||||
offset?: number
|
offset?: number
|
||||||
}): Promise<void> => {
|
}): Promise<void> => {
|
||||||
const newArticles = await apiClient.getSearchResults({ query, limit, offset })
|
const newLayoutShouts = await apiClient.getSearchResults({ layout, query, limit, offset })
|
||||||
addArticles(newArticles)
|
addLayoutShouts(layout, newLayoutShouts)
|
||||||
addSortedArticles(newArticles)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const incrementView = async ({ articleSlug }: { articleSlug: string }): Promise<void> => {
|
|
||||||
await apiClient.incrementView({ articleSlug })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loadArticle = async ({ slug }: { slug: string }): Promise<void> => {
|
|
||||||
const article = await apiClient.getArticle({ slug })
|
|
||||||
|
|
||||||
if (!article) {
|
|
||||||
throw new Error(`Can't load article, slug: "${slug}"`)
|
|
||||||
}
|
|
||||||
|
|
||||||
addArticles([article])
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createArticle = async ({ article }: { article: ShoutInput }) => {
|
|
||||||
try {
|
|
||||||
await apiClient.createArticle({ article })
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type InitialState = {
|
type InitialState = {
|
||||||
sortedArticles?: Shout[]
|
sortedLayoutShouts?: Shout[]
|
||||||
topRatedArticles?: Shout[]
|
topRatedLayoutShouts?: Shout[]
|
||||||
topRatedMonthArticles?: Shout[]
|
topRatedMonthLayoutShouts?: Shout[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useArticlesStore = (initialState: InitialState = {}) => {
|
export const useLayoutsStore = (layout: LayoutType, initialData: Shout[]) => {
|
||||||
addArticles([...(initialState.sortedArticles || [])])
|
addLayoutShouts(layout, initialData || [])
|
||||||
|
|
||||||
if (initialState.sortedArticles) {
|
|
||||||
setSortedArticles([...initialState.sortedArticles])
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
articleEntities,
|
addLayoutShouts,
|
||||||
sortedArticles,
|
sortedLayoutShouts,
|
||||||
topArticles,
|
loadSearchResults,
|
||||||
topMonthArticles,
|
loadRecentLayoutShouts,
|
||||||
topViewedArticles,
|
loadTopMonthLayoutShouts,
|
||||||
topCommentedArticles,
|
loadTopLayoutShouts
|
||||||
articlesByLayout
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,10 @@ import authorsBySlugs from '../graphql/query/authors-by-slugs'
|
||||||
import incrementView from '../graphql/mutation/increment-view'
|
import incrementView from '../graphql/mutation/increment-view'
|
||||||
import createArticle from '../graphql/mutation/article-create'
|
import createArticle from '../graphql/mutation/article-create'
|
||||||
import myChats from '../graphql/query/my-chats'
|
import myChats from '../graphql/query/my-chats'
|
||||||
import getLayout from '../graphql/query/articles-for-layout'
|
import getRecentByLayout from '../graphql/query/layout-recent'
|
||||||
|
import getTopByLayout from '../graphql/query/layout-top'
|
||||||
|
import getTopMonthByLayout from '../graphql/query/layout-top-month'
|
||||||
|
import type { LayoutType } from '../components/Views/LayoutView'
|
||||||
|
|
||||||
const FEED_SIZE = 50
|
const FEED_SIZE = 50
|
||||||
|
|
||||||
|
@ -147,11 +150,13 @@ export const apiClient = {
|
||||||
getSearchResults: async ({
|
getSearchResults: async ({
|
||||||
query,
|
query,
|
||||||
limit = FEED_SIZE,
|
limit = FEED_SIZE,
|
||||||
offset = 0
|
offset = 0,
|
||||||
|
layout = 'literature'
|
||||||
}: {
|
}: {
|
||||||
query: string
|
query: string
|
||||||
limit: number
|
limit: number
|
||||||
offset?: number
|
offset?: number
|
||||||
|
layout?: LayoutType
|
||||||
}): Promise<Shout[]> => {
|
}): Promise<Shout[]> => {
|
||||||
const response = await publicGraphQLClient
|
const response = await publicGraphQLClient
|
||||||
.query(searchResults, {
|
.query(searchResults, {
|
||||||
|
@ -336,8 +341,18 @@ export const apiClient = {
|
||||||
const resp = await privateGraphQLClient.query(myChats, payload).toPromise()
|
const resp = await privateGraphQLClient.query(myChats, payload).toPromise()
|
||||||
return resp.data.myChats
|
return resp.data.myChats
|
||||||
},
|
},
|
||||||
getLayoutShouts: async ({ layout = 'article', amount = 50, offset = 0 }) => {
|
getRecentLayoutShouts: async ({ layout = 'article', amount = 50, offset = 0 }) => {
|
||||||
const resp = await publicGraphQLClient.query(getLayout, { amount, offset, layout }).toPromise()
|
const resp = await publicGraphQLClient.query(getRecentByLayout, { amount, offset, layout }).toPromise()
|
||||||
return resp.data.shoutsByLayout
|
return resp.data.recentLayoutShouts
|
||||||
|
},
|
||||||
|
getTopLayoutShouts: async ({ layout = 'article', amount = 50, offset = 0 }) => {
|
||||||
|
const resp = await publicGraphQLClient.query(getTopByLayout, { amount, offset, layout }).toPromise()
|
||||||
|
return resp.data.topLayoutShouts
|
||||||
|
},
|
||||||
|
getTopMonthLayoutShouts: async ({ layout = 'article', amount = 50, offset = 0 }) => {
|
||||||
|
const resp = await publicGraphQLClient
|
||||||
|
.query(getTopMonthByLayout, { amount, offset, layout })
|
||||||
|
.toPromise()
|
||||||
|
return resp.data.topMonthLayoutShouts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user