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/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",

View File

@ -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",

View File

@ -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,

View File

@ -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)} />

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 { 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')}>
<Show when={page().route !== 'create'}>
<div class={clsx(styles.userControlItem, styles.userControlItemVerbose)}>
<a href="/create">
<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}>

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 { 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">
Добавьте несколько тем, чтобы читатель знал, о&nbsp;чем ваш материал, и&nbsp;мог найти
его на&nbsp;страницах интересных ему тем. Темы можно менять местами, первая тема
становится заглавной
</p>
{/*<p class="description">*/}
{/* Добавьте несколько тем, чтобы читатель знал, о&nbsp;чем ваш материал, и&nbsp;мог найти*/}
{/* его на&nbsp;страницах интересных ему тем. Темы можно менять местами, первая тема*/}
{/* становится заглавной*/}
{/*</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>Карточка материала на&nbsp;главной</h4>
<p class="description">
@ -96,8 +157,10 @@ export const CreateView = () => {
Проверьте ещё раз введённые данные, если всё верно, вы&nbsp;можете сохранить или
опубликовать ваш текст
</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>

View File

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