insert link enter fix (#94)

* floating plus fix, esc fix

* a href="#" -> span
This commit is contained in:
Igor Lobanov 2023-05-12 15:45:31 +02:00 committed by GitHub
parent 47d14b0a5d
commit bd6e014cdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 60 additions and 42 deletions

View File

@ -19,6 +19,7 @@ import { Title } from '@solidjs/meta'
import { useLocalize } from '../../context/localize'
import stylesHeader from '../Nav/Header.module.scss'
import styles from './Article.module.scss'
import { imageProxy } from '../../utils/imageProxy'
interface ArticleProps {
article: Shout
@ -152,7 +153,7 @@ export const FullArticle = (props: ArticleProps) => {
<Show when={props.article.cover}>
<div
class={styles.shoutCover}
style={{ 'background-image': `url('${props.article.cover}')` }}
style={{ 'background-image': `url('${imageProxy(props.article.cover)}')` }}
/>
</Show>
</div>

View File

@ -17,7 +17,7 @@
background: #fff;
left: 24px;
position: absolute;
top: -2px;
top: -4px;
min-width: 64vw;
}
}

View File

@ -30,6 +30,7 @@ export const EditorFloatingMenu = (props: FloatingMenuProps) => {
const [selectedMenuItem, setSelectedMenuItem] = createSignal<MenuItem | undefined>()
const [menuOpen, setMenuOpen] = createSignal<boolean>(false)
const menuRef: { current: HTMLDivElement } = { current: null }
const plusButtonRef: { current: HTMLButtonElement } = { current: null }
const handleEmbedFormSubmit = async (value: string) => {
// TODO: add support instagram embed (blockquote)
const emb = await embedData(value)
@ -62,7 +63,11 @@ export const EditorFloatingMenu = (props: FloatingMenuProps) => {
useOutsideClickHandler({
containerRef: menuRef,
handler: () => {
handler: (e) => {
if (plusButtonRef.current.contains(e.target)) {
return
}
if (menuOpen()) {
setMenuOpen(false)
}
@ -82,6 +87,7 @@ export const EditorFloatingMenu = (props: FloatingMenuProps) => {
<>
<div ref={props.ref} class={styles.editorFloatingMenu}>
<button
ref={(el) => (plusButtonRef.current = el)}
type="button"
onClick={() => {
setMenuOpen(!menuOpen())

View File

@ -18,7 +18,8 @@ export const InlineForm = (props: Props) => {
const [formValue, setFormValue] = createSignal(props.initialValue || '')
const [formValueError, setFormValueError] = createSignal<string | undefined>()
const handleFormInput = (value) => {
const handleFormInput = (e) => {
const value = e.currentTarget.value
setFormValueError()
setFormValue(value)
}
@ -36,16 +37,16 @@ export const InlineForm = (props: Props) => {
props.onClose()
}
const handleKeyPress = async (event) => {
const handleKeyDown = async (e) => {
setFormValueError('')
const key = event.key
if (key === 'Enter') {
if (e.key === 'Enter') {
e.preventDefault()
await handleSaveButtonClick()
}
if (key === 'Esc') {
props.onClear
if (e.key === 'Escape' && props.onClear) {
props.onClear()
}
}
@ -57,8 +58,8 @@ export const InlineForm = (props: Props) => {
type="text"
value={props.initialValue ?? ''}
placeholder={props.placeholder}
onKeyPress={(e) => handleKeyPress(e)}
onInput={(e) => handleFormInput(e.currentTarget.value)}
onKeyDown={handleKeyDown}
onInput={handleFormInput}
/>
<button type="button" onClick={handleSaveButtonClick} disabled={Boolean(formValueError())}>
<Icon name="status-done" />

View File

@ -56,7 +56,8 @@
}
}
a {
.link {
cursor: pointer;
text-decoration: none;
border-bottom: none;
color: rgb(255 255 255 / 35%);

View File

@ -42,18 +42,15 @@ export const Panel = (props: Props) => {
}
})
const handleSaveLinkClick = (e) => {
e.preventDefault()
const handleSaveClick = () => {
saveShout()
}
const handlePublishLinkClick = (e) => {
e.preventDefault()
const handlePublishClick = () => {
publishShout()
}
const handleFixTypographyLinkClick = (e) => {
e.preventDefault()
const handleFixTypographyClick = () => {
const html = useEditorHTML(() => editorRef.current())
editorRef.current().commands.setContent(typograf.execute(html()))
}
@ -74,27 +71,27 @@ export const Panel = (props: Props) => {
<div class={clsx(styles.actionsHolder, styles.scrolled)}>
<section>
<p>
<a href="#" onClick={handlePublishLinkClick}>
<span class={styles.link} onClick={handlePublishClick}>
{t('Publish')}
</a>
</span>
</p>
<p>
<a href="#" onClick={handleSaveLinkClick}>
<span class={styles.link} onClick={handleSaveClick}>
{t('Save draft')}
</a>
</span>
</p>
</section>
<section>
<p>
<a class={styles.linkWithIcon}>
<a class={clsx(styles.link, styles.linkWithIcon)}>
<Icon name="eye" class={styles.icon} />
{t('Preview')}
</a>
</p>
<p>
<a
class={styles.linkWithIcon}
class={clsx(styles.link, styles.linkWithIcon)}
onClick={() => toggleEditorPanel()}
href={getPagePath(router, 'edit', { shoutId: props.shoutId.toString() })}
>
@ -103,7 +100,7 @@ export const Panel = (props: Props) => {
</a>
</p>
<p>
<a class={styles.linkWithIcon}>
<a class={clsx(styles.link, styles.linkWithIcon)}>
<Icon name="feed-discussion" class={styles.icon} />
{t('FAQ')}
</a>
@ -112,10 +109,11 @@ export const Panel = (props: Props) => {
<section>
<p>
<a>{t('Invite co-authors')}</a>
<a class={styles.link}>{t('Invite co-authors')}</a>
</p>
<p>
<a
class={styles.link}
onClick={() => toggleEditorPanel()}
href={getPagePath(router, 'editSettings', { shoutId: props.shoutId.toString() })}
>
@ -123,24 +121,30 @@ export const Panel = (props: Props) => {
</a>
</p>
<p>
<a onClick={handleFixTypographyLinkClick} href="#">
<span class={styles.link} onClick={handleFixTypographyClick}>
{t('Fix typography')}
</a>
</span>
</p>
<p>
<a>{t('Corrections history')}</a>
<a class={styles.link}>{t('Corrections history')}</a>
</p>
</section>
<section>
<p>
<a href="/how-to-write-a-good-article">{t('How to write a good article')}</a>
<a class={styles.link} href="/how-to-write-a-good-article">
{t('How to write a good article')}
</a>
</p>
<p>
<a href="#">{t('Hotkeys')}</a>
<a class={styles.link} href="#">
{t('Hotkeys')}
</a>
</p>
<p>
<a href="#">{t('Help')}</a>
<a class={styles.link} href="#">
{t('Help')}
</a>
</p>
</section>

View File

@ -2,6 +2,7 @@ import { Show, createMemo } from 'solid-js'
import './DialogCard.module.scss'
import styles from './DialogAvatar.module.scss'
import { clsx } from 'clsx'
import { imageProxy } from '../../utils/imageProxy'
type Props = {
name: string
@ -46,7 +47,7 @@ const DialogAvatar = (props: Props) => {
style={{ 'background-color': `${randomBg()}` }}
>
<Show when={Boolean(props.url)} fallback={<div class={styles.letter}>{nameFirstLetter()}</div>}>
<div class={styles.imageHolder} style={{ 'background-image': `url(${props.url})` }} />
<div class={styles.imageHolder} style={{ 'background-image': `url(${imageProxy(props.url)})` }} />
</Show>
</div>
)

View File

@ -16,9 +16,11 @@ export const Modal = (props: ModalProps) => {
const { modal } = useModalStore()
const handleHide = () => {
if (modal()) {
hideModal()
props.onClose && props.onClose()
}
}
useEscKeyDownHandler(handleHide)

View File

@ -2,7 +2,9 @@ import { onCleanup, onMount } from 'solid-js'
export const useEscKeyDownHandler = (onEscKeyDown: () => void) => {
const keydownHandler = (e: KeyboardEvent) => {
if (e.key === 'Escape') onEscKeyDown()
if (e.key === 'Escape') {
onEscKeyDown()
}
}
onMount(() => {

View File

@ -2,24 +2,24 @@ import { onCleanup, onMount } from 'solid-js'
type Options = {
containerRef: { current: HTMLElement }
handler: () => void
handler: (e: MouseEvent & { target: Element }) => void
// if predicate is present
// handler is called only if predicate function returns true
predicate?: () => boolean
predicate?: (e: MouseEvent & { target: Element }) => boolean
}
export const useOutsideClickHandler = (options: Options) => {
const { predicate, containerRef, handler } = options
const handleClickOutside = (event: MouseEvent & { target: Element }) => {
if (predicate && !predicate()) {
const handleClickOutside = (e: MouseEvent & { target: Element }) => {
if (predicate && !predicate(e)) {
return
}
if (event.target === containerRef.current || containerRef.current?.contains(event.target)) {
if (e.target === containerRef.current || containerRef.current?.contains(e.target)) {
return
}
handler()
handler(e)
}
onMount(() => {