diff --git a/src/components/AuthModal/index.tsx b/src/components/AuthModal/index.tsx index b0b118c1..51208374 100644 --- a/src/components/AuthModal/index.tsx +++ b/src/components/AuthModal/index.tsx @@ -3,7 +3,7 @@ import { Component, Show, createEffect, createMemo } from 'solid-js' import { Dynamic } from 'solid-js/web' import { useLocalize } from '~/context/localize' -import { AuthModalSource, useUI } from '~/context/ui' +import { ModalSource, useUI } from '~/context/ui' import { isMobile } from '~/lib/mediaQuery' import { ChangePasswordForm } from './ChangePasswordForm' import { EmailConfirm } from './EmailConfirm' @@ -25,7 +25,7 @@ export type AuthModalMode = export type AuthModalSearchParams = { mode: AuthModalMode - source?: AuthModalSource + source?: ModalSource token?: string } diff --git a/src/components/Draft/Draft.module.scss b/src/components/Draft/Draft.module.scss index 52b0804e..51ddd0fe 100644 --- a/src/components/Draft/Draft.module.scss +++ b/src/components/Draft/Draft.module.scss @@ -1,3 +1,7 @@ +.draft { + margin-bottom: 56px; +} + .created { @include font-size(1.2rem); diff --git a/src/components/Draft/Draft.tsx b/src/components/Draft/Draft.tsx index 1821dfaf..c1a3262f 100644 --- a/src/components/Draft/Draft.tsx +++ b/src/components/Draft/Draft.tsx @@ -1,15 +1,13 @@ +import { A } from '@solidjs/router' import { clsx } from 'clsx' - import { useLocalize } from '~/context/localize' import { useSnackbar, useUI } from '~/context/ui' import type { Shout } from '~/graphql/schema/core.gen' import { Icon } from '../_shared/Icon' -import { A } from '@solidjs/router' import styles from './Draft.module.scss' type Props = { - class?: string shout: Shout onPublish: (shout: Shout) => void onDelete: (shout: Shout) => void @@ -46,7 +44,7 @@ export const Draft = (props: Props) => { } return ( -
+
{' '} {formatDate(new Date(props.shout.created_at * 1000), { hour: '2-digit', minute: '2-digit' })} diff --git a/src/styles/Create.module.scss b/src/components/Draft/LayoutSelector.module.scss similarity index 100% rename from src/styles/Create.module.scss rename to src/components/Draft/LayoutSelector.module.scss diff --git a/src/components/Draft/LayoutSelector.tsx b/src/components/Draft/LayoutSelector.tsx new file mode 100644 index 00000000..1a8959ef --- /dev/null +++ b/src/components/Draft/LayoutSelector.tsx @@ -0,0 +1,67 @@ +import { useNavigate } from '@solidjs/router' +import clsx from 'clsx' +import { For } from 'solid-js' +import { useEditorContext } from '~/context/editor' +import { useLocalize } from '~/context/localize' +import { useSession } from '~/context/session' +import { useSnackbar } from '~/context/ui' +import createShoutMutation from '~/graphql/mutation/core/article-create' +import { LayoutType } from '~/types/common' +import { Button } from '../_shared/Button' +import { Icon } from '../_shared/Icon' + +import styles from './LayoutSelector.module.scss' + +export const LayoutSelector = () => { + const { t } = useLocalize() + const { client } = useSession() + const { saveDraftToLocalStorage } = useEditorContext() + const { showSnackbar } = useSnackbar() + const navigate = useNavigate() + + const handleCreate = async (layout: LayoutType) => { + console.debug('[routes : edit/new] handling create click...') + const result = await client() + ?.mutation(createShoutMutation, { shout: { layout: layout } }) + .toPromise() + if (result) { + console.debug(result) + const { shout, error } = result.data.create_shout + if (error) { + showSnackbar({ + body: `${t('Error')}: ${t(error)}`, + type: 'error' + }) + return + } + if (shout?.id) { + saveDraftToLocalStorage({ + shoutId: shout.id, + selectedTopics: shout.topics, + slug: shout.slug, + title: '', + body: '' + }) + navigate(`/edit/${shout.id}`) + } + } + } + return ( +
+

{t('Choose a post type')}

+
    + + {(layout: string) => ( +
  • handleCreate(layout.toLowerCase() as LayoutType)}> +
    + +
    {t(layout)}
    +
    +
  • + )} +
    +
+
+ ) +} diff --git a/src/components/Editor/Toolbar/EditorFloatingMenu.tsx b/src/components/Editor/Toolbar/EditorFloatingMenu.tsx index b2a2876a..61a468c7 100644 --- a/src/components/Editor/Toolbar/EditorFloatingMenu.tsx +++ b/src/components/Editor/Toolbar/EditorFloatingMenu.tsx @@ -12,7 +12,7 @@ import { Modal } from '../../_shared/Modal' import { Menu } from './Menu' import type { MenuItem } from './Menu/Menu' -import styles from './EditorFloatingMenu.module.scss' +import styles from '../EditorFloatingMenu/EditorFloatingMenu.module.scss' type FloatingMenuProps = { editor: Editor diff --git a/src/components/Views/Home.module.scss b/src/components/Feed/RandomTopicSwiper.module.scss similarity index 100% rename from src/components/Views/Home.module.scss rename to src/components/Feed/RandomTopicSwiper.module.scss diff --git a/src/components/Feed/RandomTopicSwiper.tsx b/src/components/Feed/RandomTopicSwiper.tsx new file mode 100644 index 00000000..b9c0fef0 --- /dev/null +++ b/src/components/Feed/RandomTopicSwiper.tsx @@ -0,0 +1,54 @@ +import { Show, createEffect, createSignal, on } from 'solid-js' +import { useAuthors } from '~/context/authors' +import { useLocalize } from '~/context/localize' +import { useTopics } from '~/context/topics' +import { loadShouts } from '~/graphql/api/public' +import { Author, Shout, Topic } from '~/graphql/schema/core.gen' +import { capitalize } from '~/utils/capitalize' +import { Icon } from '../_shared/Icon' +import Group from './Group' + +import styles from './RandomTopicSwiper.module.scss' + +export const RandomTopicSwiper = () => { + const { t } = useLocalize() + const { randomTopic } = useTopics() + const { addAuthors } = useAuthors() + const [randomTopicArticles, setRandomTopicArticles] = createSignal([]) + + createEffect( + on( + () => randomTopic(), // NOTE: triggs once + async (topic?: Topic) => { + if (topic) { + const shoutsByTopicLoader = loadShouts({ + filters: { topic: topic.slug, featured: true }, + limit: 5, + offset: 0 + }) + const shouts = await shoutsByTopicLoader() + setRandomTopicArticles(shouts || []) + shouts?.forEach((s: Shout) => addAuthors((s?.authors || []) as Author[])) + } + }, + { defer: true } + ) + ) + return ( + + +
{capitalize(randomTopic()?.title || '', true)}
+ +
+ } + /> + + ) +} diff --git a/src/components/HeaderNav/Header.tsx b/src/components/HeaderNav/Header.tsx index a43584fa..a2619c2a 100644 --- a/src/components/HeaderNav/Header.tsx +++ b/src/components/HeaderNav/Header.tsx @@ -8,7 +8,6 @@ import { SharePopup, getShareUrl } from '../Article/SharePopup' import { AuthModal } from '../AuthModal' import { SearchModal } from '../SearchModal/SearchModal' import { Snackbar } from '../Snackbar/Snackbar' -import { RandomTopics } from '../TopicsNav/TopicsNav' import { ConfirmModal } from '../_shared/ConfirmModal' import { Icon } from '../_shared/Icon' import { Modal } from '../_shared/Modal' @@ -16,6 +15,7 @@ import { Newsletter } from '../_shared/Newsletter' import styles from './Header.module.scss' import { HeaderAuth } from './HeaderAuth' import { Link } from './HeaderLink' +import { RandomTopics } from './TopicsNav' type Props = { title?: string diff --git a/src/components/TopicsNav/TopicsNav.module.scss b/src/components/HeaderNav/TopicsNav.module.scss similarity index 100% rename from src/components/TopicsNav/TopicsNav.module.scss rename to src/components/HeaderNav/TopicsNav.module.scss diff --git a/src/components/TopicsNav/TopicsNav.tsx b/src/components/HeaderNav/TopicsNav.tsx similarity index 99% rename from src/components/TopicsNav/TopicsNav.tsx rename to src/components/HeaderNav/TopicsNav.tsx index ac8b0a3f..5ca0fc29 100644 --- a/src/components/TopicsNav/TopicsNav.tsx +++ b/src/components/HeaderNav/TopicsNav.tsx @@ -7,6 +7,7 @@ import { useTopics } from '~/context/topics' import type { Topic } from '~/graphql/schema/core.gen' import { notLatin } from '~/intl/chars' import { getRandomItemsFromArray } from '~/utils/random' + import styles from './TopicsNav.module.scss' export const RandomTopics = () => { diff --git a/src/components/TopicsNav/index.ts b/src/components/TopicsNav/index.ts deleted file mode 100644 index 37653d78..00000000 --- a/src/components/TopicsNav/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { TopicsNav } from './TopicsNav' diff --git a/src/components/Views/DraftsView/DraftsView.tsx b/src/components/Views/DraftsView.tsx similarity index 56% rename from src/components/Views/DraftsView/DraftsView.tsx rename to src/components/Views/DraftsView.tsx index c2de14a2..1d49753e 100644 --- a/src/components/Views/DraftsView/DraftsView.tsx +++ b/src/components/Views/DraftsView.tsx @@ -1,16 +1,26 @@ import { useNavigate } from '@solidjs/router' -import { clsx } from 'clsx' -import { For, Show, createSignal } from 'solid-js' +import { Client } from '@urql/core' +import { For, Show, createEffect, createSignal, on, onMount } from 'solid-js' import { Draft } from '~/components/Draft' import { useEditorContext } from '~/context/editor' import { useLocalize } from '~/context/localize' +import { useSession } from '~/context/session' +import getDraftsQuery from '~/graphql/query/core/articles-load-drafts' import { Shout } from '~/graphql/schema/core.gen' -import styles from './DraftsView.module.scss' -export const DraftsView = (props: { drafts: Shout[] }) => { - const [drafts, setDrafts] = createSignal(props.drafts || []) +const fetchDrafts = async (client: Client) => { + const resp = await client?.query(getDraftsQuery, {}).toPromise() + const result = resp?.data?.get_shouts_drafts || [] + if (resp.error || result.error) console.error(resp.error || result.error) + return result.shouts as Shout[] +} + +export const DraftsView = (props: { drafts?: Shout[] }) => { + const { client, requireAuthentication} = useSession() const navigate = useNavigate() const { publishShoutById, deleteShout } = useEditorContext() + const [drafts, setDrafts] = createSignal(props.drafts || []) + const handleDraftDelete = async (shout: Shout) => { const success = await deleteShout(shout.id) if (success) { @@ -23,10 +33,20 @@ export const DraftsView = (props: { drafts: Shout[] }) => { setTimeout(() => navigate('/feed'), 2000) } + onMount(() => { + requireAuthentication(async () => { + const result = await fetchDrafts(client() as Client) + console.debug('fetchDrafts result: ', result) + if (result) { + setDrafts(result as Shout[]) + } + }, 'edit') + }) + const { t } = useLocalize() return ( -
+

{t('Drafts')}

@@ -37,12 +57,7 @@ export const DraftsView = (props: { drafts: Shout[] }) => {
{(draft) => ( - + )}
diff --git a/src/components/Views/DraftsView/DraftsView.module.scss b/src/components/Views/DraftsView/DraftsView.module.scss deleted file mode 100644 index b5b71e12..00000000 --- a/src/components/Views/DraftsView/DraftsView.module.scss +++ /dev/null @@ -1,7 +0,0 @@ -.DraftsView { - display: block; -} - -.draft { - margin-bottom: 56px; -} diff --git a/src/components/Views/DraftsView/index.ts b/src/components/Views/DraftsView/index.ts deleted file mode 100644 index c4d5dd40..00000000 --- a/src/components/Views/DraftsView/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { DraftsView } from './DraftsView' diff --git a/src/components/Views/Home.tsx b/src/components/Views/Home.tsx index e0b98bb8..a3d3ee77 100644 --- a/src/components/Views/Home.tsx +++ b/src/components/Views/Home.tsx @@ -1,25 +1,21 @@ -import { For, Show, createEffect, createMemo, createSignal, on } from 'solid-js' +import { For, Show, createMemo, onMount } from 'solid-js' import { useAuthors } from '~/context/authors' import { SHOUTS_PER_PAGE } from '~/context/feed' import { useLocalize } from '~/context/localize' import { useTopics } from '~/context/topics' -import { loadShouts } from '~/graphql/api/public' import { Author, Shout, Topic } from '~/graphql/schema/core.gen' -import { capitalize } from '~/utils/capitalize' import { paginate } from '~/utils/paginate' import Banner from '../Discours/Banner' import Hero from '../Discours/Hero' import { Beside } from '../Feed/Beside' -import Group from '../Feed/Group' +import { RandomTopicSwiper } from '../Feed/RandomTopicSwiper' import { Row1 } from '../Feed/Row1' import { Row2 } from '../Feed/Row2' import { Row3 } from '../Feed/Row3' import { Row5 } from '../Feed/Row5' import RowShort from '../Feed/RowShort' -import { TopicsNav } from '../TopicsNav' -import { Icon } from '../_shared/Icon' +import { TopicsNav } from '../HeaderNav/TopicsNav' import { ArticleCardSwiper } from '../_shared/SolidSwiper/ArticleCardSwiper' -import styles from './Home.module.scss' export const RANDOM_TOPICS_COUNT = 12 export const RANDOM_TOPIC_SHOUTS_COUNT = 7 @@ -38,28 +34,11 @@ export interface HomeViewProps { export const HomeView = (props: HomeViewProps) => { const { t } = useLocalize() const { topAuthors, addAuthors } = useAuthors() - const { topTopics, randomTopic } = useTopics() - const [randomTopicArticles, setRandomTopicArticles] = createSignal([]) - createEffect( - on( - () => randomTopic(), - async (topic?: Topic) => { - if (topic) { - const shoutsByTopicLoader = loadShouts({ - filters: { topic: topic.slug, featured: true }, - limit: 5, - offset: 0 - }) - const shouts = await shoutsByTopicLoader() - setRandomTopicArticles(shouts || []) - shouts?.forEach((s: Shout) => addAuthors((s?.authors || []) as Author[])) - props.featuredShouts?.forEach((s: Shout) => addAuthors((s?.authors || []) as Author[])) - props.topRatedShouts?.forEach((s: Shout) => addAuthors((s?.authors || []) as Author[])) - } - }, - { defer: true } - ) - ) + const { topTopics } = useTopics() + onMount(() => { + props.featuredShouts?.forEach((s: Shout) => addAuthors((s?.authors || []) as Author[])) + props.topRatedShouts?.forEach((s: Shout) => addAuthors((s?.authors || []) as Author[])) + }) const pages = createMemo(() => paginate(props.featuredShouts || [], SHOUTS_PER_PAGE + CLIENT_LOAD_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE) @@ -99,21 +78,8 @@ export const HomeView = (props: HomeViewProps) => { header={

{t('Top commented')}

} nodate={true} /> - - -
{capitalize(randomTopic()?.title || '', true)}
- -
- } - /> - + + diff --git a/src/components/Views/PublishSettings/PublishSettings.tsx b/src/components/Views/PublishSettings/PublishSettings.tsx index 9eec9b41..8660db83 100644 --- a/src/components/Views/PublishSettings/PublishSettings.tsx +++ b/src/components/Views/PublishSettings/PublishSettings.tsx @@ -2,6 +2,7 @@ import { useNavigate } from '@solidjs/router' import { clsx } from 'clsx' import { Show, createEffect, createSignal, lazy, onMount } from 'solid-js' import { createStore } from 'solid-js/store' +import { UploadModalContent } from '~/components/Upload/UploadModalContent/UploadModalContent' import { Button } from '~/components/_shared/Button' import { Icon } from '~/components/_shared/Icon' import { Image } from '~/components/_shared/Image' @@ -13,9 +14,8 @@ import { useSnackbar, useUI } from '~/context/ui' import { Topic } from '~/graphql/schema/core.gen' import { UploadedFile } from '~/types/upload' import { Modal } from '../../_shared/Modal' +import { TopicSelect } from './TopicSelect' -import { TopicSelect } from '~/components/TopicSelect/TopicSelect' -import { UploadModalContent } from '~/components/Upload/UploadModalContent/UploadModalContent' import stylesBeside from '../../Feed/Beside.module.scss' import styles from './PublishSettings.module.scss' diff --git a/src/components/TopicSelect/TopicSelect.module.scss b/src/components/Views/PublishSettings/TopicSelect/TopicSelect.module.scss similarity index 100% rename from src/components/TopicSelect/TopicSelect.module.scss rename to src/components/Views/PublishSettings/TopicSelect/TopicSelect.module.scss diff --git a/src/components/TopicSelect/TopicSelect.tsx b/src/components/Views/PublishSettings/TopicSelect/TopicSelect.tsx similarity index 100% rename from src/components/TopicSelect/TopicSelect.tsx rename to src/components/Views/PublishSettings/TopicSelect/TopicSelect.tsx diff --git a/src/components/TopicSelect/index.ts b/src/components/Views/PublishSettings/TopicSelect/index.ts similarity index 100% rename from src/components/TopicSelect/index.ts rename to src/components/Views/PublishSettings/TopicSelect/index.ts diff --git a/src/context/session.tsx b/src/context/session.tsx index a4f58ba3..7d29c2f0 100644 --- a/src/context/session.tsx +++ b/src/context/session.tsx @@ -25,7 +25,7 @@ import { onMount, useContext } from 'solid-js' -import { type AuthModalSource, useSnackbar, useUI } from '~/context/ui' +import { type ModalSource, useSnackbar, useUI } from '~/context/ui' import { graphqlClientCreate } from '~/graphql/client' import { authApiUrl, authorizerClientId, authorizerRedirectUrl, coreApiUrl } from '../config' import { useLocalize } from './localize' @@ -45,7 +45,7 @@ export type SessionContextType = { setSession: (token: AuthToken) => void requireAuthentication: ( callback: (() => Promise) | (() => void), - modalSource: AuthModalSource + modalSource: ModalSource ) => void signUp: (params: SignupInput) => Promise signIn: (params: LoginInput) => Promise @@ -265,7 +265,7 @@ export const SessionProvider = (props: { * @param callback - The function to execute after authentication. * @param modalSource - The source of the authentication modal. */ - const requireAuthentication = (callback: () => void, modalSource: AuthModalSource) => { + const requireAuthentication = (callback: () => void, modalSource: ModalSource) => { setAuthCallback(() => callback) if (!session()) { loadSession() diff --git a/src/context/ui.tsx b/src/context/ui.tsx index f3114032..b43e4bc1 100644 --- a/src/context/ui.tsx +++ b/src/context/ui.tsx @@ -70,7 +70,7 @@ export const SnackbarProvider = (props: { children: JSX.Element }) => { return {props.children} } -export type AuthModalSource = +export type ModalSource = | 'discussions' | 'vote' | 'subscribe' @@ -78,6 +78,7 @@ export type AuthModalSource = | 'follow' | 'create' | 'authguard' + | 'edit' export type ModalType = | 'auth' @@ -128,7 +129,7 @@ type ConfirmMessage = { type UIContextType = { modal: Accessor - showModal: (m: ModalType, source?: AuthModalSource) => void + showModal: (m: ModalType, source?: ModalSource) => void hideModal: () => void confirmMessage: Accessor showConfirm: (message?: ConfirmMessage) => Promise @@ -163,7 +164,7 @@ export const UIProvider = (props: { children: JSX.Element }) => { hideModal() } - const showModal = (modalType: ModalType, modalSource?: AuthModalSource) => { + const showModal = (modalType: ModalType, modalSource?: ModalSource) => { // console.log('[context.ui] showModal()', modalType) if (modalSource) { setSearchParams({ source: modalSource }) diff --git a/src/routes/edit/(drafts).tsx b/src/routes/edit/(drafts).tsx index 919f04f0..0ddd5f9e 100644 --- a/src/routes/edit/(drafts).tsx +++ b/src/routes/edit/(drafts).tsx @@ -1,28 +1,15 @@ -import { createAsync } from '@solidjs/router' -import { Client } from '@urql/core' import { AuthGuard } from '~/components/AuthGuard' import { DraftsView } from '~/components/Views/DraftsView' import { PageLayout } from '~/components/_shared/PageLayout' import { useLocalize } from '~/context/localize' -import { useSession } from '~/context/session' -import getDraftsQuery from '~/graphql/query/core/articles-load-drafts' -import { Shout } from '~/graphql/schema/core.gen' - -const fetchDrafts = async (client: Client) => { - const resp = await client?.query(getDraftsQuery, {}).toPromise() - const result = resp?.data?.load_drafts || [] - return result as Shout[] -} export default () => { const { t } = useLocalize() - const { client } = useSession() - const drafts = createAsync(async () => client() && (await fetchDrafts(client() as Client))) return ( - + ) diff --git a/src/routes/edit/new.tsx b/src/routes/edit/new.tsx index 28d24947..11fd0ee0 100644 --- a/src/routes/edit/new.tsx +++ b/src/routes/edit/new.tsx @@ -1,53 +1,10 @@ -import { useNavigate } from '@solidjs/router' -import { clsx } from 'clsx' -import { For } from 'solid-js' import { AuthGuard } from '~/components/AuthGuard' -import { Button } from '~/components/_shared/Button' -import { Icon } from '~/components/_shared/Icon' +import { LayoutSelector } from '~/components/Draft/LayoutSelector' import { PageLayout } from '~/components/_shared/PageLayout' -import { useEditorContext } from '~/context/editor' import { useLocalize } from '~/context/localize' -import { useSession } from '~/context/session' -import { useSnackbar } from '~/context/ui' -import createShoutMutation from '~/graphql/mutation/core/article-create' -import { LayoutType } from '~/types/common' - -import styles from '~/styles/Create.module.scss' export default () => { const { t } = useLocalize() - const { client } = useSession() - const { saveDraftToLocalStorage } = useEditorContext() - - const { showSnackbar } = useSnackbar() - const navigate = useNavigate() - const handleCreate = async (layout: LayoutType) => { - console.debug('[routes : edit/new] handling create click...') - const result = await client() - ?.mutation(createShoutMutation, { shout: { layout: layout } }) - .toPromise() - if (result) { - console.debug(result) - const { shout, error } = result.data.create_shout - if (error) { - showSnackbar({ - body: `${t('Error')}: ${t(error)}`, - type: 'error' - }) - return - } - if (shout?.id) { - saveDraftToLocalStorage({ - shoutId: shout.id, - selectedTopics: shout.topics, - slug: shout.slug, - title: '', - body: '' - }) - navigate(`/edit/${shout.id}`) - } - } - } return ( { desc={t('Participate in the Discours: share information, join the editorial team')} > -
-

{t('Choose a post type')}

-
    - - {(layout: string) => ( -
  • handleCreate(layout.toLowerCase() as LayoutType)}> -
    - -
    {t(layout)}
    -
    -
  • - )} -
    -
-
+
) diff --git a/src/routes/expo/[...layout].tsx b/src/routes/expo/[...layout].tsx index f0410caf..d72d3dfc 100644 --- a/src/routes/expo/[...layout].tsx +++ b/src/routes/expo/[...layout].tsx @@ -1,6 +1,6 @@ import { Params, RouteSectionProps, createAsync } from '@solidjs/router' import { Show, createEffect, createSignal, on } from 'solid-js' -import { TopicsNav } from '~/components/TopicsNav' +import { TopicsNav } from '~/components/HeaderNav/TopicsNav' import { Expo } from '~/components/Views/Expo' import ExpoNav from '~/components/Views/Expo/ExpoNav' import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper' diff --git a/src/components/Views/Create.module.scss b/src/styles/Home.module.scss similarity index 100% rename from src/components/Views/Create.module.scss rename to src/styles/Home.module.scss