apifixes-wip

This commit is contained in:
tonyrewin 2022-09-13 11:05:11 +03:00
parent fe88d3e150
commit 4d1e7f7831
10 changed files with 1177 additions and 1181 deletions

View File

@ -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",

View File

@ -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}

View File

@ -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())}>

View File

@ -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'}
/>

View File

@ -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
/>

View File

@ -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 })
}

View File

@ -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 }
}

View File

@ -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 }
}

View File

@ -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> => {

2174
yarn.lock

File diff suppressed because it is too large Load Diff