home-fix+topics-wip

This commit is contained in:
Untone 2024-06-28 18:05:45 +03:00
parent a616f97fe4
commit 4e631f5f91
6 changed files with 43 additions and 41 deletions

View File

@ -155,11 +155,13 @@ export const Header = (props: Props) => {
const loc = useLocation()
const handleToggleMenuByLink = (event: MouseEvent, route: string) => {
event.preventDefault()
console.debug(loc.pathname, route)
// console.debug('[Header] toggle menu link from', loc.pathname)
// console.debug('to', route)
if (!fixed()) return
if (loc.pathname.startsWith(route) || loc.pathname.startsWith(`/${route}`)) {
toggleFixed()
}
navigate(route)
}
return (
<header
@ -213,7 +215,7 @@ export const Header = (props: Props) => {
routeName="home"
active={isZineVisible()}
body={t('journal')}
onClick={(event) => handleToggleMenuByLink(event, 'home')}
onClick={(event) => handleToggleMenuByLink(event, '/')}
/>
<Link
onMouseOver={() => toggleSubnavigation(true, setIsFeedVisible)}
@ -221,7 +223,7 @@ export const Header = (props: Props) => {
routeName="feed"
active={isFeedVisible()}
body={t('feed')}
onClick={(event) => handleToggleMenuByLink(event, 'feed')}
onClick={(event) => handleToggleMenuByLink(event, '/feed')}
/>
<Link
onMouseOver={() => toggleSubnavigation(true, setIsTopicsVisible)}
@ -229,14 +231,14 @@ export const Header = (props: Props) => {
routeName="topics"
active={isTopicsVisible()}
body={t('topics')}
onClick={(event) => handleToggleMenuByLink(event, 'topics')}
onClick={(event) => handleToggleMenuByLink(event, '/topics')}
/>
<Link
onMouseOver={() => hideSubnavigation(0)}
onMouseOut={() => hideSubnavigation(0)}
routeName="authors"
body={t('authors')}
onClick={(event) => handleToggleMenuByLink(event, 'authors')}
onClick={(event) => handleToggleMenuByLink(event, '/authors')}
/>
<Link
onMouseOver={() => toggleSubnavigation(true, setIsKnowledgeBaseVisible)}
@ -244,7 +246,7 @@ export const Header = (props: Props) => {
routeName="guide"
body={t('Knowledge base')}
active={isKnowledgeBaseVisible()}
onClick={(event) => handleToggleMenuByLink(event, 'guide')}
onClick={(event) => handleToggleMenuByLink(event, '/guide')}
/>
</ul>

View File

@ -1,8 +1,9 @@
import { clsx } from 'clsx'
import { For, Show, createMemo, createSignal } from 'solid-js'
import { Meta } from '@solidjs/meta'
import { useSearchParams } from '@solidjs/router'
import { clsx } from 'clsx'
import { For, Show, createEffect, createMemo, createSignal, on, onMount } from 'solid-js'
import { useTopics } from '~/context/topics'
import { useLocalize } from '../../../context/localize'
import type { Topic } from '../../../graphql/schema/core.gen'
import { capitalize } from '../../../utils/capitalize'
@ -12,14 +13,13 @@ import { scrollHandler } from '../../../utils/scroll'
import { TopicBadge } from '../../Topic/TopicBadge'
import { Loading } from '../../_shared/Loading'
import { SearchField } from '../../_shared/SearchField'
import styles from './AllTopics.module.scss'
type Props = {
topics: Topic[]
}
export const TOPICS_PER_PAGE = 20
export const TOPICS_PER_PAGE = 50
export const ABC = {
ru: 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ#',
en: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ#'
@ -28,12 +28,14 @@ export const ABC = {
export const AllTopics = (props: Props) => {
const { t, lang } = useLocalize()
const alphabet = createMemo(() => ABC[lang()])
const [searchParams] = useSearchParams<{ by?: string }>()
const sortedTopics = createMemo(() => props.topics)
const { setTopicsSort, sortedTopics } = useTopics()
const topics = createMemo(() => sortedTopics() || props.topics)
const [searchParams, ] = useSearchParams<{ by?: string }>()
createEffect(on(() => searchParams?.by || 'shouts', setTopicsSort, {defer: true}))
onMount(() => setTopicsSort('shouts'))
// sorted derivative
const byLetter = createMemo<{ [letter: string]: Topic[] }>(() => {
return sortedTopics().reduce(
return topics().reduce(
(acc, topic) => {
let letter = lang() === 'en' ? topic.slug[0].toUpperCase() : (topic?.title?.[0] || '').toUpperCase()
if (/[^ËА-яё]/.test(letter) && lang() === 'ru') letter = '#'
@ -63,9 +65,8 @@ export const AllTopics = (props: Props) => {
// filter
const [searchQuery, setSearchQuery] = createSignal('')
const filteredResults = createMemo(() => {
return dummyFilter(sortedTopics(), searchQuery(), lang())
})
const [filteredResults, setFilteredResults] = createSignal<Topic[]>([])
createEffect(() => setFilteredResults((_prev: Topic[]) => dummyFilter(topics(), searchQuery(), lang()) as Topic[]))
// subcomponent
const AllTopicsHead = () => (
@ -113,7 +114,7 @@ export const AllTopics = (props: Props) => {
<Meta name="twitter:card" content="summary_large_image" />
<Meta name="twitter:title" content={ogTitle} />
<Meta name="twitter:description" content={description} />
<Show when={Boolean(props.topics)} fallback={<Loading />}>
<Show when={Boolean(filteredResults())} fallback={<Loading />}>
<div class="row">
<div class="col-md-19 offset-md-5">
<AllTopicsHead />

View File

@ -281,9 +281,9 @@ export const SessionProvider = (props: {
const updateProfile = async (params: UpdateProfileInput) => {
const resp = await authenticate(authorizer().updateProfile, params as UpdateProfileInput)
console.debug('[context.session] updateProfile:', resp)
console.debug('[context.session] updateProfile response:', resp)
if (resp?.data) {
console.debug(resp.data)
// console.debug('[context.session] response data ', resp.data)
// FIXME: renew updated profile
return true
}
@ -292,12 +292,12 @@ export const SessionProvider = (props: {
const signOut = async () => {
const authResult: ApiResponse<GenericResponse> = await authorizer().logout()
console.debug(authResult)
// console.debug('[context.session] sign out', authResult)
if (authResult) {
setSession({} as AuthToken)
setIsSessionLoaded(true)
showSnackbar({ body: t("You've successfully logged out") })
console.debug(session())
// console.debug(session())
return true
}
return false

View File

@ -106,13 +106,15 @@ const saveTopicsToIndexedDB = async (db: IDBDatabase, topics: Topic[]) => {
await tx.done
}
}
export type TopicSort = 'shouts' | 'followers' | 'authors' | 'title' | ''
export const TopicsProvider = (props: { children: JSX.Element }) => {
const [topicEntities, setTopicEntities] = createSignal<{ [topicSlug: string]: Topic }>({})
const [sortAllBy, setSortAllBy] = createSignal<'shouts' | 'followers' | 'authors' | 'title'>('shouts')
const [sortedTopics, setSortedTopics] = createSignal<Topic[]>([])
const [sortAllBy, setSortAllBy] = createSignal<TopicSort>('')
const sortedTopics = createLazyMemo<Topic[]>(() => {
createEffect(() => {
const topics = Object.values(topicEntities())
console.debug('[context.topics] effect trig', topics)
switch (sortAllBy()) {
case 'followers': {
topics.sort(byTopicStatDesc('followers'))
@ -134,8 +136,7 @@ export const TopicsProvider = (props: { children: JSX.Element }) => {
topics.sort(byTopicStatDesc('shouts'))
}
}
return topics
setSortedTopics(topics as Topic[])
})
const topTopics = createMemo(() => {
@ -188,7 +189,7 @@ export const TopicsProvider = (props: { children: JSX.Element }) => {
const isCacheValid = now - timestamp < CACHE_LIFETIME
const topics = isCacheValid ? req : await loadAllTopics()
console.info(`[context.topics] got ${(topics as Topic[]).length || 0} topics`)
console.info(`[context.topics] got ${(topics as Topic[]).length || 0} topics from idb`)
addTopics(topics as Topic[])
setRandomTopic(getRandomTopicsFromArray(topics || [], 1).pop())
}

View File

@ -33,9 +33,9 @@ export const ArticlePage = (props: RouteSectionProps<{ article: Shout }>) => {
console.info('[routes.slug] mounted, connecting ga...')
await loadGAScript(gaIdentity)
initGA(gaIdentity)
console.debug('Google Analytics connected successfully')
console.debug('[routes.slug] Google Analytics connected successfully')
} catch (error) {
console.warn('Failed to connect Google Analytics:', error)
console.warn('[routes.slug] Failed to connect Google Analytics:', error)
}
}
})

View File

@ -1,8 +1,8 @@
import { type RouteDefinition, type RouteSectionProps, createAsync, useSearchParams } from '@solidjs/router'
import { Suspense, createEffect, createSignal, on } from 'solid-js'
import { Topic, TopicStat } from '~/graphql/schema/core.gen'
import { type RouteDefinition, type RouteSectionProps, createAsync } from '@solidjs/router'
import { Suspense, createEffect} from 'solid-js'
import { useTopics } from '~/context/topics'
import { Topic } from '~/graphql/schema/core.gen'
import { loadTopics } from '~/lib/api'
import { byTopicStatDesc } from '~/utils/sortby'
import { AllTopics } from '../components/Views/AllTopics'
import { Loading } from '../components/_shared/Loading'
import { PageLayout } from '../components/_shared/PageLayout'
@ -16,18 +16,16 @@ const fetchData = async () => {
export const route = { load: loadTopics } satisfies RouteDefinition
export default function HomePage(props: RouteSectionProps<{ topics: Topic[] }>) {
export default function AllTopicsPage(props: RouteSectionProps<{ topics: Topic[] }>) {
const { t } = useLocalize()
const topics = createAsync<Topic[]>(async () => props.data.topics || (await fetchData()) || [])
const [topicsSort, setTopicsSort] = createSignal<string>('shouts')
const [searchParams] = useSearchParams<{ by?: string }>()
createEffect(on(() => searchParams?.by || 'shouts', setTopicsSort))
const { addTopics } = useTopics()
createEffect(() => addTopics(topics()||[]))
return (
<PageLayout withPadding={true} title={`${t('Discours')}:${t('All topics')}`}>
<ReactionsProvider>
<Suspense fallback={<Loading />}>
<AllTopics topics={topics()?.sort(byTopicStatDesc(topicsSort() as keyof TopicStat)) || []} />
<AllTopics topics={topics() || []} />
</Suspense>
</ReactionsProvider>
</PageLayout>