commit
b7f3e4363a
|
@ -43,34 +43,34 @@ const astroConfig: AstroUserConfig = {
|
||||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
manualChunks(id) {
|
manualChunks(id) {
|
||||||
if (id.includes('node_modules')) {
|
if (id.includes('node_modules')) {
|
||||||
let chunkid = 'vendor'
|
// FIXME: doesn't work in production
|
||||||
if (id.includes('solid')) {
|
// if (id.includes('solid')) {
|
||||||
chunkid = 'solid'
|
// chunkid = 'solid'
|
||||||
}
|
// }
|
||||||
if (id.includes('acorn')) {
|
// if (id.includes('acorn')) {
|
||||||
chunkid = 'acorn'
|
// chunkid = 'acorn'
|
||||||
}
|
// }
|
||||||
if (id.includes('simple-peer')) {
|
// if (id.includes('simple-peer')) {
|
||||||
chunkid = 'simple-peer'
|
// chunkid = 'simple-peer'
|
||||||
}
|
// }
|
||||||
if (id.includes('prosemirror')) {
|
// if (id.includes('prosemirror')) {
|
||||||
chunkid = 'prosemirror'
|
// chunkid = 'prosemirror'
|
||||||
}
|
// }
|
||||||
if (id.includes('markdown') || id.includes('mdurl')) {
|
// if (id.includes('markdown') || id.includes('mdurl')) {
|
||||||
chunkid = 'markdown'
|
// chunkid = 'markdown'
|
||||||
}
|
// }
|
||||||
if (id.includes('swiper')) {
|
// if (id.includes('swiper')) {
|
||||||
chunkid = 'swiper'
|
// chunkid = 'swiper'
|
||||||
}
|
// }
|
||||||
if (
|
// if (
|
||||||
id.includes('yjs') ||
|
// id.includes('yjs') ||
|
||||||
id.includes('y-prosemirror') ||
|
// id.includes('y-prosemirror') ||
|
||||||
id.includes('y-protocols') ||
|
// id.includes('y-protocols') ||
|
||||||
id.includes('y-webrtc')
|
// id.includes('y-webrtc')
|
||||||
) {
|
// ) {
|
||||||
chunkid = 'yjs'
|
// chunkid = 'yjs'
|
||||||
}
|
// }
|
||||||
return chunkid
|
return 'vendor'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
5
public/icons/arrows-rotate.svg
Normal file
5
public/icons/arrows-rotate.svg
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 512 512">
|
||||||
|
<path
|
||||||
|
d="M105.1 202.6c7.7-21.8 20.2-42.3 37.8-59.8c62.5-62.5 163.8-62.5 226.3 0L386.3 160H336c-17.7 0-32 14.3-32 32s14.3 32 32 32H463.5c0 0 0 0 0 0h.4c17.7 0 32-14.3 32-32V64c0-17.7-14.3-32-32-32s-32 14.3-32 32v51.2L414.4 97.6c-87.5-87.5-229.3-87.5-316.8 0C73.2 122 55.6 150.7 44.8 181.4c-5.9 16.7 2.9 34.9 19.5 40.8s34.9-2.9 40.8-19.5zM39 289.3c-5 1.5-9.8 4.2-13.7 8.2c-4 4-6.7 8.8-8.1 14c-.3 1.2-.6 2.5-.8 3.8c-.3 1.7-.4 3.4-.4 5.1V448c0 17.7 14.3 32 32 32s32-14.3 32-32V396.9l17.6 17.5 0 0c87.5 87.4 229.3 87.4 316.7 0c24.4-24.4 42.1-53.1 52.9-83.7c5.9-16.7-2.9-34.9-19.5-40.8s-34.9 2.9-40.8 19.5c-7.7 21.8-20.2 42.3-37.8 59.8c-62.5 62.5-163.8 62.5-226.3 0l-.1-.1L125.6 352H176c17.7 0 32-14.3 32-32s-14.3-32-32-32H48.4c-1.6 0-3.2 .1-4.8 .3s-3.1 .5-4.6 1z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 842 B |
|
@ -37,7 +37,6 @@ const formatDate = (date: Date) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FullArticle = (props: ArticleProps) => {
|
export const FullArticle = (props: ArticleProps) => {
|
||||||
const body = createMemo(() => props.article.body.toString().trim())
|
|
||||||
const { session } = useAuthStore()
|
const { session } = useAuthStore()
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
@ -93,9 +92,16 @@ export const FullArticle = (props: ArticleProps) => {
|
||||||
<div class="shout__cover" style={{ 'background-image': `url('${props.article.cover}')` }} />
|
<div class="shout__cover" style={{ 'background-image': `url('${props.article.cover}')` }} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Show when={Boolean(props.article.body)}>
|
||||||
<div class="shout__body">
|
<div class="shout__body">
|
||||||
<MD body={body()} />
|
<Show
|
||||||
|
when={!props.article.body.startsWith('<')}
|
||||||
|
fallback={<div innerHTML={props.article.body} />}
|
||||||
|
>
|
||||||
|
<MD body={props.article.body} />
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
</Show>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<div class="col-md-8 shift-content">
|
<div class="col-md-8 shift-content">
|
||||||
|
|
27
src/components/Loading.module.scss
Normal file
27
src/components/Loading.module.scss
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
.container {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
animation-name: spin;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
background-image: url(/icons/arrows-rotate.svg);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
animation-duration: 2s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
}
|
9
src/components/Loading.tsx
Normal file
9
src/components/Loading.tsx
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import styles from './Loading.module.scss'
|
||||||
|
|
||||||
|
export const Loading = () => {
|
||||||
|
return (
|
||||||
|
<div class={styles.container}>
|
||||||
|
<div class={styles.icon} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import { useAuthStore, signIn, register } from '../../stores/auth'
|
||||||
import { useValidator } from '../../utils/validators'
|
import { useValidator } from '../../utils/validators'
|
||||||
import { baseUrl } from '../../graphql/publicGraphQLClient'
|
import { baseUrl } from '../../graphql/publicGraphQLClient'
|
||||||
import { ApiError } from '../../utils/apiClient'
|
import { ApiError } from '../../utils/apiClient'
|
||||||
|
import { handleClientRouteLinkClick } from '../../stores/router'
|
||||||
|
|
||||||
type AuthMode = 'sign-in' | 'sign-up' | 'forget' | 'reset' | 'resend' | 'password'
|
type AuthMode = 'sign-in' | 'sign-up' | 'forget' | 'reset' | 'resend' | 'password'
|
||||||
|
|
||||||
|
@ -30,9 +31,16 @@ const titles = {
|
||||||
|
|
||||||
// const isProperEmail = (email) => email && email.length > 5 && email.includes('@') && email.includes('.')
|
// const isProperEmail = (email) => email && email.length > 5 && email.includes('@') && email.includes('.')
|
||||||
|
|
||||||
|
// 3rd party provider auth handler
|
||||||
|
const oauth = (provider: string): void => {
|
||||||
|
const popup = window.open(`${baseUrl}/oauth/${provider}`, provider, 'width=740, height=420')
|
||||||
|
popup?.focus()
|
||||||
|
hideModal()
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME !!!
|
// FIXME !!!
|
||||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
export default (props: { code?: string; mode?: string }) => {
|
export default (props: { code?: string; mode?: AuthMode }) => {
|
||||||
const { session } = useAuthStore()
|
const { session } = useAuthStore()
|
||||||
const [handshaking] = createSignal(false)
|
const [handshaking] = createSignal(false)
|
||||||
const { getModal } = useModalStore()
|
const { getModal } = useModalStore()
|
||||||
|
@ -45,13 +53,6 @@ export default (props: { code?: string; mode?: string }) => {
|
||||||
let passElement: HTMLInputElement | undefined
|
let passElement: HTMLInputElement | undefined
|
||||||
let codeElement: HTMLInputElement | undefined
|
let codeElement: HTMLInputElement | undefined
|
||||||
|
|
||||||
// 3rd party provider auth handler
|
|
||||||
const oauth = (provider: string): void => {
|
|
||||||
const popup = window.open(`${baseUrl}/oauth/${provider}`, provider, 'width=740, height=420')
|
|
||||||
popup?.focus()
|
|
||||||
hideModal()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: restore logic
|
// FIXME: restore logic
|
||||||
// const usedEmails = {}
|
// const usedEmails = {}
|
||||||
// const checkEmailAsync = async (email: string) => {
|
// const checkEmailAsync = async (email: string) => {
|
||||||
|
@ -179,9 +180,15 @@ export default (props: { code?: string; mode?: string }) => {
|
||||||
{t('New stories every day and even more!')}
|
{t('New stories every day and even more!')}
|
||||||
</p>
|
</p>
|
||||||
<p class="disclamer">
|
<p class="disclamer">
|
||||||
{t('By signing up you agree with our')}
|
{t('By signing up you agree with our')}{' '}
|
||||||
<a href="/about/terms-of-use" onClick={hideModal}>
|
<a
|
||||||
{' ' + t('terms of use')}
|
href="/about/terms-of-use"
|
||||||
|
onClick={(event) => {
|
||||||
|
hideModal()
|
||||||
|
handleClientRouteLinkClick(event)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('terms of use')}
|
||||||
</a>
|
</a>
|
||||||
, {t('personal data usage and email notifications')}.
|
, {t('personal data usage and email notifications')}.
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -116,7 +116,7 @@ export const Header = (props: Props) => {
|
||||||
>
|
>
|
||||||
<For each={resources}>
|
<For each={resources}>
|
||||||
{(r) => (
|
{(r) => (
|
||||||
<li classList={{ selected: r.route === getPage().route }}>
|
<li classList={{ [styles.selected]: r.route === getPage().route }}>
|
||||||
<a href={getPagePath(router, r.route, null)} onClick={handleClientRouteLinkClick}>
|
<a href={getPagePath(router, r.route, null)} onClick={handleClientRouteLinkClick}>
|
||||||
{r.name}
|
{r.name}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { AllAuthorsView } from '../Views/AllAuthors'
|
||||||
import type { PageProps } from '../types'
|
import type { PageProps } from '../types'
|
||||||
import { createSignal, onMount, Show } from 'solid-js'
|
import { createSignal, onMount, Show } from 'solid-js'
|
||||||
import { loadAllAuthors } from '../../stores/zine/authors'
|
import { loadAllAuthors } from '../../stores/zine/authors'
|
||||||
import { t } from '../../utils/intl'
|
import { Loading } from '../Loading'
|
||||||
|
|
||||||
export const AllAuthorsPage = (props: PageProps) => {
|
export const AllAuthorsPage = (props: PageProps) => {
|
||||||
const [isLoaded, setIsLoaded] = createSignal<boolean>(Boolean(props.allAuthors))
|
const [isLoaded, setIsLoaded] = createSignal<boolean>(Boolean(props.allAuthors))
|
||||||
|
@ -19,7 +19,7 @@ export const AllAuthorsPage = (props: PageProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<Show when={isLoaded()} fallback={t('Loading')}>
|
<Show when={isLoaded()} fallback={<Loading />}>
|
||||||
<AllAuthorsView authors={props.allAuthors} />
|
<AllAuthorsView authors={props.allAuthors} />
|
||||||
</Show>
|
</Show>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|
|
@ -2,8 +2,8 @@ import { MainLayout } from '../Layouts/MainLayout'
|
||||||
import { AllTopicsView } from '../Views/AllTopics'
|
import { AllTopicsView } from '../Views/AllTopics'
|
||||||
import type { PageProps } from '../types'
|
import type { PageProps } from '../types'
|
||||||
import { createSignal, onMount, Show } from 'solid-js'
|
import { createSignal, onMount, Show } from 'solid-js'
|
||||||
import { t } from '../../utils/intl'
|
|
||||||
import { loadAllTopics } from '../../stores/zine/topics'
|
import { loadAllTopics } from '../../stores/zine/topics'
|
||||||
|
import { Loading } from '../Loading'
|
||||||
|
|
||||||
export const AllTopicsPage = (props: PageProps) => {
|
export const AllTopicsPage = (props: PageProps) => {
|
||||||
const [isLoaded, setIsLoaded] = createSignal<boolean>(Boolean(props.allTopics))
|
const [isLoaded, setIsLoaded] = createSignal<boolean>(Boolean(props.allTopics))
|
||||||
|
@ -19,7 +19,7 @@ export const AllTopicsPage = (props: PageProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<Show when={isLoaded()} fallback={t('Loading')}>
|
<Show when={isLoaded()} fallback={<Loading />}>
|
||||||
<AllTopicsView topics={props.allTopics} />
|
<AllTopicsView topics={props.allTopics} />
|
||||||
</Show>
|
</Show>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|
|
@ -3,9 +3,9 @@ import { ArticleView } from '../Views/Article'
|
||||||
import type { PageProps } from '../types'
|
import type { PageProps } from '../types'
|
||||||
import { loadArticle, useArticlesStore } from '../../stores/zine/articles'
|
import { loadArticle, useArticlesStore } from '../../stores/zine/articles'
|
||||||
import { createMemo, onMount, Show } from 'solid-js'
|
import { createMemo, onMount, Show } from 'solid-js'
|
||||||
import { t } from '../../utils/intl'
|
|
||||||
import type { Shout } from '../../graphql/types.gen'
|
import type { Shout } from '../../graphql/types.gen'
|
||||||
import { useRouter } from '../../stores/router'
|
import { useRouter } from '../../stores/router'
|
||||||
|
import { Loading } from '../Loading'
|
||||||
|
|
||||||
export const ArticlePage = (props: PageProps) => {
|
export const ArticlePage = (props: PageProps) => {
|
||||||
const sortedArticles = props.article ? [props.article] : []
|
const sortedArticles = props.article ? [props.article] : []
|
||||||
|
@ -38,7 +38,7 @@ export const ArticlePage = (props: PageProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout headerTitle={article()?.title || ''}>
|
<MainLayout headerTitle={article()?.title || ''}>
|
||||||
<Show when={Boolean(article())} fallback={t('Loading')}>
|
<Show when={Boolean(article())} fallback={<Loading />}>
|
||||||
<ArticleView article={article()} />
|
<ArticleView article={article()} />
|
||||||
</Show>
|
</Show>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|
|
@ -4,8 +4,8 @@ import type { PageProps } from '../types'
|
||||||
import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js'
|
import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js'
|
||||||
import { loadArticlesForAuthors, resetSortedArticles } from '../../stores/zine/articles'
|
import { loadArticlesForAuthors, resetSortedArticles } from '../../stores/zine/articles'
|
||||||
import { useRouter } from '../../stores/router'
|
import { useRouter } from '../../stores/router'
|
||||||
import { t } from '../../utils/intl'
|
|
||||||
import { loadAuthor } from '../../stores/zine/authors'
|
import { loadAuthor } from '../../stores/zine/authors'
|
||||||
|
import { Loading } from '../Loading'
|
||||||
|
|
||||||
export const AuthorPage = (props: PageProps) => {
|
export const AuthorPage = (props: PageProps) => {
|
||||||
const [isLoaded, setIsLoaded] = createSignal(Boolean(props.authorArticles) && Boolean(props.author))
|
const [isLoaded, setIsLoaded] = createSignal(Boolean(props.authorArticles) && Boolean(props.author))
|
||||||
|
@ -37,7 +37,7 @@ export const AuthorPage = (props: PageProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<Show when={isLoaded()} fallback={t('Loading')}>
|
<Show when={isLoaded()} fallback={<Loading />}>
|
||||||
<AuthorView author={props.author} authorArticles={props.authorArticles} authorSlug={slug()} />
|
<AuthorView author={props.author} authorArticles={props.authorArticles} authorSlug={slug()} />
|
||||||
</Show>
|
</Show>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { FeedView } from '../Views/Feed'
|
||||||
import type { PageProps } from '../types'
|
import type { PageProps } from '../types'
|
||||||
import { createSignal, onCleanup, onMount, Show } from 'solid-js'
|
import { createSignal, onCleanup, onMount, Show } from 'solid-js'
|
||||||
import { loadRecentArticles, resetSortedArticles } from '../../stores/zine/articles'
|
import { loadRecentArticles, resetSortedArticles } from '../../stores/zine/articles'
|
||||||
import { t } from '../../utils/intl'
|
import { Loading } from '../Loading'
|
||||||
|
|
||||||
export const FeedPage = (props: PageProps) => {
|
export const FeedPage = (props: PageProps) => {
|
||||||
const [isLoaded, setIsLoaded] = createSignal(Boolean(props.feedArticles))
|
const [isLoaded, setIsLoaded] = createSignal(Boolean(props.feedArticles))
|
||||||
|
@ -22,7 +22,7 @@ export const FeedPage = (props: PageProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<Show when={isLoaded()} fallback={t('Loading')}>
|
<Show when={isLoaded()} fallback={<Loading />}>
|
||||||
<FeedView articles={props.feedArticles} />
|
<FeedView articles={props.feedArticles} />
|
||||||
</Show>
|
</Show>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|
|
@ -2,9 +2,9 @@ import { HomeView } from '../Views/Home'
|
||||||
import { MainLayout } from '../Layouts/MainLayout'
|
import { MainLayout } from '../Layouts/MainLayout'
|
||||||
import type { PageProps } from '../types'
|
import type { PageProps } from '../types'
|
||||||
import { createSignal, onCleanup, onMount, Show } from 'solid-js'
|
import { createSignal, onCleanup, onMount, Show } from 'solid-js'
|
||||||
import { t } from '../../utils/intl'
|
|
||||||
import { loadPublishedArticles, resetSortedArticles } from '../../stores/zine/articles'
|
import { loadPublishedArticles, resetSortedArticles } from '../../stores/zine/articles'
|
||||||
import { loadRandomTopics } from '../../stores/zine/topics'
|
import { loadRandomTopics } from '../../stores/zine/topics'
|
||||||
|
import { Loading } from '../Loading'
|
||||||
|
|
||||||
export const HomePage = (props: PageProps) => {
|
export const HomePage = (props: PageProps) => {
|
||||||
const [isLoaded, setIsLoaded] = createSignal(Boolean(props.homeArticles) && Boolean(props.randomTopics))
|
const [isLoaded, setIsLoaded] = createSignal(Boolean(props.homeArticles) && Boolean(props.randomTopics))
|
||||||
|
@ -24,7 +24,7 @@ export const HomePage = (props: PageProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<Show when={isLoaded()} fallback={t('Loading')}>
|
<Show when={isLoaded()} fallback={<Loading />}>
|
||||||
<HomeView randomTopics={props.randomTopics} recentPublishedArticles={props.homeArticles || []} />
|
<HomeView randomTopics={props.randomTopics} recentPublishedArticles={props.homeArticles || []} />
|
||||||
</Show>
|
</Show>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|
|
@ -3,8 +3,8 @@ import { SearchView } from '../Views/Search'
|
||||||
import type { PageProps } from '../types'
|
import type { PageProps } from '../types'
|
||||||
import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js'
|
import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js'
|
||||||
import { loadSearchResults, resetSortedArticles } from '../../stores/zine/articles'
|
import { loadSearchResults, resetSortedArticles } from '../../stores/zine/articles'
|
||||||
import { t } from '../../utils/intl'
|
|
||||||
import { useRouter } from '../../stores/router'
|
import { useRouter } from '../../stores/router'
|
||||||
|
import { Loading } from '../Loading'
|
||||||
|
|
||||||
export const SearchPage = (props: PageProps) => {
|
export const SearchPage = (props: PageProps) => {
|
||||||
const [isLoaded, setIsLoaded] = createSignal(Boolean(props.searchResults))
|
const [isLoaded, setIsLoaded] = createSignal(Boolean(props.searchResults))
|
||||||
|
@ -34,7 +34,7 @@ export const SearchPage = (props: PageProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<Show when={isLoaded()} fallback={t('Loading')}>
|
<Show when={isLoaded()} fallback={<Loading />}>
|
||||||
<SearchView results={props.searchResults || []} query={props.searchQuery} />
|
<SearchView results={props.searchResults || []} query={props.searchQuery} />
|
||||||
</Show>
|
</Show>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|
|
@ -4,8 +4,8 @@ import type { PageProps } from '../types'
|
||||||
import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js'
|
import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js'
|
||||||
import { loadArticlesForTopics, resetSortedArticles } from '../../stores/zine/articles'
|
import { loadArticlesForTopics, resetSortedArticles } from '../../stores/zine/articles'
|
||||||
import { useRouter } from '../../stores/router'
|
import { useRouter } from '../../stores/router'
|
||||||
import { t } from '../../utils/intl'
|
|
||||||
import { loadTopic } from '../../stores/zine/topics'
|
import { loadTopic } from '../../stores/zine/topics'
|
||||||
|
import { Loading } from '../Loading'
|
||||||
|
|
||||||
export const TopicPage = (props: PageProps) => {
|
export const TopicPage = (props: PageProps) => {
|
||||||
const [isLoaded, setIsLoaded] = createSignal(Boolean(props.authorArticles) && Boolean(props.author))
|
const [isLoaded, setIsLoaded] = createSignal(Boolean(props.authorArticles) && Boolean(props.author))
|
||||||
|
@ -37,7 +37,7 @@ export const TopicPage = (props: PageProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<Show when={isLoaded()} fallback={t('Loading')}>
|
<Show when={isLoaded()} fallback={<Loading />}>
|
||||||
<TopicView topic={props.topic} topicArticles={props.topicArticles} topicSlug={slug()} />
|
<TopicView topic={props.topic} topicArticles={props.topicArticles} topicSlug={slug()} />
|
||||||
</Show>
|
</Show>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|
|
@ -9,8 +9,9 @@ import { useAuthorsStore } from '../../stores/zine/authors'
|
||||||
import { useArticlesStore } from '../../stores/zine/articles'
|
import { useArticlesStore } from '../../stores/zine/articles'
|
||||||
|
|
||||||
import '../../styles/Topic.scss'
|
import '../../styles/Topic.scss'
|
||||||
// import { useTopicsStore } from '../../stores/zine/topics'
|
import { useTopicsStore } from '../../stores/zine/topics'
|
||||||
import { useRouter } from '../../stores/router'
|
import { useRouter } from '../../stores/router'
|
||||||
|
import Beside from '../Feed/Beside'
|
||||||
|
|
||||||
// TODO: load reactions on client
|
// TODO: load reactions on client
|
||||||
type AuthorProps = {
|
type AuthorProps = {
|
||||||
|
@ -30,6 +31,7 @@ export const AuthorView = (props: AuthorProps) => {
|
||||||
sortedArticles: props.authorArticles
|
sortedArticles: props.authorArticles
|
||||||
})
|
})
|
||||||
const { authorEntities } = useAuthorsStore({ authors: [props.author] })
|
const { authorEntities } = useAuthorsStore({ authors: [props.author] })
|
||||||
|
const { topicsByAuthor } = useTopicsStore()
|
||||||
|
|
||||||
const author = createMemo(() => authorEntities()[props.authorSlug])
|
const author = createMemo(() => authorEntities()[props.authorSlug])
|
||||||
const { getSearchParams, changeSearchParam } = useRouter<AuthorPageSearchParams>()
|
const { getSearchParams, changeSearchParam } = useRouter<AuthorPageSearchParams>()
|
||||||
|
@ -54,21 +56,22 @@ export const AuthorView = (props: AuthorProps) => {
|
||||||
{t('Recent')}
|
{t('Recent')}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li classList={{ selected: getSearchParams().by === 'rating' }}>
|
{/*TODO: server sort*/}
|
||||||
<button type="button" onClick={() => changeSearchParam('by', 'rating')}>
|
{/*<li classList={{ selected: getSearchParams().by === 'rating' }}>*/}
|
||||||
{t('Popular')}
|
{/* <button type="button" onClick={() => changeSearchParam('by', 'rating')}>*/}
|
||||||
</button>
|
{/* {t('Popular')}*/}
|
||||||
</li>
|
{/* </button>*/}
|
||||||
<li classList={{ selected: getSearchParams().by === 'viewed' }}>
|
{/*</li>*/}
|
||||||
<button type="button" onClick={() => changeSearchParam('by', 'viewed')}>
|
{/*<li classList={{ selected: getSearchParams().by === 'viewed' }}>*/}
|
||||||
{t('Views')}
|
{/* <button type="button" onClick={() => changeSearchParam('by', 'viewed')}>*/}
|
||||||
</button>
|
{/* {t('Views')}*/}
|
||||||
</li>
|
{/* </button>*/}
|
||||||
<li classList={{ selected: getSearchParams().by === 'commented' }}>
|
{/*</li>*/}
|
||||||
<button type="button" onClick={() => changeSearchParam('by', 'commented')}>
|
{/*<li classList={{ selected: getSearchParams().by === 'commented' }}>*/}
|
||||||
{t('Discussing')}
|
{/* <button type="button" onClick={() => changeSearchParam('by', 'commented')}>*/}
|
||||||
</button>
|
{/* {t('Discussing')}*/}
|
||||||
</li>
|
{/* </button>*/}
|
||||||
|
{/*</li>*/}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
|
@ -83,14 +86,13 @@ export const AuthorView = (props: AuthorProps) => {
|
||||||
<h3 class="col-12">{title()}</h3>
|
<h3 class="col-12">{title()}</h3>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<Show when={sortedArticles().length > 0}>
|
<Show when={sortedArticles().length > 0}>
|
||||||
{/*FIXME*/}
|
<Beside
|
||||||
{/*<Beside*/}
|
title={t('Topics which supported by author')}
|
||||||
{/* title={t('Topics which supported by author')}*/}
|
values={topicsByAuthor()[author().slug].slice(0, 5)}
|
||||||
{/* values={getTopicsByAuthor()[author().slug].slice(0, 5)}*/}
|
beside={sortedArticles()[0]}
|
||||||
{/* beside={articles()[0]}*/}
|
wrapper={'topic'}
|
||||||
{/* wrapper={'topic'}*/}
|
topicShortDescription={true}
|
||||||
{/* topicShortDescription={true}*/}
|
/>
|
||||||
{/*/>*/}
|
|
||||||
<Row3 articles={sortedArticles().slice(1, 4)} />
|
<Row3 articles={sortedArticles().slice(1, 4)} />
|
||||||
<Row2 articles={sortedArticles().slice(4, 6)} />
|
<Row2 articles={sortedArticles().slice(4, 6)} />
|
||||||
<Row3 articles={sortedArticles().slice(6, 9)} />
|
<Row3 articles={sortedArticles().slice(6, 9)} />
|
||||||
|
|
|
@ -32,14 +32,6 @@ export const TopicView = (props: TopicProps) => {
|
||||||
|
|
||||||
const topic = createMemo(() => topicEntities()[props.topicSlug])
|
const topic = createMemo(() => topicEntities()[props.topicSlug])
|
||||||
|
|
||||||
/*
|
|
||||||
const slug = createMemo<string>(() => {
|
|
||||||
let slug = props?.slug
|
|
||||||
if (props?.slug.startsWith('@')) slug = slug.replace('@', '')
|
|
||||||
return slug
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
|
|
||||||
const title = createMemo(() => {
|
const title = createMemo(() => {
|
||||||
const m = getSearchParams().by
|
const m = getSearchParams().by
|
||||||
if (m === 'viewed') return t('Top viewed')
|
if (m === 'viewed') return t('Top viewed')
|
||||||
|
@ -60,21 +52,22 @@ export const TopicView = (props: TopicProps) => {
|
||||||
{t('Recent')}
|
{t('Recent')}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li classList={{ selected: getSearchParams().by === 'rating' }}>
|
{/*TODO: server sort*/}
|
||||||
<button type="button" onClick={() => changeSearchParam('by', 'rating')}>
|
{/*<li classList={{ selected: getSearchParams().by === 'rating' }}>*/}
|
||||||
{t('Popular')}
|
{/* <button type="button" onClick={() => changeSearchParam('by', 'rating')}>*/}
|
||||||
</button>
|
{/* {t('Popular')}*/}
|
||||||
</li>
|
{/* </button>*/}
|
||||||
<li classList={{ selected: getSearchParams().by === 'viewed' }}>
|
{/*</li>*/}
|
||||||
<button type="button" onClick={() => changeSearchParam('by', 'viewed')}>
|
{/*<li classList={{ selected: getSearchParams().by === 'viewed' }}>*/}
|
||||||
{t('Views')}
|
{/* <button type="button" onClick={() => changeSearchParam('by', 'viewed')}>*/}
|
||||||
</button>
|
{/* {t('Views')}*/}
|
||||||
</li>
|
{/* </button>*/}
|
||||||
<li classList={{ selected: getSearchParams().by === 'commented' }}>
|
{/*</li>*/}
|
||||||
<button type="button" onClick={() => changeSearchParam('by', 'commented')}>
|
{/*<li classList={{ selected: getSearchParams().by === 'commented' }}>*/}
|
||||||
{t('Discussing')}
|
{/* <button type="button" onClick={() => changeSearchParam('by', 'commented')}>*/}
|
||||||
</button>
|
{/* {t('Discussing')}*/}
|
||||||
</li>
|
{/* </button>*/}
|
||||||
|
{/*</li>*/}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
|
@ -108,11 +101,11 @@ export const TopicView = (props: TopicProps) => {
|
||||||
beside={sortedArticles()[6]}
|
beside={sortedArticles()[6]}
|
||||||
wrapper={'author'}
|
wrapper={'author'}
|
||||||
/>
|
/>
|
||||||
<Row3 articles={sortedArticles().slice(6, 9)} />
|
<Row3 articles={sortedArticles().slice(7, 10)} />
|
||||||
<Row2 articles={sortedArticles().slice(9, 11)} />
|
<Row2 articles={sortedArticles().slice(10, 12)} />
|
||||||
<Row3 articles={sortedArticles().slice(11, 14)} />
|
<Row3 articles={sortedArticles().slice(12, 15)} />
|
||||||
<Row3 articles={sortedArticles().slice(14, 17)} />
|
<Row3 articles={sortedArticles().slice(15, 18)} />
|
||||||
<Row3 articles={sortedArticles().slice(17, 20)} />
|
<Row3 articles={sortedArticles().slice(18, 21)} />
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
|
@ -11,7 +11,7 @@ export default gql`
|
||||||
communities
|
communities
|
||||||
links
|
links
|
||||||
createdAt
|
createdAt
|
||||||
wasOnlineAt
|
lastSeen
|
||||||
ratings {
|
ratings {
|
||||||
_id: rater
|
_id: rater
|
||||||
rater
|
rater
|
||||||
|
|
|
@ -38,6 +38,7 @@ body {
|
||||||
&.fixed {
|
&.fixed {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,6 +535,7 @@ astro-island {
|
||||||
.main-content {
|
.main-content {
|
||||||
flex: 1 100%;
|
flex: 1 100%;
|
||||||
padding-top: 100px;
|
padding-top: 100px;
|
||||||
|
position: relative;
|
||||||
transition: all 1s ease;
|
transition: all 1s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user