WIP
This commit is contained in:
parent
0c849a99e9
commit
382da58af2
5
public/icons/editor-horizontal-rule.svg
Normal file
5
public/icons/editor-horizontal-rule.svg
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M23 11.01L1 11V13H23V11.01Z" fill="currentColor"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M19 3H5V9H19V3ZM17 5H7V7H17V5Z" fill="currentColor"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M19 15H5V21H19V15ZM17 17H7V19H17V17Z" fill="currentColor"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 375 B |
|
@ -39,7 +39,6 @@ import { TextBubbleMenu } from './TextBubbleMenu'
|
||||||
import { ImageBubbleMenu } from './ImageBubbleMenu'
|
import { ImageBubbleMenu } from './ImageBubbleMenu'
|
||||||
import { EditorFloatingMenu } from './EditorFloatingMenu'
|
import { EditorFloatingMenu } from './EditorFloatingMenu'
|
||||||
import { useEditorContext } from '../../context/editor'
|
import { useEditorContext } from '../../context/editor'
|
||||||
import { isTextSelection } from '@tiptap/core'
|
|
||||||
|
|
||||||
type EditorProps = {
|
type EditorProps = {
|
||||||
shoutId: number
|
shoutId: number
|
||||||
|
@ -105,7 +104,11 @@ export const Editor = (props: EditorProps) => {
|
||||||
Bold,
|
Bold,
|
||||||
Italic,
|
Italic,
|
||||||
Strike,
|
Strike,
|
||||||
HorizontalRule,
|
HorizontalRule.configure({
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: 'horizontalRule'
|
||||||
|
}
|
||||||
|
}),
|
||||||
Underline,
|
Underline,
|
||||||
Link.configure({
|
Link.configure({
|
||||||
openOnClick: false
|
openOnClick: false
|
||||||
|
@ -144,25 +147,17 @@ export const Editor = (props: EditorProps) => {
|
||||||
CharacterCount,
|
CharacterCount,
|
||||||
BubbleMenu.configure({
|
BubbleMenu.configure({
|
||||||
pluginKey: 'textBubbleMenu',
|
pluginKey: 'textBubbleMenu',
|
||||||
element: textBubbleMenuRef.current,
|
element: textBubbleMenuRef.current
|
||||||
shouldShow: ({ editor: e, view, state, oldState, from, to }) => {
|
// shouldShow: ({ editor: e, view, state, oldState, from, to }) => {
|
||||||
const { doc, selection } = state
|
// console.log('!!! e:', view)
|
||||||
const { empty } = selection
|
// return !e.isActive('image')
|
||||||
|
// }
|
||||||
const isEmptyTextBlock = doc.textBetween(from, to).length === 0 && isTextSelection(selection)
|
|
||||||
|
|
||||||
if (!view.hasFocus() || empty || isEmptyTextBlock || e.isActive('image')) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
BubbleMenu.configure({
|
BubbleMenu.configure({
|
||||||
pluginKey: 'imageBubbleMenu',
|
pluginKey: 'imageBubbleMenu',
|
||||||
element: imageBubbleMenuRef.current,
|
element: imageBubbleMenuRef.current,
|
||||||
shouldShow: ({ editor: e, view, state, oldState, from, to }) => {
|
shouldShow: ({ editor: e, view, state, oldState, from, to }) => {
|
||||||
return view.hasFocus() && e.isActive('image')
|
return e.isFocused && e.isActive('image')
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
FloatingMenu.configure({
|
FloatingMenu.configure({
|
||||||
|
|
|
@ -12,10 +12,10 @@
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menuHolder {
|
.menuHolder {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
left: calc(100% + 1rem);
|
left: calc(100% + 1rem);
|
||||||
box-shadow: 0 4px 10px rgba(#000, 0.25);
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -0.8rem;
|
top: -0.8rem;
|
||||||
min-width: 64vw;
|
min-width: 64vw;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import HTMLParser from 'html-to-json-parser'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { useLocalize } from '../../../context/localize'
|
||||||
import { Modal } from '../../Nav/Modal'
|
import { Modal } from '../../Nav/Modal'
|
||||||
import { Menu } from './Menu'
|
import { Menu } from './Menu'
|
||||||
|
import type { MenuItem } from './Menu/Menu'
|
||||||
import { showModal } from '../../../stores/ui'
|
import { showModal } from '../../../stores/ui'
|
||||||
import { UploadModalContent } from '../UploadModal'
|
import { UploadModalContent } from '../UploadModal'
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ const validateEmbed = async (value) => {
|
||||||
|
|
||||||
export const EditorFloatingMenu = (props: FloatingMenuProps) => {
|
export const EditorFloatingMenu = (props: FloatingMenuProps) => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
const [selectedMenuItem, setSelectedMenuItem] = createSignal<string | null>(null)
|
const [selectedMenuItem, setSelectedMenuItem] = createSignal<MenuItem | null>(null)
|
||||||
const [menuOpen, setMenuOpen] = createSignal<boolean>(false)
|
const [menuOpen, setMenuOpen] = createSignal<boolean>(false)
|
||||||
const handleEmbedFormSubmit = async (value: string) => {
|
const handleEmbedFormSubmit = async (value: string) => {
|
||||||
// TODO: add support instagram embed (blockquote)
|
// TODO: add support instagram embed (blockquote)
|
||||||
|
@ -40,8 +41,15 @@ export const EditorFloatingMenu = (props: FloatingMenuProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (selectedMenuItem() === 'image') {
|
switch (selectedMenuItem()) {
|
||||||
|
case 'image': {
|
||||||
showModal('uploadImage')
|
showModal('uploadImage')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case 'horizontal-rule': {
|
||||||
|
props.editor.chain().focus().setHorizontalRule().run()
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const closeUploadModalHandler = () => {
|
const closeUploadModalHandler = () => {
|
||||||
|
@ -58,7 +66,7 @@ export const EditorFloatingMenu = (props: FloatingMenuProps) => {
|
||||||
<Show when={menuOpen()}>
|
<Show when={menuOpen()}>
|
||||||
<div class={styles.menuHolder}>
|
<div class={styles.menuHolder}>
|
||||||
<Show when={!selectedMenuItem()}>
|
<Show when={!selectedMenuItem()}>
|
||||||
<Menu selectedItem={(value) => setSelectedMenuItem(value)} />
|
<Menu selectedItem={(value: MenuItem) => setSelectedMenuItem(value)} />
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={selectedMenuItem() === 'embed'}>
|
<Show when={selectedMenuItem() === 'embed'}>
|
||||||
<InlineForm
|
<InlineForm
|
||||||
|
|
|
@ -1,19 +1,27 @@
|
||||||
import styles from './Menu.module.scss'
|
import styles from './Menu.module.scss'
|
||||||
import { Icon } from '../../../_shared/Icon'
|
import { Icon } from '../../../_shared/Icon'
|
||||||
|
|
||||||
|
export type MenuItem = 'image' | 'embed' | 'horizontal-rule'
|
||||||
type Props = {
|
type Props = {
|
||||||
selectedItem: (value: string) => void
|
selectedItem: (value: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Menu = (props: Props) => {
|
export const Menu = (props: Props) => {
|
||||||
|
const setSelectedMenuItem = (value: MenuItem) => {
|
||||||
|
props.selectedItem(value)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={styles.Menu}>
|
<div class={styles.Menu}>
|
||||||
<button type="button" onClick={() => props.selectedItem('image')}>
|
<button type="button" onClick={() => setSelectedMenuItem('image')}>
|
||||||
<Icon class={styles.icon} name="editor-image" />
|
<Icon class={styles.icon} name="editor-image" />
|
||||||
</button>
|
</button>
|
||||||
<button type="button" onClick={() => props.selectedItem('embed')}>
|
<button type="button" onClick={() => setSelectedMenuItem('embed')}>
|
||||||
<Icon class={styles.icon} name="editor-embed" />
|
<Icon class={styles.icon} name="editor-embed" />
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" onClick={() => setSelectedMenuItem('horizontal-rule')}>
|
||||||
|
<Icon class={styles.icon} name="editor-horizontal-rule" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,3 +68,7 @@
|
||||||
display: block;
|
display: block;
|
||||||
width: unset !important;
|
width: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.horizontalRule {
|
||||||
|
border-top: 2px solid #000;
|
||||||
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ export const UploadModalContent = (props: Props) => {
|
||||||
.chain()
|
.chain()
|
||||||
.focus()
|
.focus()
|
||||||
.extendMarkRange('link')
|
.extendMarkRange('link')
|
||||||
.setImage({ src: `/api/image?url=${src}` })
|
.setImage({ src: `https://new.discours.io/api/image?url=${src}` })
|
||||||
.run()
|
.run()
|
||||||
hideModal()
|
hideModal()
|
||||||
}
|
}
|
||||||
|
|
|
@ -677,7 +677,7 @@ figcaption {
|
||||||
|
|
||||||
.main-content {
|
.main-content {
|
||||||
flex: 1 100%;
|
flex: 1 100%;
|
||||||
min-height: 300px;
|
min-height: 90vh;
|
||||||
padding-top: 120px;
|
padding-top: 120px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user