topic selector WIP
This commit is contained in:
parent
293e7a06e4
commit
73f9013dc0
17
package-lock.json
generated
17
package-lock.json
generated
|
@ -33,6 +33,7 @@
|
|||
"@solid-primitives/storage": "^1.3.7",
|
||||
"@solid-primitives/upload": "^0.0.109",
|
||||
"@solidjs/meta": "^0.28.2",
|
||||
"@thisbeyond/solid-select": "^0.13.0",
|
||||
"@tiptap/core": "^2.0.0-beta.220",
|
||||
"@tiptap/extension-blockquote": "^2.0.0-beta.220",
|
||||
"@tiptap/extension-bold": "^2.0.0-beta.220",
|
||||
|
@ -5549,6 +5550,15 @@
|
|||
"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": {
|
||||
"version": "2.0.0-beta.220",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.220.tgz",
|
||||
|
@ -27344,6 +27354,13 @@
|
|||
"dev": true,
|
||||
"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": {
|
||||
"version": "2.0.0-beta.220",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.220.tgz",
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
"@solid-primitives/storage": "^1.3.7",
|
||||
"@solid-primitives/upload": "^0.0.109",
|
||||
"@solidjs/meta": "^0.28.2",
|
||||
"@thisbeyond/solid-select": "^0.13.0",
|
||||
"@tiptap/core": "^2.0.0-beta.220",
|
||||
"@tiptap/extension-blockquote": "^2.0.0-beta.220",
|
||||
"@tiptap/extension-bold": "^2.0.0-beta.220",
|
||||
|
|
|
@ -34,7 +34,6 @@ import { SessionProvider } from '../context/session'
|
|||
import { ProfileSettingsPage } from '../pages/profile/profileSettings.page'
|
||||
import { ProfileSecurityPage } from '../pages/profile/profileSecurity.page'
|
||||
import { ProfileSubscriptionsPage } from '../pages/profile/profileSubscriptions.page'
|
||||
import { CreateSettingsPage } from '../pages/createSettings.page'
|
||||
import { SnackbarProvider } from '../context/snackbar'
|
||||
import { LocalizeProvider } from '../context/localize'
|
||||
|
||||
|
@ -46,7 +45,7 @@ const pagesMap: Record<keyof typeof ROUTES, Component<PageProps>> = {
|
|||
expo: LayoutShoutsPage,
|
||||
connect: ConnectPage,
|
||||
create: CreatePage,
|
||||
createSettings: CreateSettingsPage,
|
||||
createSettings: CreatePage,
|
||||
home: HomePage,
|
||||
topics: AllTopicsPage,
|
||||
topic: TopicPage,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { createTiptapEditor } from 'solid-tiptap'
|
||||
import { createTiptapEditor, useEditorHTML } from 'solid-tiptap'
|
||||
import { clsx } from 'clsx'
|
||||
import { useLocalize } from '../../context/localize'
|
||||
import { Blockquote } from '@tiptap/extension-blockquote'
|
||||
|
@ -35,9 +35,11 @@ import { TrailingNode } from './extensions/TrailingNode'
|
|||
import './Prosemirror.scss'
|
||||
import { EditorBubbleMenu } from './EditorBubbleMenu'
|
||||
import { EditorFloatingMenu } from './EditorFloatingMenu'
|
||||
import { createEffect } from 'solid-js'
|
||||
|
||||
type EditorProps = {
|
||||
initialContent?: string
|
||||
onChange: (text: string) => void
|
||||
}
|
||||
|
||||
// const ydoc = new Y.Doc()
|
||||
|
@ -118,6 +120,12 @@ export const Editor = (props: EditorProps) => {
|
|||
]
|
||||
}))
|
||||
|
||||
const html = useEditorHTML(() => editor())
|
||||
|
||||
createEffect(() => {
|
||||
props.onChange(html())
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<div ref={(el) => (editorElRef.current = el)} />
|
||||
|
|
21
src/components/Editor/TopicSelect/TopicSelect.tsx
Normal file
21
src/components/Editor/TopicSelect/TopicSelect.tsx
Normal 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} />
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import styles from './Header.module.scss'
|
||||
import { clsx } from 'clsx'
|
||||
import { useRouter } from '../../stores/router'
|
||||
import { router, useRouter } from '../../stores/router'
|
||||
|
||||
import { Icon } from '../_shared/Icon'
|
||||
import { createSignal, Show } from 'solid-js'
|
||||
|
@ -12,6 +12,7 @@ import { showModal, useWarningsStore } from '../../stores/ui'
|
|||
import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient'
|
||||
import { useSession } from '../../context/session'
|
||||
import { useLocalize } from '../../context/localize'
|
||||
import { getPagePath } from '@nanostores/router'
|
||||
|
||||
type HeaderAuthProps = {
|
||||
setIsProfilePopupVisible: (value: boolean) => void
|
||||
|
@ -43,12 +44,14 @@ export const HeaderAuth = (props: HeaderAuthProps) => {
|
|||
<Show when={isSessionLoaded()} keyed={true}>
|
||||
<div class={styles.usernav}>
|
||||
<div class={clsx(styles.userControl, styles.userControl, 'col')}>
|
||||
<div class={clsx(styles.userControlItem, styles.userControlItemVerbose)}>
|
||||
<a href="/create">
|
||||
<span class={styles.textLabel}>{t('Create post')}</span>
|
||||
<Icon name="pencil" class={styles.icon} />
|
||||
</a>
|
||||
</div>
|
||||
<Show when={page().route !== 'create'}>
|
||||
<div class={clsx(styles.userControlItem, styles.userControlItemVerbose)}>
|
||||
<a href={getPagePath(router, 'create')}>
|
||||
<span class={styles.textLabel}>{t('Create post')}</span>
|
||||
<Icon name="pencil" class={styles.icon} />
|
||||
</a>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<Show when={isAuthenticated()}>
|
||||
<div class={styles.userControlItem}>
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
// aka TopicInput
|
||||
|
||||
export default () => <></>
|
|
@ -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 { useLocalize } from '../../context/localize'
|
||||
import { clsx } from 'clsx'
|
||||
import styles from './Create.module.scss'
|
||||
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'))
|
||||
|
||||
type ShoutForm = {
|
||||
slug: string
|
||||
title: string
|
||||
subtitle: string
|
||||
topicSlugs: string[]
|
||||
body: string
|
||||
coverImageUrl: string
|
||||
}
|
||||
|
||||
export const CreateView = () => {
|
||||
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 (
|
||||
<>
|
||||
<Title>{t('Write an article')}</Title>
|
||||
<Suspense fallback={<Loading />}>
|
||||
<form>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<div class="wide-container">
|
||||
<div class="shift-content">
|
||||
<div class="row">
|
||||
<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>
|
||||
<div class="pretty-form__item">
|
||||
<input
|
||||
type="text"
|
||||
name="header"
|
||||
id="header"
|
||||
name="title"
|
||||
id="title"
|
||||
placeholder="Придумайте заголовок вашей истории"
|
||||
value={form.title}
|
||||
onChange={(e) => setForm('title', e.currentTarget.value)}
|
||||
/>
|
||||
<label for="header">Придумайте заголовок вашей истории</label>
|
||||
<label for="title">Придумайте заголовок вашей истории</label>
|
||||
</div>
|
||||
|
||||
<h4>Подзаголовок</h4>
|
||||
<div class="pretty-form__item">
|
||||
<input type="text" name="subheader" id="subheader" placeholder="Подзаголовок" />
|
||||
<label for="subheader">Подзаголовок</label>
|
||||
<input
|
||||
type="text"
|
||||
name="subtitle"
|
||||
id="subtitle"
|
||||
placeholder="Подзаголовок"
|
||||
value={form.subtitle}
|
||||
onChange={(e) => setForm('subtitle', e.currentTarget.value)}
|
||||
/>
|
||||
<label for="subtitle">Подзаголовок</label>
|
||||
</div>
|
||||
|
||||
<Editor />
|
||||
<Editor onChange={(body) => setForm('body', body)} />
|
||||
|
||||
<h1>Настройки публикации</h1>
|
||||
{/*<h4>Лид</h4>*/}
|
||||
|
@ -58,31 +112,38 @@ export const CreateView = () => {
|
|||
{/*</div>*/}
|
||||
|
||||
<h4>Темы</h4>
|
||||
<p class="description">
|
||||
Добавьте несколько тем, чтобы читатель знал, о чем ваш материал, и мог найти
|
||||
его на страницах интересных ему тем. Темы можно менять местами, первая тема
|
||||
становится заглавной
|
||||
</p>
|
||||
{/*<p class="description">*/}
|
||||
{/* Добавьте несколько тем, чтобы читатель знал, о чем ваш материал, и мог найти*/}
|
||||
{/* его на страницах интересных ему тем. Темы можно менять местами, первая тема*/}
|
||||
{/* становится заглавной*/}
|
||||
{/*</p>*/}
|
||||
<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>
|
||||
|
||||
<h4>Соавторы</h4>
|
||||
<p class="description">У каждого соавтора можно добавить роль</p>
|
||||
<div class="pretty-form__item--with-button">
|
||||
<div class="pretty-form__item">
|
||||
<input type="text" name="authors" id="authors" placeholder="Введите имя или e-mail" />
|
||||
<label for="authors">Введите имя или e-mail</label>
|
||||
</div>
|
||||
<button class="button button--submit">Добавить</button>
|
||||
</div>
|
||||
{/*<h4>Соавторы</h4>*/}
|
||||
{/*<p class="description">У каждого соавтора можно добавить роль</p>*/}
|
||||
{/*<div class="pretty-form__item--with-button">*/}
|
||||
{/* <div class="pretty-form__item">*/}
|
||||
{/* <input type="text" name="authors" id="authors" placeholder="Введите имя или e-mail" />*/}
|
||||
{/* <label for="authors">Введите имя или e-mail</label>*/}
|
||||
{/* </div>*/}
|
||||
{/* <button class="button button--submit">Добавить</button>*/}
|
||||
{/*</div>*/}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">Михаил Драбкин</div>
|
||||
<div class="col-md-6">
|
||||
<input type="text" name="coauthor" id="coauthor1" class="nolabel" />
|
||||
</div>
|
||||
</div>
|
||||
{/*<div class="row">*/}
|
||||
{/* <div class="col-md-6">Михаил Драбкин</div>*/}
|
||||
{/* <div class="col-md-6">*/}
|
||||
{/* <input type="text" name="coauthor" id="coauthor1" class="nolabel" />*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
|
||||
<h4>Карточка материала на главной</h4>
|
||||
<p class="description">
|
||||
|
@ -96,8 +157,10 @@ export const CreateView = () => {
|
|||
Проверьте ещё раз введённые данные, если всё верно, вы можете сохранить или
|
||||
опубликовать ваш текст
|
||||
</p>
|
||||
<button class={clsx('button button--outline', styles.button)}>Сохранить</button>
|
||||
<button class={clsx('button button--submit', styles.button)}>Опубликовать</button>
|
||||
{/*<button class={clsx('button button--outline', styles.button)}>Сохранить</button>*/}
|
||||
<button type="submit" class={clsx('button button--submit', styles.button)}>
|
||||
Опубликовать
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
import { PageLayout } from '../components/_shared/PageLayout'
|
||||
|
||||
export const CreateSettingsPage = () => {
|
||||
return <PageLayout>Настройки публикации</PageLayout>
|
||||
}
|
||||
|
||||
export const Page = CreateSettingsPage
|
Loading…
Reference in New Issue
Block a user