fixes
This commit is contained in:
parent
55ccd419e2
commit
95f100e930
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"*.{js,ts,tsx,json,scss,css,html,astro}": "prettier --write",
|
"*.{js,ts,tsx,json,scss,css,html}": "prettier --write",
|
||||||
"package.json": "sort-package-json",
|
"package.json": "sort-package-json",
|
||||||
"*.{scss,css}": "stylelint",
|
"*.{scss,css}": "stylelint",
|
||||||
"*.{ts,tsx,js}": "eslint --fix",
|
"*.{ts,tsx,js}": "eslint --fix",
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { renderMarkdown } from '@astrojs/markdown-remark'
|
||||||
import { markdownOptions } from '../../../mdx.config'
|
import { markdownOptions } from '../../../mdx.config'
|
||||||
import { useStore } from '@nanostores/solid'
|
import { useStore } from '@nanostores/solid'
|
||||||
import { session } from '../../stores/auth'
|
import { session } from '../../stores/auth'
|
||||||
|
import { incrementView, loadArticle } from '../../stores/zine/articles'
|
||||||
|
|
||||||
const MAX_COMMENT_LEVEL = 6
|
const MAX_COMMENT_LEVEL = 6
|
||||||
|
|
||||||
|
@ -43,14 +44,24 @@ export const FullArticle = (props: ArticleProps) => {
|
||||||
const auth = useStore(session)
|
const auth = useStore(session)
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const b: string = props.article?.body
|
if (!props.article.body) {
|
||||||
if (b?.toString().startsWith('<')) {
|
loadArticle({ slug: props.article.slug })
|
||||||
setBody(b)
|
|
||||||
} else {
|
|
||||||
renderMarkdown(b, markdownOptions).then(({ code }) => setBody(code))
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// onMount(() => {
|
||||||
|
// const b: string = props.article?.body
|
||||||
|
// if (b?.toString().startsWith('<')) {
|
||||||
|
// setBody(b)
|
||||||
|
// } else {
|
||||||
|
// renderMarkdown(b, markdownOptions).then(({ code }) => setBody(code))
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
incrementView({ articleSlug: props.article.slug })
|
||||||
|
})
|
||||||
|
|
||||||
const formattedDate = createMemo(() => formatDate(new Date(props.article.createdAt)))
|
const formattedDate = createMemo(() => formatDate(new Date(props.article.createdAt)))
|
||||||
|
|
||||||
const mainTopic = () =>
|
const mainTopic = () =>
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { t } from '../../utils/intl'
|
||||||
import { useModalStore, showModal, useWarningsStore } from '../../stores/ui'
|
import { useModalStore, showModal, useWarningsStore } from '../../stores/ui'
|
||||||
import { useStore } from '@nanostores/solid'
|
import { useStore } from '@nanostores/solid'
|
||||||
import { session as ssession } from '../../stores/auth'
|
import { session as ssession } from '../../stores/auth'
|
||||||
import { route, router } from '../../stores/router'
|
import { handleClientRouteLinkClick, router } from '../../stores/router'
|
||||||
import './Header.scss'
|
import './Header.scss'
|
||||||
|
|
||||||
const resources = [
|
const resources = [
|
||||||
|
@ -42,8 +42,22 @@ export const Header = () => {
|
||||||
|
|
||||||
// derived
|
// derived
|
||||||
const authorized = createMemo(() => session()?.user?.slug)
|
const authorized = createMemo(() => session()?.user?.slug)
|
||||||
const enterClick = route(() => showModal('auth'))
|
|
||||||
const bellClick = createMemo(() => (authorized() ? route(toggleWarnings) : enterClick))
|
const handleEnterClick = (ev) => {
|
||||||
|
showModal('auth')
|
||||||
|
handleClientRouteLinkClick(ev)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBellIconClick = (ev) => {
|
||||||
|
if (!authorized()) {
|
||||||
|
handleEnterClick(ev)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleWarnings()
|
||||||
|
handleClientRouteLinkClick(ev)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header>
|
<header>
|
||||||
<Modal name="auth">
|
<Modal name="auth">
|
||||||
|
@ -52,7 +66,7 @@ export const Header = () => {
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<nav class="row header__inner" classList={{ fixed: fixed() }}>
|
<nav class="row header__inner" classList={{ fixed: fixed() }}>
|
||||||
<div class="main-logo col-auto">
|
<div class="main-logo col-auto">
|
||||||
<a href="/" onClick={route}>
|
<a href="/" onClick={handleClientRouteLinkClick}>
|
||||||
<img src="/logo.svg" alt={t('Discours')} />
|
<img src="/logo.svg" alt={t('Discours')} />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -60,7 +74,7 @@ export const Header = () => {
|
||||||
<For each={resources}>
|
<For each={resources}>
|
||||||
{(r: { href: string; name: string }) => (
|
{(r: { href: string; name: string }) => (
|
||||||
<li classList={{ selected: r.href === subpath() }}>
|
<li classList={{ selected: r.href === subpath() }}>
|
||||||
<a href={r.href} onClick={route}>
|
<a href={r.href} onClick={handleClientRouteLinkClick}>
|
||||||
{r.name}
|
{r.name}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -70,7 +84,7 @@ export const Header = () => {
|
||||||
<div class="usernav">
|
<div class="usernav">
|
||||||
<div class="usercontrol col">
|
<div class="usercontrol col">
|
||||||
<div class="usercontrol__item">
|
<div class="usercontrol__item">
|
||||||
<a href="#auth" onClick={bellClick}>
|
<a href="#auth" onClick={handleBellIconClick}>
|
||||||
<div>
|
<div>
|
||||||
<Icon name="bell-white" counter={authorized() ? getWarnings().length : 1} />
|
<Icon name="bell-white" counter={authorized() ? getWarnings().length : 1} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -87,7 +101,7 @@ export const Header = () => {
|
||||||
when={authorized()}
|
when={authorized()}
|
||||||
fallback={
|
fallback={
|
||||||
<div class="usercontrol__item loginbtn">
|
<div class="usercontrol__item loginbtn">
|
||||||
<a href="#auth" onClick={enterClick}>
|
<a href="#auth" onClick={handleEnterClick}>
|
||||||
{t('enter')}
|
{t('enter')}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin: 0;
|
margin-right: 2.2rem;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { groupByName } from '../../utils/groupby'
|
||||||
import Icon from '../Nav/Icon'
|
import Icon from '../Nav/Icon'
|
||||||
import { t } from '../../utils/intl'
|
import { t } from '../../utils/intl'
|
||||||
import { useAuthorsStore } from '../../stores/zine/authors'
|
import { useAuthorsStore } from '../../stores/zine/authors'
|
||||||
import { route, params as paramsStore } from '../../stores/router'
|
import { params as paramsStore, handleClientRouteLinkClick } from '../../stores/router'
|
||||||
import { session } from '../../stores/auth'
|
import { session } from '../../stores/auth'
|
||||||
import { useStore } from '@nanostores/solid'
|
import { useStore } from '@nanostores/solid'
|
||||||
import '../../styles/AllTopics.scss'
|
import '../../styles/AllTopics.scss'
|
||||||
|
@ -18,7 +18,9 @@ export const AllAuthorsPage = (props: any) => {
|
||||||
const [abc, setAbc] = createSignal([])
|
const [abc, setAbc] = createSignal([])
|
||||||
const auth = useStore(session)
|
const auth = useStore(session)
|
||||||
const subscribed = (s) => Boolean(auth()?.info?.authors && auth()?.info?.authors?.includes(s || ''))
|
const subscribed = (s) => Boolean(auth()?.info?.authors && auth()?.info?.authors?.includes(s || ''))
|
||||||
|
|
||||||
const params = useStore(paramsStore)
|
const params = useStore(paramsStore)
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if ((!params()['by'] || params()['by'] === 'abc') && abc().length === 0) {
|
if ((!params()['by'] || params()['by'] === 'abc') && abc().length === 0) {
|
||||||
console.log('[authors] default grouping by abc')
|
console.log('[authors] default grouping by abc')
|
||||||
|
@ -49,17 +51,17 @@ export const AllAuthorsPage = (props: any) => {
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<ul class="view-switcher">
|
<ul class="view-switcher">
|
||||||
<li classList={{ selected: params()['by'] === 'shouts' }}>
|
<li classList={{ selected: params()['by'] === 'shouts' }}>
|
||||||
<a href="/authors?by=shouts" onClick={route}>
|
<a href="/authors?by=shouts" onClick={handleClientRouteLinkClick}>
|
||||||
{t('By shouts')}
|
{t('By shouts')}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li classList={{ selected: params()['by'] === 'rating' }}>
|
<li classList={{ selected: params()['by'] === 'rating' }}>
|
||||||
<a href="/authors?by=rating" onClick={route}>
|
<a href="/authors?by=rating" onClick={handleClientRouteLinkClick}>
|
||||||
{t('By rating')}
|
{t('By rating')}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li classList={{ selected: !params()['by'] || params()['by'] === 'abc' }}>
|
<li classList={{ selected: !params()['by'] || params()['by'] === 'abc' }}>
|
||||||
<a href="/authors" onClick={route}>
|
<a href="/authors" onClick={handleClientRouteLinkClick}>
|
||||||
{t('By alphabet')}
|
{t('By alphabet')}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -4,25 +4,30 @@ import { byFirstChar, sortBy } from '../../utils/sortby'
|
||||||
import Icon from '../Nav/Icon'
|
import Icon from '../Nav/Icon'
|
||||||
import { t } from '../../utils/intl'
|
import { t } from '../../utils/intl'
|
||||||
import { useTopicsStore } from '../../stores/zine/topics'
|
import { useTopicsStore } from '../../stores/zine/topics'
|
||||||
import { params as paramstore, route } from '../../stores/router'
|
import { params as paramstore, handleClientRouteLinkClick, router } from '../../stores/router'
|
||||||
import { TopicCard } from '../Topic/Card'
|
import { TopicCard } from '../Topic/Card'
|
||||||
import { session } from '../../stores/auth'
|
import { session } from '../../stores/auth'
|
||||||
import { useStore } from '@nanostores/solid'
|
import { useStore } from '@nanostores/solid'
|
||||||
import { groupByTitle } from '../../utils/groupby'
|
|
||||||
import '../../styles/AllTopics.scss'
|
import '../../styles/AllTopics.scss'
|
||||||
|
import { groupByTitle } from '../../utils/groupby'
|
||||||
|
|
||||||
export const AllTopicsPage = (props: { topics?: Topic[] }) => {
|
export const AllTopicsPage = (props: { topics?: Topic[] }) => {
|
||||||
const [sortedTopics, setSortedTopics] = createSignal<Partial<Topic>[]>([])
|
const [sortedTopics, setSortedTopics] = createSignal<Partial<Topic>[]>([])
|
||||||
const [sortedKeys, setSortedKeys] = createSignal<string[]>()
|
const [sortedKeys, setSortedKeys] = createSignal<string[]>()
|
||||||
const [abc, setAbc] = createSignal([])
|
const [abc, setAbc] = createSignal([])
|
||||||
const { getSortedTopics: topicslist } = useTopicsStore({ topics: props.topics || [] })
|
const { getSortedTopics } = useTopicsStore({ topics: props.topics || [] })
|
||||||
const auth = useStore(session)
|
const auth = useStore(session)
|
||||||
|
|
||||||
const subscribed = (s) => Boolean(auth()?.info?.topics && auth()?.info?.topics?.includes(s || ''))
|
const subscribed = (s) => Boolean(auth()?.info?.topics && auth()?.info?.topics?.includes(s || ''))
|
||||||
|
|
||||||
const params = useStore(paramstore)
|
const params = useStore(paramstore)
|
||||||
|
|
||||||
|
console.log({ router })
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (abc().length === 0 && (!params()['by'] || params()['by'] === 'abc')) {
|
if (abc().length === 0 && (!params()['by'] || params()['by'] === 'abc')) {
|
||||||
console.log('[topics] default grouping by abc')
|
console.log('[topics] default grouping by abc')
|
||||||
const grouped = { ...groupByTitle(topicslist()) }
|
const grouped = { ...groupByTitle(getSortedTopics()) }
|
||||||
grouped['A-Z'] = sortBy(grouped['A-Z'], byFirstChar)
|
grouped['A-Z'] = sortBy(grouped['A-Z'], byFirstChar)
|
||||||
setAbc(grouped)
|
setAbc(grouped)
|
||||||
const keys = Object.keys(abc)
|
const keys = Object.keys(abc)
|
||||||
|
@ -30,88 +35,95 @@ export const AllTopicsPage = (props: { topics?: Topic[] }) => {
|
||||||
setSortedKeys(keys as string[])
|
setSortedKeys(keys as string[])
|
||||||
} else {
|
} else {
|
||||||
console.log('[topics] sorting by ' + params()['by'])
|
console.log('[topics] sorting by ' + params()['by'])
|
||||||
setSortedTopics(sortBy(topicslist(), params()['by']))
|
setSortedTopics(sortBy(getSortedTopics(), params()['by']))
|
||||||
}
|
}
|
||||||
}, [topicslist(), params()])
|
}, [getSortedTopics(), params()])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div class="all-topics-page">
|
||||||
<div class="all-topics-page">
|
<Show when={getSortedTopics().length > 0}>
|
||||||
<Show when={Boolean(sortedTopics()?.length)}>
|
<div class="wide-container">
|
||||||
<div class="wide-container">
|
<div class="shift-content">
|
||||||
<div class="shift-content">
|
<div class="row">
|
||||||
<div class="row">
|
<div class="col-md-9 page-header">
|
||||||
<div class="col-md-9 page-header">
|
<h1>{t('Topics')}</h1>
|
||||||
<h1>{t('Topics')}</h1>
|
<p>{t('Subscribe what you like to tune your personal feed')}</p>
|
||||||
<p>{t('Subscribe what you like to tune your personal feed')}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<ul class="view-switcher">
|
<ul class="view-switcher">
|
||||||
<li classList={{ selected: params()['by'] === 'shouts' }}>
|
<li classList={{ selected: params()['by'] === 'shouts' }}>
|
||||||
<a href="/topics?by=shouts" onClick={route}>
|
<a href="/topics?by=shouts" onClick={handleClientRouteLinkClick}>
|
||||||
{t('By shouts')}
|
{t('By shouts')}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li classList={{ selected: params()['by'] === 'authors' }}>
|
<li classList={{ selected: params()['by'] === 'authors' }}>
|
||||||
<a href="/topics?by=authors" onClick={route}>
|
<a href="/topics?by=authors" onClick={handleClientRouteLinkClick}>
|
||||||
{t('By authors')}
|
{t('By authors')}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li classList={{ selected: params()['by'] === 'abc' }}>
|
<li classList={{ selected: params()['by'] === 'abc' }}>
|
||||||
<a href="/topics" onClick={route}>
|
<a href="/topics" onClick={handleClientRouteLinkClick}>
|
||||||
{t('By alphabet')}
|
{t('By alphabet')}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="view-switcher__search">
|
<li class="view-switcher__search">
|
||||||
<a href="/topic/search">
|
<a href="/topic/search">
|
||||||
<Icon name="search" />
|
<Icon name="search" />
|
||||||
{t('Search topic')}
|
{t('Search topic')}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<Show
|
<div class="stats">
|
||||||
when={params()['by'] === 'abc'}
|
<For each={getSortedTopics()}>
|
||||||
fallback={() => (
|
{(topic) => (
|
||||||
<div class="stats">
|
<TopicCard topic={topic} compact={false} subscribed={subscribed(topic.slug)} />
|
||||||
<For each={sortedTopics()}>
|
|
||||||
{(topic: Topic) => (
|
|
||||||
<TopicCard topic={topic} compact={false} subscribed={subscribed(topic.slug)} />
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
>
|
</For>
|
||||||
<For each={sortedKeys() || []}>
|
|
||||||
{(letter: string) => (
|
|
||||||
<div class="group">
|
|
||||||
<h2>{letter}</h2>
|
|
||||||
<div class="container">
|
|
||||||
<div class="row">
|
|
||||||
<For each={abc()[letter]}>
|
|
||||||
{(topic: Partial<Topic>) => (
|
|
||||||
<div class="topic col-sm-6 col-md-3">
|
|
||||||
<div class="topic-title">
|
|
||||||
<a href={`/topic/${topic.slug}`}>{topic.title}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</Show>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/*FIXME*/}
|
||||||
|
{/*<Show*/}
|
||||||
|
{/* when={params()['by'] === 'abc'}*/}
|
||||||
|
{/* fallback={() => (*/}
|
||||||
|
{/* <div class="stats">*/}
|
||||||
|
{/* <For each={getSortedTopics()}>*/}
|
||||||
|
{/* {(topic: Topic) => (*/}
|
||||||
|
{/* <TopicCard topic={topic} compact={false} subscribed={subscribed(topic.slug)} />*/}
|
||||||
|
{/* )}*/}
|
||||||
|
{/* </For>*/}
|
||||||
|
{/* </div>*/}
|
||||||
|
{/* )}*/}
|
||||||
|
{/*>*/}
|
||||||
|
{/* <For each={sortedKeys() || []}>*/}
|
||||||
|
{/* {(letter: string) => (*/}
|
||||||
|
{/* <div class="group">*/}
|
||||||
|
{/* <h2>{letter}</h2>*/}
|
||||||
|
{/* <div class="container">*/}
|
||||||
|
{/* <div class="row">*/}
|
||||||
|
{/* <For each={abc()[letter]}>*/}
|
||||||
|
{/* {(topic: Partial<Topic>) => (*/}
|
||||||
|
{/* <div class="topic col-sm-6 col-md-3">*/}
|
||||||
|
{/* <div class="topic-title">*/}
|
||||||
|
{/* <a href={`/topic/${topic.slug}`}>{topic.title}</a>*/}
|
||||||
|
{/* </div>*/}
|
||||||
|
{/* </div>*/}
|
||||||
|
{/* )}*/}
|
||||||
|
{/* </For>*/}
|
||||||
|
{/* </div>*/}
|
||||||
|
{/* </div>*/}
|
||||||
|
{/* </div>*/}
|
||||||
|
{/* )}*/}
|
||||||
|
{/* </For>*/}
|
||||||
|
{/*</Show>*/}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</div>
|
||||||
</div>
|
</Show>
|
||||||
</>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { t } from '../../utils/intl'
|
||||||
import { useTopicsStore } from '../../stores/zine/topics'
|
import { useTopicsStore } from '../../stores/zine/topics'
|
||||||
import { loadPublishedArticles, useArticlesStore } from '../../stores/zine/articles'
|
import { loadPublishedArticles, useArticlesStore } from '../../stores/zine/articles'
|
||||||
import { useAuthorsStore } from '../../stores/zine/authors'
|
import { useAuthorsStore } from '../../stores/zine/authors'
|
||||||
|
import { router } from '../../stores/router'
|
||||||
|
|
||||||
type HomeProps = {
|
type HomeProps = {
|
||||||
randomTopics: Topic[]
|
randomTopics: Topic[]
|
||||||
|
@ -26,7 +27,7 @@ type HomeProps = {
|
||||||
offset?: number
|
offset?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const LAYOUTS = ['article', 'prose', 'music', 'video', 'image']
|
// const LAYOUTS = ['article', 'prose', 'music', 'video', 'image']
|
||||||
|
|
||||||
export const HomePage = (props: HomeProps) => {
|
export const HomePage = (props: HomeProps) => {
|
||||||
const [someLayout, setSomeLayout] = createSignal([] as Shout[])
|
const [someLayout, setSomeLayout] = createSignal([] as Shout[])
|
||||||
|
|
|
@ -99,7 +99,7 @@ export const TopicPage = (props: TopicProps) => {
|
||||||
<Show when={sortedArticles().length > 5}>
|
<Show when={sortedArticles().length > 5}>
|
||||||
<Beside
|
<Beside
|
||||||
title={t('Topic is supported by')}
|
title={t('Topic is supported by')}
|
||||||
values={getAuthorsByTopic()[topic().slug]}
|
values={getAuthorsByTopic()[topic().slug].slice(0, 7)}
|
||||||
beside={sortedArticles()[6]}
|
beside={sortedArticles()[6]}
|
||||||
wrapper={'author'}
|
wrapper={'author'}
|
||||||
/>
|
/>
|
||||||
|
|
15
src/components/providers/ServerRouterProvider.tsx
Normal file
15
src/components/providers/ServerRouterProvider.tsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { isServer } from 'solid-js/web'
|
||||||
|
import { router } from '../../stores/router'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
href: string
|
||||||
|
children: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ServerRouterProvider = (props: Props) => {
|
||||||
|
if (isServer) {
|
||||||
|
router.open(props.href)
|
||||||
|
}
|
||||||
|
|
||||||
|
return props.children
|
||||||
|
}
|
|
@ -4,12 +4,10 @@ import { useStore } from '@nanostores/solid'
|
||||||
import { Suspense } from 'solid-js'
|
import { Suspense } from 'solid-js'
|
||||||
import { Header } from '../components/Nav/Header'
|
import { Header } from '../components/Nav/Header'
|
||||||
import { locale as langstore } from '../stores/ui'
|
import { locale as langstore } from '../stores/ui'
|
||||||
import { router } from '../stores/router'
|
|
||||||
import { t } from '../utils/intl'
|
import { t } from '../utils/intl'
|
||||||
|
|
||||||
const { title } = Astro.params
|
const { title } = Astro.params
|
||||||
const locale = useStore(langstore)
|
const locale = useStore(langstore)
|
||||||
router.open(Astro.url.pathname) // mb doesn't work!
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang={locale() || 'ru'}>
|
<html lang={locale() || 'ru'}>
|
||||||
|
|
|
@ -3,30 +3,33 @@ import '../styles/app.scss'
|
||||||
import { Suspense } from 'solid-js'
|
import { Suspense } from 'solid-js'
|
||||||
import { Header } from '../components/Nav/Header'
|
import { Header } from '../components/Nav/Header'
|
||||||
import { Footer } from '../components/Discours/Footer'
|
import { Footer } from '../components/Discours/Footer'
|
||||||
|
import { ServerRouterProvider } from '../components/providers/ServerRouterProvider'
|
||||||
import { t } from '../utils/intl'
|
import { t } from '../utils/intl'
|
||||||
import { locale as langstore } from '../stores/ui'
|
import { locale as langstore } from '../stores/ui'
|
||||||
import { useStore } from '@nanostores/solid'
|
import { useStore } from '@nanostores/solid'
|
||||||
import { router } from '../stores/router'
|
|
||||||
|
|
||||||
|
const { pathname, search } = Astro.url
|
||||||
|
|
||||||
|
// FIXME always returns ru
|
||||||
const locale = useStore(langstore)
|
const locale = useStore(langstore)
|
||||||
// FIXME why
|
|
||||||
router.open(Astro.url.pathname) // looks like doesn't work!
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang={locale() || 'en'}>
|
<ServerRouterProvider href={pathname + search}>
|
||||||
<head>
|
<html lang={locale() || 'en'}>
|
||||||
<meta charset="utf-8" />
|
<head>
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
<title>{t('Discours')}</title>
|
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||||
</head>
|
<title>{t('Discours')}</title>
|
||||||
<body>
|
</head>
|
||||||
<Header />
|
<body>
|
||||||
<main class="main-content">
|
<Header />
|
||||||
<Suspense>
|
<main class="main-content">
|
||||||
<slot />
|
<Suspense>
|
||||||
</Suspense>
|
<slot />
|
||||||
</main>
|
</Suspense>
|
||||||
<Footer />
|
</main>
|
||||||
</body>
|
<Footer />
|
||||||
</html>
|
</body>
|
||||||
|
</html>
|
||||||
|
</ServerRouterProvider>
|
||||||
|
|
|
@ -15,8 +15,8 @@ Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate'
|
||||||
|
|
||||||
<Zine>
|
<Zine>
|
||||||
<HomePage
|
<HomePage
|
||||||
randomTopics={randomTopics}
|
|
||||||
recentPublishedArticles={recentPublished}
|
recentPublishedArticles={recentPublished}
|
||||||
|
randomTopics={randomTopics}
|
||||||
topMonthArticles={topMonth}
|
topMonthArticles={topMonth}
|
||||||
topOverallArticles={topOverall}
|
topOverallArticles={topOverall}
|
||||||
client:load
|
client:load
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { createRouter, createSearchParams } from '@nanostores/router'
|
import { createRouter, createSearchParams } from '@nanostores/router'
|
||||||
import { createEffect } from 'solid-js'
|
|
||||||
import { isServer } from 'solid-js/web'
|
import { isServer } from 'solid-js/web'
|
||||||
|
|
||||||
// Types for :params in route templates
|
// Types for :params in route templates
|
||||||
|
@ -41,24 +40,15 @@ export const router = createRouter<Routes>(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// suppresses reload
|
export const handleClientRouteLinkClick = (ev) => {
|
||||||
export const route = (ev) => {
|
const href = ev.target.href
|
||||||
// eslint-disable-next-line unicorn/consistent-function-scoping
|
console.log('[router] faster link', href)
|
||||||
const _route = (ev) => {
|
ev.stopPropagation()
|
||||||
const href: string = ev.target.href
|
ev.preventDefault()
|
||||||
console.log('[router] faster link', href)
|
router.open(href)
|
||||||
ev.stopPropoganation()
|
|
||||||
ev.preventDefault()
|
|
||||||
router.open(href)
|
|
||||||
}
|
|
||||||
if (typeof ev === 'function') {
|
|
||||||
return _route
|
|
||||||
} else if (!isServer && ev?.target && ev.target.href) {
|
|
||||||
_route(ev)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isServer) {
|
if (!isServer) {
|
||||||
console.log('[router] client runtime')
|
const { pathname, search } = window.location
|
||||||
createEffect(() => router.open(window.location.pathname), [window.location])
|
router.open(pathname + search)
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,6 +170,14 @@ export const loadSearchResults = async ({
|
||||||
addSortedArticles(newArticles)
|
addSortedArticles(newArticles)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const incrementView = async ({ articleSlug }: { articleSlug: string }): Promise<void> => {
|
||||||
|
await apiClient.incrementView({ articleSlug })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loadArticle = async ({ slug }: { slug: string }): Promise<Shout> => {
|
||||||
|
return await apiClient.getArticle({ slug })
|
||||||
|
}
|
||||||
|
|
||||||
type InitialState = {
|
type InitialState = {
|
||||||
sortedArticles?: Shout[]
|
sortedArticles?: Shout[]
|
||||||
topRatedArticles?: Shout[]
|
topRatedArticles?: Shout[]
|
||||||
|
|
|
@ -14,7 +14,9 @@ let topicEntitiesStore: WritableAtom<{ [topicSlug: string]: Topic }>
|
||||||
let sortedTopicsStore: ReadableAtom<Topic[]>
|
let sortedTopicsStore: ReadableAtom<Topic[]>
|
||||||
let topTopicsStore: ReadableAtom<Topic[]>
|
let topTopicsStore: ReadableAtom<Topic[]>
|
||||||
let randomTopicsStore: WritableAtom<Topic[]>
|
let randomTopicsStore: WritableAtom<Topic[]>
|
||||||
let topicsByAuthorStore: WritableAtom<{ [authorSlug: string]: Topic[] }>
|
let topicsByAuthorStore: WritableAtom<{ [authorSlug: string]: Topic[] }> = atom<{
|
||||||
|
[authorSlug: string]: Topic[]
|
||||||
|
}>({})
|
||||||
|
|
||||||
const initStore = (initial?: Record<string, Topic>) => {
|
const initStore = (initial?: Record<string, Topic>) => {
|
||||||
if (topicEntitiesStore) {
|
if (topicEntitiesStore) {
|
||||||
|
|
|
@ -30,6 +30,7 @@ import authReset from '../graphql/mutation/auth-reset'
|
||||||
import authForget from '../graphql/mutation/auth-forget'
|
import authForget from '../graphql/mutation/auth-forget'
|
||||||
import authResend from '../graphql/mutation/auth-resend'
|
import authResend from '../graphql/mutation/auth-resend'
|
||||||
import authorsBySlugs from '../graphql/query/authors-by-slugs'
|
import authorsBySlugs from '../graphql/query/authors-by-slugs'
|
||||||
|
import incrementView from '../graphql/mutation/increment-view'
|
||||||
|
|
||||||
const log = getLogger('api-client')
|
const log = getLogger('api-client')
|
||||||
|
|
||||||
|
@ -81,7 +82,7 @@ export const apiClient = {
|
||||||
})
|
})
|
||||||
.toPromise()
|
.toPromise()
|
||||||
|
|
||||||
return response.data.searchQuery
|
return response.data?.searchQuery || []
|
||||||
},
|
},
|
||||||
getRecentArticles: async ({
|
getRecentArticles: async ({
|
||||||
limit = FEED_SIZE,
|
limit = FEED_SIZE,
|
||||||
|
@ -266,5 +267,8 @@ export const apiClient = {
|
||||||
const response = await privateGraphQLClient.mutation(reactionDestroy, { id }).toPromise()
|
const response = await privateGraphQLClient.mutation(reactionDestroy, { id }).toPromise()
|
||||||
|
|
||||||
return response.data.deleteReaction
|
return response.data.deleteReaction
|
||||||
|
},
|
||||||
|
incrementView: async ({ articleSlug }) => {
|
||||||
|
await privateGraphQLClient.mutation(incrementView, { shout: articleSlug })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user