Merge remote-tracking branch 'gitlab/dev' into drafts
This commit is contained in:
commit
378fc65955
|
@ -39,6 +39,7 @@ 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
|
||||||
|
@ -147,17 +148,21 @@ 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 }) => {
|
||||||
// console.log('!!! e:', view)
|
const { doc, selection } = state
|
||||||
// return !e.isActive('image')
|
const { empty } = selection
|
||||||
// }
|
|
||||||
|
const isEmptyTextBlock = doc.textBetween(from, to).length === 0 && isTextSelection(selection)
|
||||||
|
|
||||||
|
return !(!view.hasFocus() || empty || isEmptyTextBlock || e.isActive('image'))
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
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 e.isFocused && e.isActive('image')
|
return view.hasFocus() && e.isActive('image')
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
FloatingMenu.configure({
|
FloatingMenu.configure({
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
|
|
||||||
.menuHolder {
|
.menuHolder {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
left: calc(100% + 1rem);
|
left: 40px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -0.8rem;
|
top: -0.4rem;
|
||||||
min-width: 64vw;
|
min-width: 64vw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,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<MenuItem | null>(null)
|
const [selectedMenuItem, setSelectedMenuItem] = createSignal<MenuItem | undefined>()
|
||||||
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)
|
||||||
|
@ -53,14 +53,19 @@ export const EditorFloatingMenu = (props: FloatingMenuProps) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const closeUploadModalHandler = () => {
|
const closeUploadModalHandler = () => {
|
||||||
setSelectedMenuItem(null)
|
setSelectedMenuItem()
|
||||||
setMenuOpen(false)
|
setMenuOpen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div ref={props.ref} class={styles.editorFloatingMenu}>
|
<div ref={props.ref} class={styles.editorFloatingMenu}>
|
||||||
<button type="button" onClick={() => setMenuOpen(!menuOpen())}>
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setMenuOpen(!menuOpen())
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Icon name="editor-plus" />
|
<Icon name="editor-plus" />
|
||||||
</button>
|
</button>
|
||||||
<Show when={menuOpen()}>
|
<Show when={menuOpen()}>
|
||||||
|
@ -73,7 +78,7 @@ export const EditorFloatingMenu = (props: FloatingMenuProps) => {
|
||||||
placeholder={t('Paste Embed code')}
|
placeholder={t('Paste Embed code')}
|
||||||
showInput={true}
|
showInput={true}
|
||||||
onClose={closeUploadModalHandler}
|
onClose={closeUploadModalHandler}
|
||||||
onClear={() => setSelectedMenuItem(null)}
|
onClear={() => setSelectedMenuItem()}
|
||||||
validate={validateEmbed}
|
validate={validateEmbed}
|
||||||
onSubmit={handleEmbedFormSubmit}
|
onSubmit={handleEmbedFormSubmit}
|
||||||
errorMessage={t('Error')}
|
errorMessage={t('Error')}
|
||||||
|
@ -83,7 +88,7 @@ export const EditorFloatingMenu = (props: FloatingMenuProps) => {
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<Modal variant="narrow" name="uploadImage" onClose={closeUploadModalHandler}>
|
<Modal variant="narrow" name="uploadImage" onClose={closeUploadModalHandler}>
|
||||||
<UploadModalContent closeCallback={() => setSelectedMenuItem(null)} editor={props.editor} />
|
<UploadModalContent closeCallback={() => setSelectedMenuItem()} editor={props.editor} />
|
||||||
</Modal>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,6 +2,7 @@ import styles from './Menu.module.scss'
|
||||||
import { Icon } from '../../../_shared/Icon'
|
import { Icon } from '../../../_shared/Icon'
|
||||||
|
|
||||||
export type MenuItem = 'image' | 'embed' | 'horizontal-rule'
|
export type MenuItem = 'image' | 'embed' | 'horizontal-rule'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
selectedItem: (value: string) => void
|
selectedItem: (value: string) => void
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { useLocalize } from '../../../context/localize'
|
||||||
import { Editor } from '@tiptap/core'
|
import { Editor } from '@tiptap/core'
|
||||||
import { Loading } from '../../_shared/Loading'
|
import { Loading } from '../../_shared/Loading'
|
||||||
import { verifyImg } from '../../../utils/verifyImg'
|
import { verifyImg } from '../../../utils/verifyImg'
|
||||||
|
import { imageProxy } from '../../../utils/imageProxy'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
editor: Editor
|
editor: Editor
|
||||||
|
@ -29,7 +30,7 @@ export const UploadModalContent = (props: Props) => {
|
||||||
.chain()
|
.chain()
|
||||||
.focus()
|
.focus()
|
||||||
.extendMarkRange('link')
|
.extendMarkRange('link')
|
||||||
.setImage({ src: `https://new.discours.io/api/image?url=${src}` })
|
.setImage({ src: imageProxy(src) })
|
||||||
.run()
|
.run()
|
||||||
hideModal()
|
hideModal()
|
||||||
}
|
}
|
||||||
|
@ -43,6 +44,7 @@ export const UploadModalContent = (props: Props) => {
|
||||||
setIsUploading(true)
|
setIsUploading(true)
|
||||||
const fileUrl = await handleFileUpload(file)
|
const fileUrl = await handleFileUpload(file)
|
||||||
setIsUploading(false)
|
setIsUploading(false)
|
||||||
|
props.closeCallback()
|
||||||
renderImage(fileUrl)
|
renderImage(fileUrl)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[upload image] error', error)
|
console.error('[upload image] error', error)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { createSignal, For } from 'solid-js'
|
import { For } from 'solid-js'
|
||||||
import type { Author } from '../../../graphql/types.gen'
|
import type { Author } from '../../../graphql/types.gen'
|
||||||
import { useAuthorsStore } from '../../../stores/zine/authors'
|
import { useAuthorsStore } from '../../../stores/zine/authors'
|
||||||
import { Icon } from '../../_shared/Icon'
|
import { Icon } from '../../_shared/Icon'
|
||||||
|
@ -29,10 +29,6 @@ export const Sidebar = (props: FeedSidebarProps) => {
|
||||||
const { articlesByTopic } = useArticlesStore()
|
const { articlesByTopic } = useArticlesStore()
|
||||||
const { topicEntities } = useTopicsStore()
|
const { topicEntities } = useTopicsStore()
|
||||||
|
|
||||||
createSignal(() => {
|
|
||||||
console.log('!!! topicEntities:', topicEntities())
|
|
||||||
})
|
|
||||||
|
|
||||||
const checkTopicIsSeen = (topicSlug: string) => {
|
const checkTopicIsSeen = (topicSlug: string) => {
|
||||||
return articlesByTopic()[topicSlug]?.every((article) => Boolean(seen()[article.slug]))
|
return articlesByTopic()[topicSlug]?.every((article) => Boolean(seen()[article.slug]))
|
||||||
}
|
}
|
||||||
|
|
|
@ -484,11 +484,15 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
vertical-align: middle;
|
width: auto;
|
||||||
width: auto;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.textLabel {
|
.textLabel {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { splitProps } from 'solid-js'
|
import { splitProps } from 'solid-js'
|
||||||
import type { JSX } from 'solid-js'
|
import type { JSX } from 'solid-js'
|
||||||
|
import { imageProxy } from '../../../utils/imageProxy'
|
||||||
|
|
||||||
export const Image = (props: JSX.ImgHTMLAttributes<HTMLImageElement>) => {
|
export const Image = (props: JSX.ImgHTMLAttributes<HTMLImageElement>) => {
|
||||||
const [local, others] = splitProps(props, ['src'])
|
const [local, others] = splitProps(props, ['src'])
|
||||||
|
|
||||||
return <img src={`/api/image?url=${encodeURI(local.src)}`} {...others} />
|
return <img src={imageProxy(local.src)} {...others} />
|
||||||
}
|
}
|
||||||
|
|
4
src/utils/imageProxy.ts
Normal file
4
src/utils/imageProxy.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import { isDev } from './config'
|
||||||
|
export const imageProxy = (url: string) => {
|
||||||
|
return `${isDev ? 'https://new.discours.io' : ''}/api/image?url=${encodeURI(url)}`
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user