home-fix+topics-wip
This commit is contained in:
parent
a616f97fe4
commit
4e631f5f91
|
@ -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>
|
||||
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue
Block a user