topic selector WIP

This commit is contained in:
bniwredyc 2023-03-23 18:15:50 +01:00
parent 293e7a06e4
commit 73f9013dc0
10 changed files with 153 additions and 51 deletions

17
package-lock.json generated
View File

@ -33,6 +33,7 @@
"@solid-primitives/storage": "^1.3.7", "@solid-primitives/storage": "^1.3.7",
"@solid-primitives/upload": "^0.0.109", "@solid-primitives/upload": "^0.0.109",
"@solidjs/meta": "^0.28.2", "@solidjs/meta": "^0.28.2",
"@thisbeyond/solid-select": "^0.13.0",
"@tiptap/core": "^2.0.0-beta.220", "@tiptap/core": "^2.0.0-beta.220",
"@tiptap/extension-blockquote": "^2.0.0-beta.220", "@tiptap/extension-blockquote": "^2.0.0-beta.220",
"@tiptap/extension-bold": "^2.0.0-beta.220", "@tiptap/extension-bold": "^2.0.0-beta.220",
@ -5549,6 +5550,15 @@
"solid-js": ">=1.4.0" "solid-js": ">=1.4.0"
} }
}, },
"node_modules/@thisbeyond/solid-select": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@thisbeyond/solid-select/-/solid-select-0.13.0.tgz",
"integrity": "sha512-eION+Xf8TGLs1NZrvRo1NRKOl4plYMbY7UswHhh5bEUY8oMltjrBhUWF0hzaFViEc1zZpkCQyafaD89iofG6Tg==",
"dev": true,
"peerDependencies": {
"solid-js": "^1.5"
}
},
"node_modules/@tiptap/core": { "node_modules/@tiptap/core": {
"version": "2.0.0-beta.220", "version": "2.0.0-beta.220",
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.220.tgz", "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.220.tgz",
@ -27344,6 +27354,13 @@
"dev": true, "dev": true,
"requires": {} "requires": {}
}, },
"@thisbeyond/solid-select": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@thisbeyond/solid-select/-/solid-select-0.13.0.tgz",
"integrity": "sha512-eION+Xf8TGLs1NZrvRo1NRKOl4plYMbY7UswHhh5bEUY8oMltjrBhUWF0hzaFViEc1zZpkCQyafaD89iofG6Tg==",
"dev": true,
"requires": {}
},
"@tiptap/core": { "@tiptap/core": {
"version": "2.0.0-beta.220", "version": "2.0.0-beta.220",
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.220.tgz", "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.220.tgz",

View File

@ -53,6 +53,7 @@
"@solid-primitives/storage": "^1.3.7", "@solid-primitives/storage": "^1.3.7",
"@solid-primitives/upload": "^0.0.109", "@solid-primitives/upload": "^0.0.109",
"@solidjs/meta": "^0.28.2", "@solidjs/meta": "^0.28.2",
"@thisbeyond/solid-select": "^0.13.0",
"@tiptap/core": "^2.0.0-beta.220", "@tiptap/core": "^2.0.0-beta.220",
"@tiptap/extension-blockquote": "^2.0.0-beta.220", "@tiptap/extension-blockquote": "^2.0.0-beta.220",
"@tiptap/extension-bold": "^2.0.0-beta.220", "@tiptap/extension-bold": "^2.0.0-beta.220",

View File

@ -34,7 +34,6 @@ import { SessionProvider } from '../context/session'
import { ProfileSettingsPage } from '../pages/profile/profileSettings.page' import { ProfileSettingsPage } from '../pages/profile/profileSettings.page'
import { ProfileSecurityPage } from '../pages/profile/profileSecurity.page' import { ProfileSecurityPage } from '../pages/profile/profileSecurity.page'
import { ProfileSubscriptionsPage } from '../pages/profile/profileSubscriptions.page' import { ProfileSubscriptionsPage } from '../pages/profile/profileSubscriptions.page'
import { CreateSettingsPage } from '../pages/createSettings.page'
import { SnackbarProvider } from '../context/snackbar' import { SnackbarProvider } from '../context/snackbar'
import { LocalizeProvider } from '../context/localize' import { LocalizeProvider } from '../context/localize'
@ -46,7 +45,7 @@ const pagesMap: Record<keyof typeof ROUTES, Component<PageProps>> = {
expo: LayoutShoutsPage, expo: LayoutShoutsPage,
connect: ConnectPage, connect: ConnectPage,
create: CreatePage, create: CreatePage,
createSettings: CreateSettingsPage, createSettings: CreatePage,
home: HomePage, home: HomePage,
topics: AllTopicsPage, topics: AllTopicsPage,
topic: TopicPage, topic: TopicPage,

View File

@ -1,4 +1,4 @@
import { createTiptapEditor } from 'solid-tiptap' import { createTiptapEditor, useEditorHTML } from 'solid-tiptap'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { useLocalize } from '../../context/localize' import { useLocalize } from '../../context/localize'
import { Blockquote } from '@tiptap/extension-blockquote' import { Blockquote } from '@tiptap/extension-blockquote'
@ -35,9 +35,11 @@ import { TrailingNode } from './extensions/TrailingNode'
import './Prosemirror.scss' import './Prosemirror.scss'
import { EditorBubbleMenu } from './EditorBubbleMenu' import { EditorBubbleMenu } from './EditorBubbleMenu'
import { EditorFloatingMenu } from './EditorFloatingMenu' import { EditorFloatingMenu } from './EditorFloatingMenu'
import { createEffect } from 'solid-js'
type EditorProps = { type EditorProps = {
initialContent?: string initialContent?: string
onChange: (text: string) => void
} }
// const ydoc = new Y.Doc() // const ydoc = new Y.Doc()
@ -118,6 +120,12 @@ export const Editor = (props: EditorProps) => {
] ]
})) }))
const html = useEditorHTML(() => editor())
createEffect(() => {
props.onChange(html())
})
return ( return (
<> <>
<div ref={(el) => (editorElRef.current = el)} /> <div ref={(el) => (editorElRef.current = el)} />

View File

@ -0,0 +1,21 @@
import type { Topic } from '../../../graphql/types.gen'
import { createOptions, Select } from '@thisbeyond/solid-select'
import { useLocalize } from '../../../context/localize'
import '@thisbeyond/solid-select/style.css'
type TopicSelectProps = {
topics: Topic[]
onChange: (selectedTopics: Topic[]) => void
}
export const TopicSelect = (props: TopicSelectProps) => {
const { t } = useLocalize()
const selectProps = createOptions(props.topics, { key: 'title' })
const handleChange = (selectedTopics: Topic[]) => {
props.onChange(selectedTopics)
}
return <Select multiple={true} {...selectProps} placeholder={t('Topics')} onChange={handleChange} />
}

View File

@ -1,6 +1,6 @@
import styles from './Header.module.scss' import styles from './Header.module.scss'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { useRouter } from '../../stores/router' import { router, useRouter } from '../../stores/router'
import { Icon } from '../_shared/Icon' import { Icon } from '../_shared/Icon'
import { createSignal, Show } from 'solid-js' import { createSignal, Show } from 'solid-js'
@ -12,6 +12,7 @@ import { showModal, useWarningsStore } from '../../stores/ui'
import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient' import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient'
import { useSession } from '../../context/session' import { useSession } from '../../context/session'
import { useLocalize } from '../../context/localize' import { useLocalize } from '../../context/localize'
import { getPagePath } from '@nanostores/router'
type HeaderAuthProps = { type HeaderAuthProps = {
setIsProfilePopupVisible: (value: boolean) => void setIsProfilePopupVisible: (value: boolean) => void
@ -43,12 +44,14 @@ export const HeaderAuth = (props: HeaderAuthProps) => {
<Show when={isSessionLoaded()} keyed={true}> <Show when={isSessionLoaded()} keyed={true}>
<div class={styles.usernav}> <div class={styles.usernav}>
<div class={clsx(styles.userControl, styles.userControl, 'col')}> <div class={clsx(styles.userControl, styles.userControl, 'col')}>
<Show when={page().route !== 'create'}>
<div class={clsx(styles.userControlItem, styles.userControlItemVerbose)}> <div class={clsx(styles.userControlItem, styles.userControlItemVerbose)}>
<a href="/create"> <a href={getPagePath(router, 'create')}>
<span class={styles.textLabel}>{t('Create post')}</span> <span class={styles.textLabel}>{t('Create post')}</span>
<Icon name="pencil" class={styles.icon} /> <Icon name="pencil" class={styles.icon} />
</a> </a>
</div> </div>
</Show>
<Show when={isAuthenticated()}> <Show when={isAuthenticated()}>
<div class={styles.userControlItem}> <div class={styles.userControlItem}>

View File

@ -1,3 +0,0 @@
// aka TopicInput
export default () => <></>

View File

@ -1,42 +1,96 @@
import { lazy, Suspense } from 'solid-js' import { createSignal, lazy, onMount, Show, Suspense } from 'solid-js'
import { Loading } from '../_shared/Loading' import { Loading } from '../_shared/Loading'
import { useLocalize } from '../../context/localize' import { useLocalize } from '../../context/localize'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import styles from './Create.module.scss' import styles from './Create.module.scss'
import { Title } from '@solidjs/meta' import { Title } from '@solidjs/meta'
import { createStore } from 'solid-js/store'
import type { ShoutInput, Topic } from '../../graphql/types.gen'
import { apiClient } from '../../utils/apiClient'
import { TopicSelect } from '../Editor/TopicSelect/TopicSelect'
const Editor = lazy(() => import('../Editor/Editor')) const Editor = lazy(() => import('../Editor/Editor'))
type ShoutForm = {
slug: string
title: string
subtitle: string
topicSlugs: string[]
body: string
coverImageUrl: string
}
export const CreateView = () => { export const CreateView = () => {
const { t } = useLocalize() const { t } = useLocalize()
const [topics, setTopics] = createSignal<Topic[]>(null)
const [form, setForm] = createStore<ShoutForm>({
slug: '',
title: '',
subtitle: '',
topicSlugs: [],
body: '',
coverImageUrl: ''
})
onMount(async () => {
const allTopics = await apiClient.getAllTopics()
setTopics(allTopics)
})
const handleFormSubmit = (e) => {
e.preventDefault()
}
return ( return (
<> <>
<Title>{t('Write an article')}</Title> <Title>{t('Write an article')}</Title>
<Suspense fallback={<Loading />}> <Suspense fallback={<Loading />}>
<form> <form onSubmit={handleFormSubmit}>
<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-10 col-lg-9 col-xl-8"> <div class="col-md-10 col-lg-9 col-xl-8">
<h4>Slug</h4>
<div class="pretty-form__item">
<input
type="text"
name="slug"
id="slug"
value={form.slug}
onChange={(e) => setForm('slug', e.currentTarget.value)}
/>
<label for="slug">Slug</label>
</div>
<h4>Заголовок</h4> <h4>Заголовок</h4>
<div class="pretty-form__item"> <div class="pretty-form__item">
<input <input
type="text" type="text"
name="header" name="title"
id="header" id="title"
placeholder="Придумайте заголовок вашей истории" placeholder="Придумайте заголовок вашей истории"
value={form.title}
onChange={(e) => setForm('title', e.currentTarget.value)}
/> />
<label for="header">Придумайте заголовок вашей истории</label> <label for="title">Придумайте заголовок вашей истории</label>
</div> </div>
<h4>Подзаголовок</h4> <h4>Подзаголовок</h4>
<div class="pretty-form__item"> <div class="pretty-form__item">
<input type="text" name="subheader" id="subheader" placeholder="Подзаголовок" /> <input
<label for="subheader">Подзаголовок</label> type="text"
name="subtitle"
id="subtitle"
placeholder="Подзаголовок"
value={form.subtitle}
onChange={(e) => setForm('subtitle', e.currentTarget.value)}
/>
<label for="subtitle">Подзаголовок</label>
</div> </div>
<Editor /> <Editor onChange={(body) => setForm('body', body)} />
<h1>Настройки публикации</h1> <h1>Настройки публикации</h1>
{/*<h4>Лид</h4>*/} {/*<h4>Лид</h4>*/}
@ -58,31 +112,38 @@ export const CreateView = () => {
{/*</div>*/} {/*</div>*/}
<h4>Темы</h4> <h4>Темы</h4>
<p class="description"> {/*<p class="description">*/}
Добавьте несколько тем, чтобы читатель знал, о&nbsp;чем ваш материал, и&nbsp;мог найти {/* Добавьте несколько тем, чтобы читатель знал, о&nbsp;чем ваш материал, и&nbsp;мог найти*/}
его на&nbsp;страницах интересных ему тем. Темы можно менять местами, первая тема {/* его на&nbsp;страницах интересных ему тем. Темы можно менять местами, первая тема*/}
становится заглавной {/* становится заглавной*/}
</p> {/*</p>*/}
<div class="pretty-form__item"> <div class="pretty-form__item">
<input type="text" name="topics" id="topics" placeholder="Темы" class="nolabel" /> <Show when={topics()}>
<TopicSelect
topics={topics()}
onChange={(selectedTopicSlugs) => setForm('topicSlugs', selectedTopics)}
selectedTopicSlugs={form.topicSlugs}
/>
</Show>
{/*<input type="text" name="topics" id="topics" placeholder="Темы" class="nolabel" />*/}
</div> </div>
<h4>Соавторы</h4> {/*<h4>Соавторы</h4>*/}
<p class="description">У каждого соавтора можно добавить роль</p> {/*<p class="description">У каждого соавтора можно добавить роль</p>*/}
<div class="pretty-form__item--with-button"> {/*<div class="pretty-form__item--with-button">*/}
<div class="pretty-form__item"> {/* <div class="pretty-form__item">*/}
<input type="text" name="authors" id="authors" placeholder="Введите имя или e-mail" /> {/* <input type="text" name="authors" id="authors" placeholder="Введите имя или e-mail" />*/}
<label for="authors">Введите имя или e-mail</label> {/* <label for="authors">Введите имя или e-mail</label>*/}
</div> {/* </div>*/}
<button class="button button--submit">Добавить</button> {/* <button class="button button--submit">Добавить</button>*/}
</div> {/*</div>*/}
<div class="row"> {/*<div class="row">*/}
<div class="col-md-6">Михаил Драбкин</div> {/* <div class="col-md-6">Михаил Драбкин</div>*/}
<div class="col-md-6"> {/* <div class="col-md-6">*/}
<input type="text" name="coauthor" id="coauthor1" class="nolabel" /> {/* <input type="text" name="coauthor" id="coauthor1" class="nolabel" />*/}
</div> {/* </div>*/}
</div> {/*</div>*/}
<h4>Карточка материала на&nbsp;главной</h4> <h4>Карточка материала на&nbsp;главной</h4>
<p class="description"> <p class="description">
@ -96,8 +157,10 @@ export const CreateView = () => {
Проверьте ещё раз введённые данные, если всё верно, вы&nbsp;можете сохранить или Проверьте ещё раз введённые данные, если всё верно, вы&nbsp;можете сохранить или
опубликовать ваш текст опубликовать ваш текст
</p> </p>
<button class={clsx('button button--outline', styles.button)}>Сохранить</button> {/*<button class={clsx('button button--outline', styles.button)}>Сохранить</button>*/}
<button class={clsx('button button--submit', styles.button)}>Опубликовать</button> <button type="submit" class={clsx('button button--submit', styles.button)}>
Опубликовать
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,7 +0,0 @@
import { PageLayout } from '../components/_shared/PageLayout'
export const CreateSettingsPage = () => {
return <PageLayout>Настройки публикации</PageLayout>
}
export const Page = CreateSettingsPage