Swiper update article & editor view (#145)

* Swiper update article & editor view
* Add link by META+KeyK
* Add isFocused check
This commit is contained in:
Ilya Y 2023-07-28 12:47:19 +03:00 committed by GitHub
parent 40af94e101
commit 506b36af7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 88 additions and 72 deletions

View File

@ -218,6 +218,7 @@
"Quotes": "Quotes",
"Reason uknown": "Reason unknown",
"Recent": "Fresh",
"Remove link": "Remove link",
"Reply": "Reply",
"Report": "Complain",
"Required": "Required",
@ -321,8 +322,8 @@
"back to menu": "back to menu",
"bold": "bold",
"bookmarks": "bookmarks",
"cancel": "Cancel",
"cancel_low_caps": "cancel",
"Cancel": "Cancel",
"cancel": "cancel",
"collections": "collections",
"community": "community",
"delimiter": "delimiter",

View File

@ -233,6 +233,7 @@
"Reason uknown": "Причина неизвестна",
"Recent": "Свежее",
"Release date...": "Дата выхода...",
"Remove link": "Убрать ссылку",
"Reply": "Ответить",
"Report": "Пожаловаться",
"Required": "Поле обязательно для заполнения",
@ -339,8 +340,8 @@
"back to menu": "назад в меню",
"bold": "жирный",
"bookmarks": "закладки",
"cancel": "Отмена",
"cancel_low_caps": "отменить",
"Cancel": "Отмена",
"cancel": "отменить",
"collections": "коллекции",
"community": "сообщество",
"create_chat": "Создать чат",

View File

@ -153,7 +153,13 @@ export const FullArticle = (props: ArticleProps) => {
)}
</For>
</div>
<Show when={props.article.cover && props.article.layout !== 'video'}>
<Show
when={
props.article.cover &&
props.article.layout !== 'video' &&
props.article.layout !== 'image'
}
>
<div
class={styles.shoutCover}
style={{ 'background-image': `url('${imageProxy(props.article.cover)}')` }}

View File

@ -1,4 +1,4 @@
import { createEffect, createSignal, onMount, untrack } from 'solid-js'
import { createEffect, createSignal } from 'solid-js'
import { createTiptapEditor, useEditorHTML } from 'solid-tiptap'
import { useLocalize } from '../../context/localize'
import { Bold } from '@tiptap/extension-bold'

View File

@ -53,6 +53,10 @@ export const InlineForm = (props: Props) => {
}
}
const handleClear = () => {
props.initialValue ? props.onClear() : props.onClose()
}
return (
<div class={styles.InlineForm}>
<div class={styles.form}>
@ -76,9 +80,9 @@ export const InlineForm = (props: Props) => {
</button>
)}
</Popover>
<Popover content={props.initialValue ? t('Unlink') : t('Cancel')}>
<Popover content={props.initialValue ? t('Remove link') : t('Cancel')}>
{(triggerRef: (el) => void) => (
<button ref={triggerRef} type="button" onClick={props.onClear}>
<button ref={triggerRef} type="button" onClick={handleClear}>
{props.initialValue ? <Icon name="editor-unlink" /> : <Icon name="status-cancel" />}
</button>
)}

View File

@ -237,7 +237,7 @@ export const Panel = (props: Props) => {
<section class={styles.shortcutList}>
<p>
{t('cancel_low_caps')}
{t('cancel')}
<span class={styles.shortcut}>
<span class={styles.shortcutButton}>Ctrl</span>
<span class={styles.shortcutButton}>Z</span>

View File

@ -124,16 +124,21 @@ const SimplifiedEditor = (props: Props) => {
})
const handleKeyDown = async (event) => {
if (props.submitByEnter && event.keyCode === 13 && !event.shiftKey && !isEmpty()) {
if (isEmpty() || !editor().isFocused) {
return
}
if (
event.code === 'Enter' &&
((props.submitByEnter && !event.shiftKey) || (props.submitByShiftEnter && event.shiftKey))
) {
event.preventDefault()
props.onSubmit(html())
handleClear()
}
if (props.submitByShiftEnter && event.keyCode === 13 && event.shiftKey && !isEmpty()) {
event.preventDefault()
props.onSubmit(html())
handleClear()
if (event.code === 'KeyK' && (event.metaKey || event.ctrlKey) && !editor().state.selection.empty) {
showModal('editorInsertLink')
}
}
@ -144,7 +149,8 @@ const SimplifiedEditor = (props: Props) => {
onCleanup(() => {
window.removeEventListener('keydown', handleKeyDown)
})
const handleToggleBlockquote = () => editor().chain().focus().toggleBlockquote().run()
const handleInsertLink = () => !editor().state.selection.empty && showModal('editorInsertLink')
return (
<div
class={clsx(styles.SimplifiedEditor, {
@ -184,7 +190,7 @@ const SimplifiedEditor = (props: Props) => {
<button
ref={triggerRef}
type="button"
onClick={() => showModal('editorInsertLink')}
onClick={() => handleInsertLink}
class={clsx(styles.actionButton, { [styles.active]: isLink() })}
>
<Icon name="editor-link" />
@ -197,7 +203,7 @@ const SimplifiedEditor = (props: Props) => {
<button
ref={triggerRef}
type="button"
onClick={() => editor().chain().focus().toggleBlockquote().run()}
onClick={handleToggleBlockquote}
class={clsx(styles.actionButton, { [styles.active]: isBlockquote() })}
>
<Icon name="editor-quote" />
@ -221,7 +227,7 @@ const SimplifiedEditor = (props: Props) => {
</Show>
</div>
<div class={styles.buttons}>
<Button value={t('cancel')} variant="secondary" disabled={isEmpty()} onClick={handleClear} />
<Button value={t('Cancel')} variant="secondary" disabled={isEmpty()} onClick={handleClear} />
<Button
value={props.submitButtonText ?? t('Send')}
variant="primary"

View File

@ -88,7 +88,7 @@ const CreateModalContent = (props: Props) => {
<div class={styles.footer}>
<button type="button" class="btn btn-lg fs-3 btn-outline-danger" onClick={reset}>
{t('cancel')}
{t('Cancel')}
</button>
<button
type="button"

View File

@ -5,7 +5,6 @@ import { Popover } from '../Popover'
import { useLocalize } from '../../../context/localize'
import { register } from 'swiper/element/bundle'
import { DropArea } from '../DropArea'
import MD from '../../Article/MD'
import { createFileUploader } from '@solid-primitives/upload'
import SwiperCore, { Manipulation, Navigation, Pagination } from 'swiper'
import { SwiperRef } from './swiper'
@ -103,9 +102,11 @@ export const SolidSwiper = (props: Props) => {
} catch (error) {
await showSnackbar({ type: 'error', body: t('Error') })
console.error('[runUpload]', error)
setLoading(false)
}
} else {
await showSnackbar({ type: 'error', body: t('Invalid file type') })
setLoading(false)
return false
}
}
@ -179,52 +180,6 @@ export const SolidSwiper = (props: Props) => {
</Popover>
</Show>
</div>
<Switch>
<Match when={props.editorMode}>
<div class={styles.description}>
<input
type="text"
class={clsx(styles.input, styles.title)}
placeholder={t('Enter image title')}
value={slide.title}
onChange={(event) =>
handleSlideDescriptionChange(index(), 'title', event.target.value)
}
/>
<input
type="text"
class={styles.input}
placeholder={t('Specify the source and the name of the author')}
value={slide.source}
onChange={(event) =>
handleSlideDescriptionChange(index(), 'source', event.target.value)
}
/>
<SimplifiedEditor
initialContent={slide.body}
smallHeight={true}
placeholder={t('Enter image description')}
onSubmit={(value) => handleSlideDescriptionChange(index(), 'body', value)}
submitButtonText={t('Save')}
/>
</div>
</Match>
<Match when={!props.editorMode}>
<div class={styles.slideDescription}>
<Show when={slide?.title}>
<div class={styles.articleTitle}>{slide.title}</div>
</Show>
<Show when={slide?.source}>
<div class={styles.source}>{slide.source}</div>
</Show>
<Show when={slide?.body}>
<div class={styles.body}>
<MD body={slide.body} />
</div>
</Show>
</div>
</Match>
</Switch>
</swiper-slide>
)}
</For>
@ -249,23 +204,19 @@ export const SolidSwiper = (props: Props) => {
{slideIndex() + 1} / {props.images.length}
</div>
</div>
<div class={clsx(styles.holder, styles.thumbsHolder)}>
<div class={styles.thumbs}>
<swiper-container
class={'thumbSwiper'}
ref={(el) => (thumbSwipeRef.current = el)}
slides-per-view={'auto'}
free-mode={true}
observer={true}
space-between={20}
auto-scroll-offset={1}
watch-overflow={true}
slide-to-clicked-slide={true}
watch-slides-visibility={true}
watch-slides-progress={true}
direction={props.editorMode ? 'horizontal' : 'vertical'}
slides-offset-after={props.editorMode && 140}
slides-offset-after={props.editorMode && 160}
slides-offset-before={props.editorMode && 30}
>
<For each={props.images}>
{(slide, index) => (
@ -337,6 +288,46 @@ export const SolidSwiper = (props: Props) => {
</div>
</Show>
</div>
<Show
when={props.editorMode}
fallback={
<div class={styles.slideDescription}>
<Show when={props.images[slideIndex()]?.title}>
<div class={styles.articleTitle}>{props.images[slideIndex()].title}</div>
</Show>
<Show when={props.images[slideIndex()]?.source}>
<div class={styles.source}>{props.images[slideIndex()].source}</div>
</Show>
<Show when={props.images[slideIndex()]?.body}>
<div class={styles.body} innerHTML={props.images[slideIndex()].body} />
</Show>
</div>
}
>
<div class={styles.description}>
<input
type="text"
class={clsx(styles.input, styles.title)}
placeholder={t('Enter image title')}
value={props.images[slideIndex()].title}
onChange={(event) => handleSlideDescriptionChange(slideIndex(), 'title', event.target.value)}
/>
<input
type="text"
class={styles.input}
placeholder={t('Specify the source and the name of the author')}
value={props.images[slideIndex()].source}
onChange={(event) => handleSlideDescriptionChange(slideIndex(), 'source', event.target.value)}
/>
<SimplifiedEditor
initialContent={props.images[slideIndex()].body}
smallHeight={true}
placeholder={t('Enter image description')}
onSubmit={(value) => handleSlideDescriptionChange(slideIndex(), 'body', value)}
submitButtonText={t('Save')}
/>
</div>
</Show>
</div>
)
}

View File

@ -11,6 +11,7 @@ $navigation-reserve: 32px;
.Swiper {
display: block;
margin: 2rem 0;
flex-direction: column;
&.articleMode {
background: var(--background-color-invert);
@ -137,6 +138,11 @@ $navigation-reserve: 32px;
}
}
}
&.editorMode {
.holder {
width: 100%;
}
}
.navigation {
background: rgb(0 0 0 / 40%);
@ -183,6 +189,7 @@ $navigation-reserve: 32px;
.slideDescription {
margin-top: 8px;
align-self: flex-start;
.articleTitle {
@include font-size(1.4rem);