apifixes-wip
This commit is contained in:
parent
fe88d3e150
commit
4d1e7f7831
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "discoursio-astro",
|
||||
"name": "discoursio-webapp",
|
||||
"version": "0.5.1",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
|
@ -28,7 +28,7 @@
|
|||
"vercel-build": "astro build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.159.0",
|
||||
"@aws-sdk/client-s3": "^3.169.0",
|
||||
"@nanostores/i18n": "^0.6.0",
|
||||
"@nanostores/persistent": "^0.6.2",
|
||||
"@nanostores/router": "^0.6.0",
|
||||
|
@ -37,7 +37,7 @@
|
|||
"google-translate-api-x": "^10.3.5",
|
||||
"loglevel": "^1.8.0",
|
||||
"loglevel-plugin-prefix": "^0.8.4",
|
||||
"mailgun.js": "^8.0.0",
|
||||
"mailgun.js": "^8.0.1",
|
||||
"nanostores": "^0.6.0",
|
||||
"rehype-autolink-headings": "^6.1.1",
|
||||
"rehype-slug": "^5.0.1",
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
import { Show, createMemo, createSignal, createEffect } from 'solid-js'
|
||||
import { Show, createMemo } from 'solid-js'
|
||||
import type { Author, Shout, Topic } from '../../graphql/types.gen'
|
||||
import Row2 from '../Feed/Row2'
|
||||
import Row3 from '../Feed/Row3'
|
||||
import AuthorFull from '../Author/Full'
|
||||
import { t } from '../../utils/intl'
|
||||
import { useAuthorsStore } from '../../stores/zine/authors'
|
||||
import { params as paramsStore } from '../../stores/router'
|
||||
import { params } from '../../stores/router'
|
||||
import { useArticlesStore } from '../../stores/zine/articles'
|
||||
|
||||
import '../../styles/Topic.scss'
|
||||
import Beside from '../Feed/Beside'
|
||||
import { useStore } from '@nanostores/solid'
|
||||
import { useTopicsStore } from '../../stores/zine/topics'
|
||||
import { unique } from '../../utils'
|
||||
|
||||
type AuthorProps = {
|
||||
authorArticles: Shout[]
|
||||
|
@ -18,44 +20,29 @@ type AuthorProps = {
|
|||
}
|
||||
|
||||
export const AuthorPage = (props: AuthorProps) => {
|
||||
const params = useStore(paramsStore)
|
||||
const args = useStore(params)
|
||||
const { getSortedArticles: articles, getArticlesByAuthors: articlesByAuthors } = useArticlesStore({
|
||||
sortedArticles: props.authorArticles
|
||||
})
|
||||
const { getAuthorEntities: authors } = useAuthorsStore([props.author])
|
||||
const author = createMemo(() => authors()[props.author.slug])
|
||||
const slug = createMemo(() => author().slug)
|
||||
/*
|
||||
const slug = createMemo<string>(() => {
|
||||
let slug = props?.slug
|
||||
if (props?.slug.startsWith('@')) slug = slug.replace('@', '')
|
||||
return slug
|
||||
const topics = createMemo(() => {
|
||||
const ttt = []
|
||||
articlesByAuthors()[author().slug].forEach((s: Shout) =>
|
||||
s.topics.forEach((tpc: Topic) => ttt.push(tpc))
|
||||
)
|
||||
return unique(ttt)
|
||||
})
|
||||
*/
|
||||
const [authorTopics, setAuthorTopics] = createSignal<Partial<Topic>[]>([])
|
||||
createEffect(() => {
|
||||
if (authorTopics().length === 0 && articles().length > 0) {
|
||||
const r = [] as Topic[]
|
||||
articlesByAuthors()[slug()].forEach((a: Shout) => {
|
||||
a.topics.forEach((topic: Topic) => {
|
||||
if (!r.some((t) => t.slug === topic.slug)) r.push(topic)
|
||||
})
|
||||
})
|
||||
setAuthorTopics(r)
|
||||
}
|
||||
}, [articles()])
|
||||
const { getSortedTopics } = useTopicsStore({ topics: topics() })
|
||||
|
||||
const title = createMemo(() => {
|
||||
const m = params()['by']
|
||||
const m = args()['by']
|
||||
if (m === 'viewed') return t('Top viewed')
|
||||
if (m === 'rating') return t('Top rated')
|
||||
if (m === 'commented') return t('Top discussed')
|
||||
return t('Top recent')
|
||||
})
|
||||
|
||||
const setBy = (what: string) => {
|
||||
params()['by'] = what
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="container author-page">
|
||||
<Show when={author()} fallback={<div class="center">{t('Loading')}</div>}>
|
||||
|
@ -63,23 +50,23 @@ export const AuthorPage = (props: AuthorProps) => {
|
|||
<div class="row group__controls">
|
||||
<div class="col-md-8">
|
||||
<ul class="view-switcher">
|
||||
<li classList={{ selected: !params()['by'] || params()['by'] === 'recent' }}>
|
||||
<button type="button" onClick={() => setBy('')}>
|
||||
<li classList={{ selected: !args()['by'] || args()['by'] === 'recent' }}>
|
||||
<button type="button" onClick={() => (args()['by'] = 'recent')}>
|
||||
{t('Recent')}
|
||||
</button>
|
||||
</li>
|
||||
<li classList={{ selected: params()['by'] === 'rating' }}>
|
||||
<button type="button" onClick={() => setBy('rating')}>
|
||||
<li classList={{ selected: args()['by'] === 'rating' }}>
|
||||
<button type="button" onClick={() => (args()['by'] = 'rating')}>
|
||||
{t('Popular')}
|
||||
</button>
|
||||
</li>
|
||||
<li classList={{ selected: params()['by'] === 'viewed' }}>
|
||||
<button type="button" onClick={() => setBy('viewed')}>
|
||||
<li classList={{ selected: args()['by'] === 'viewed' }}>
|
||||
<button type="button" onClick={() => (args()['by'] = 'viewed')}>
|
||||
{t('Views')}
|
||||
</button>
|
||||
</li>
|
||||
<li classList={{ selected: params()['by'] === 'commented' }}>
|
||||
<button type="button" onClick={() => setBy('commented')}>
|
||||
<li classList={{ selected: args()['by'] === 'commented' }}>
|
||||
<button type="button" onClick={() => (args()['by'] = 'commented')}>
|
||||
{t('Discussing')}
|
||||
</button>
|
||||
</li>
|
||||
|
@ -99,7 +86,7 @@ export const AuthorPage = (props: AuthorProps) => {
|
|||
<Show when={articles()?.length > 0}>
|
||||
<Beside
|
||||
title={t('Topics which supported by author')}
|
||||
values={authorTopics()?.slice(0, 5)}
|
||||
values={getSortedTopics()?.slice(0, 5)}
|
||||
beside={articles()[0]}
|
||||
wrapper={'topic'}
|
||||
topicShortDescription={true}
|
||||
|
|
|
@ -24,6 +24,8 @@ import {
|
|||
} from '../../stores/zine/top'
|
||||
import { useTopicsStore } from '../../stores/zine/topics'
|
||||
import { loadMorePublished, useArticlesStore } from '../../stores/zine/articles'
|
||||
import { sortBy } from '../../utils/sortby'
|
||||
import { shuffle } from '../../utils'
|
||||
|
||||
type HomeProps = {
|
||||
randomTopics: Topic[]
|
||||
|
@ -39,39 +41,31 @@ const LAYOUTS = ['article', 'prose', 'music', 'video', 'image']
|
|||
export const HomePage = (props: HomeProps) => {
|
||||
const [someLayout, setSomeLayout] = createSignal([] as Shout[])
|
||||
const [selectedLayout, setSelectedLayout] = createSignal('article')
|
||||
const [byLayout, setByLayout] = createSignal({} as { [layout: string]: Shout[] })
|
||||
const [byTopic, setByTopic] = createSignal({} as { [topic: string]: Shout[] })
|
||||
const { getSortedArticles } = useArticlesStore({ sortedArticles: props.recentPublishedArticles })
|
||||
const articles = createMemo(() => getSortedArticles())
|
||||
const { getRandomTopics, getSortedTopics } = useTopicsStore({ randomTopics: props.randomTopics })
|
||||
const [byLayout, setByLayout] = createSignal<{ [layout: string]: Shout[] }>({})
|
||||
const { getSortedArticles: articles, getArticlesByTopics: byTopic } = useArticlesStore({
|
||||
sortedArticles: props.recentPublishedArticles
|
||||
})
|
||||
const { getSortedTopics } = useTopicsStore({ topics: sortBy(props.randomTopics, 'shouts') })
|
||||
|
||||
createEffect(() => {
|
||||
if (articles() && articles().length > 0 && Object.keys(byTopic()).length === 0) {
|
||||
console.debug('[home] ' + getRandomTopics().length.toString() + ' random topics loaded')
|
||||
console.debug('[home] ' + articles().length.toString() + ' overall shouts loaded')
|
||||
console.log('[home] preparing published articles...')
|
||||
// get shouts lists by
|
||||
const bl: { [key: string]: Shout[] } = {}
|
||||
const bt: { [key: string]: Shout[] } = {}
|
||||
articles().forEach((s: Shout) => {
|
||||
// by topic
|
||||
s.topics?.forEach(({ slug }: any) => {
|
||||
if (!bt[slug || '']) bt[slug || ''] = []
|
||||
bt[slug as string].push(s)
|
||||
})
|
||||
// by layout
|
||||
const l = s.layout || 'article'
|
||||
if (!bl[l]) bl[l] = []
|
||||
bl[l].push(s)
|
||||
})
|
||||
setByLayout(bl)
|
||||
setByTopic(bt)
|
||||
console.log('[home] some grouped articles are ready')
|
||||
console.log('[home] some grouped by layout articles are ready')
|
||||
}
|
||||
}, [articles()])
|
||||
|
||||
createEffect(() => {
|
||||
if (Object.keys(byLayout()).length > 0 && getSortedTopics()) {
|
||||
if (getSortedTopics() && !selectedLayout()) {
|
||||
// random special layout pick
|
||||
const special = LAYOUTS.filter((la) => la !== 'article')
|
||||
const layout = special[Math.floor(Math.random() * special.length)]
|
||||
|
@ -85,7 +79,7 @@ export const HomePage = (props: HomeProps) => {
|
|||
if (props.topOverallArticles) setTopRated(props.topOverallArticles)
|
||||
console.info('[home] mounted')
|
||||
})
|
||||
|
||||
const getRandomTopics = () => shuffle(getSortedTopics()).slice(0, 12)
|
||||
return (
|
||||
<Suspense fallback={t('Loading')}>
|
||||
<Show when={Boolean(articles())}>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { For, Show, createMemo } from 'solid-js'
|
||||
import { For, Show, createMemo, createEffect, createSignal } from 'solid-js'
|
||||
import type { Shout, Topic } from '../../graphql/types.gen'
|
||||
import Row3 from '../Feed/Row3'
|
||||
import Row2 from '../Feed/Row2'
|
||||
|
@ -8,9 +8,11 @@ import '../../styles/Topic.scss'
|
|||
import { FullTopic } from '../Topic/Full'
|
||||
import { t } from '../../utils/intl'
|
||||
import { params } from '../../stores/router'
|
||||
import { useTopicsStore } from '../../stores/zine/topics'
|
||||
import { useArticlesStore } from '../../stores/zine/articles'
|
||||
import { useStore } from '@nanostores/solid'
|
||||
import { unique } from '../../utils'
|
||||
import { useTopicsStore } from '../../stores/zine/topics'
|
||||
import { byCreated, sortBy } from '../../utils/sortby'
|
||||
|
||||
interface TopicProps {
|
||||
topic: Topic
|
||||
|
@ -19,22 +21,28 @@ interface TopicProps {
|
|||
|
||||
export const TopicPage = (props: TopicProps) => {
|
||||
const args = useStore(params)
|
||||
const { getAuthorsByTopic } = useTopicsStore({ topics: [props.topic] })
|
||||
const { getSortedArticles: sortedArticles } = useArticlesStore({ sortedArticles: props.topicArticles })
|
||||
const topic = createMemo(() => props.topic)
|
||||
/*
|
||||
const slug = createMemo<string>(() => {
|
||||
let slug = props?.slug
|
||||
if (props?.slug.startsWith('@')) slug = slug.replace('@', '')
|
||||
return slug
|
||||
const { getArticlesByTopics } = useArticlesStore({ sortedArticles: props.topicArticles })
|
||||
|
||||
const [topicAuthors, setTopicAuthors] = createSignal([])
|
||||
const sortedArticles = createMemo(() => {
|
||||
const aaa = getArticlesByTopics()[props.topic.slug] || []
|
||||
aaa.forEach((a: Shout) => {
|
||||
a.topics?.forEach((t: Topic) => {
|
||||
if (props.topic.slug === t.slug) {
|
||||
setTopicAuthors((aaa) => [...aaa, a])
|
||||
}
|
||||
})
|
||||
})
|
||||
return args()['by'] ? sortBy(aaa, args()['by']) : sortBy(aaa, byCreated)
|
||||
})
|
||||
*/
|
||||
const { getTopicEntities } = useTopicsStore({ topics: [props.topic] })
|
||||
const topic = createMemo(() => getTopicEntities()[props.topic.slug] || props.topic)
|
||||
|
||||
const title = createMemo(() => {
|
||||
// const m = by()
|
||||
// if (m === 'viewed') return t('Top viewed')
|
||||
// if (m === 'rating') return t('Top rated')
|
||||
// if (m === 'commented') return t('Top discussed')
|
||||
const m = args()['by']
|
||||
if (m === 'viewed') return t('Top viewed')
|
||||
if (m === 'rating') return t('Top rated')
|
||||
if (m === 'commented') return t('Top discussed')
|
||||
return t('Top recent')
|
||||
})
|
||||
|
||||
|
@ -94,7 +102,7 @@ export const TopicPage = (props: TopicProps) => {
|
|||
<Show when={sortedArticles().length > 5}>
|
||||
<Beside
|
||||
title={t('Topic is supported by')}
|
||||
values={getAuthorsByTopic() as any}
|
||||
values={unique(topicAuthors()) as any}
|
||||
beside={sortedArticles()[6]}
|
||||
wrapper={'author'}
|
||||
/>
|
||||
|
|
|
@ -15,7 +15,7 @@ Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate'
|
|||
<HomePage
|
||||
randomTopics={randomTopics}
|
||||
recentPublishedArticles={recentPublished}
|
||||
topMonthArticles={topMonth}
|
||||
topMonthArticles={[]}
|
||||
topOverallArticles={topOverall}
|
||||
client:load
|
||||
/>
|
||||
|
|
|
@ -97,12 +97,12 @@ export const useArticlesStore = ({ sortedArticles }: InitialState) => {
|
|||
|
||||
export const loadMoreAll = () => {
|
||||
const searchParams = useStore(params)
|
||||
const pn = Number.parseInt(searchParams()['page'], 10)
|
||||
const pn = Number.parseInt(searchParams()['page'] || '1', 10) || 1
|
||||
loadRecentAllArticles({ page: pn + 1 })
|
||||
}
|
||||
|
||||
export const loadMorePublished = () => {
|
||||
const searchParams = useStore(params)
|
||||
const pn = Number.parseInt(searchParams()['page'], 10)
|
||||
const pn = Number.parseInt(searchParams()['page'] || '1', 10) || 1
|
||||
loadRecentPublishedArticles({ page: pn + 1 })
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ const sortByStore = atom<AuthorsSortBy>('created')
|
|||
|
||||
let authorEntitiesStore: WritableAtom<Record<string, Author>>
|
||||
let sortedAuthorsStore: ReadableAtom<Author[]>
|
||||
|
||||
let authorsByTopicStore: WritableAtom<Record<string, Author[]>>
|
||||
const initStore = (initial?: Record<string, Author>) => {
|
||||
if (authorEntitiesStore) {
|
||||
return
|
||||
|
@ -61,6 +61,6 @@ export const useAuthorsStore = (initial?: Author[]) => {
|
|||
|
||||
const getAuthorEntities = useStore(authorEntitiesStore)
|
||||
const getSortedAuthors = useStore(sortedAuthorsStore)
|
||||
|
||||
return { getAuthorEntities, getSortedAuthors }
|
||||
const getAuthorsByTopic = useStore(authorsByTopicStore)
|
||||
return { getAuthorEntities, getSortedAuthors, getAuthorsByTopic }
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ const sortByStore = atom<TopicsSortBy>('created')
|
|||
|
||||
let topicEntitiesStore: WritableAtom<Record<string, Topic>>
|
||||
let sortedTopicsStore: ReadableAtom<Topic[]>
|
||||
let randomTopicsStore: WritableAtom<Topic[]>
|
||||
|
||||
const initStore = (initial?: Record<string, Topic>) => {
|
||||
if (topicEntitiesStore) {
|
||||
|
@ -64,18 +63,11 @@ type InitialState = {
|
|||
randomTopics?: Topic[]
|
||||
}
|
||||
|
||||
export const useTopicsStore = ({ topics, randomTopics }: InitialState) => {
|
||||
export const useTopicsStore = ({ topics }: InitialState) => {
|
||||
addTopics(topics)
|
||||
|
||||
// WIP
|
||||
if (!randomTopicsStore) {
|
||||
randomTopicsStore = atom<Topic[]>(randomTopics)
|
||||
}
|
||||
|
||||
const getTopicEntities = useStore(topicEntitiesStore)
|
||||
const getSortedTopics = useStore(sortedTopicsStore)
|
||||
const getRandomTopics = useStore(randomTopicsStore)
|
||||
// eslint-disable-next-line unicorn/consistent-function-scoping
|
||||
const getAuthorsByTopic = () => [] // FIXME: useStore(authorsByTopic)
|
||||
return { getTopicEntities, getSortedTopics, getRandomTopics, getAuthorsByTopic }
|
||||
|
||||
return { getTopicEntities, getSortedTopics }
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import topicsRandomQuery from '../graphql/query/topics-random'
|
|||
import articlesTopMonth from '../graphql/query/articles-top-month'
|
||||
import articlesTopRated from '../graphql/query/articles-top-rated'
|
||||
import authorsAll from '../graphql/query/authors-all'
|
||||
import { GRAPHQL_MAX_INT } from 'graphql/type'
|
||||
import reactionCreate from '../graphql/mutation/reaction-create'
|
||||
import reactionDestroy from '../graphql/mutation/reaction-destroy'
|
||||
import reactionUpdate from '../graphql/mutation/reaction-update'
|
||||
|
@ -43,7 +42,7 @@ export const apiClient = {
|
|||
},
|
||||
getTopMonthArticles: async () => {
|
||||
const response = await publicGraphQLClient.query(articlesTopMonth, { page: 1, size: 10 }).toPromise()
|
||||
return response.data.articlesTopMonth
|
||||
return response.data.topMonth
|
||||
},
|
||||
getRandomTopics: async () => {
|
||||
const response = await publicGraphQLClient.query(topicsRandomQuery, {}).toPromise()
|
||||
|
@ -69,33 +68,27 @@ export const apiClient = {
|
|||
|
||||
return response.data.searchQuery
|
||||
},
|
||||
getRecentAllArticles: async ({
|
||||
page = 1,
|
||||
size = FEED_PAGE_SIZE
|
||||
}: {
|
||||
page?: number
|
||||
size?: number
|
||||
}): Promise<Shout[]> => {
|
||||
getRecentAllArticles: async ({ page, size }: { page?: number; size?: number }): Promise<Shout[]> => {
|
||||
const response = await publicGraphQLClient
|
||||
.query(articlesRecentAll, {
|
||||
page,
|
||||
size
|
||||
page: page || 1,
|
||||
size: size || FEED_PAGE_SIZE
|
||||
})
|
||||
.toPromise()
|
||||
|
||||
return response.data.recentAll
|
||||
},
|
||||
getRecentPublishedArticles: async ({
|
||||
page = 1,
|
||||
size = FEED_PAGE_SIZE
|
||||
page,
|
||||
size
|
||||
}: {
|
||||
page?: number
|
||||
size?: number
|
||||
}): Promise<Shout[]> => {
|
||||
const response = await publicGraphQLClient
|
||||
.query(articlesRecentPublished, {
|
||||
page,
|
||||
size
|
||||
page: page || 1,
|
||||
size: size || FEED_PAGE_SIZE
|
||||
})
|
||||
.toPromise()
|
||||
|
||||
|
@ -198,9 +191,7 @@ export const apiClient = {
|
|||
},
|
||||
|
||||
getAllAuthors: async () => {
|
||||
const response = await publicGraphQLClient
|
||||
.query(authorsAll, { page: 1, size: GRAPHQL_MAX_INT })
|
||||
.toPromise()
|
||||
const response = await publicGraphQLClient.query(authorsAll, { page: 1, size: 9999 }).toPromise()
|
||||
return response.data.authorsAll
|
||||
},
|
||||
getArticle: async ({ slug }: { slug: string }): Promise<Shout> => {
|
||||
|
|
Loading…
Reference in New Issue
Block a user