diff --git a/src/components/Editor/Editor.tsx b/src/components/Editor/Editor.tsx
index 926a9955..4722a1ff 100644
--- a/src/components/Editor/Editor.tsx
+++ b/src/components/Editor/Editor.tsx
@@ -35,7 +35,8 @@ import { useSession } from '../../context/session'
import uniqolor from 'uniqolor'
import { HocuspocusProvider } from '@hocuspocus/provider'
import { Embed } from './extensions/embed'
-import { EditorBubbleMenu } from './EditorBubbleMenu'
+import { TextBubbleMenu } from './TextBubbleMenu'
+import { ImageBubbleMenu } from './ImageBubbleMenu'
import { EditorFloatingMenu } from './EditorFloatingMenu'
import { useEditorContext } from '../../context/editor'
@@ -74,7 +75,13 @@ export const Editor = (props: EditorProps) => {
current: null
}
- const bubbleMenuRef: {
+ const textBubbleMenuRef: {
+ current: HTMLDivElement
+ } = {
+ current: null
+ }
+
+ const imageBubbleMenuRef: {
current: HTMLDivElement
} = {
current: null
@@ -135,7 +142,19 @@ export const Editor = (props: EditorProps) => {
TrailingNode,
CharacterCount,
BubbleMenu.configure({
- element: bubbleMenuRef.current
+ pluginKey: 'textBubbleMenu',
+ element: textBubbleMenuRef.current,
+ shouldShow: ({ editor: e, view, state, oldState, from, to }) => {
+ console.log(view)
+ return e.isFocused && !e.isActive('image')
+ }
+ }),
+ BubbleMenu.configure({
+ pluginKey: 'imageBubbleMenu',
+ element: imageBubbleMenuRef.current,
+ shouldShow: ({ editor: e, view, state, oldState, from, to }) => {
+ return e.isFocused && e.isActive('image')
+ }
}),
FloatingMenu.configure({
tippyOptions: {
@@ -165,7 +184,8 @@ export const Editor = (props: EditorProps) => {
return (
<>
(editorElRef.current = el)} />
-
(bubbleMenuRef.current = el)} />
+ (textBubbleMenuRef.current = el)} />
+ (imageBubbleMenuRef.current = el)} />
(floatingMenuRef.current = el)} />
>
)
diff --git a/src/components/Editor/EditorBubbleMenu/EditorBubbleMenu.tsx b/src/components/Editor/EditorBubbleMenu/EditorBubbleMenu.tsx
deleted file mode 100644
index 5a8aad2e..00000000
--- a/src/components/Editor/EditorBubbleMenu/EditorBubbleMenu.tsx
+++ /dev/null
@@ -1,258 +0,0 @@
-import { Switch, Match, createSignal, Show } from 'solid-js'
-import type { Editor } from '@tiptap/core'
-import styles from './EditorBubbleMenu.module.scss'
-import { Icon } from '../../_shared/Icon'
-import { clsx } from 'clsx'
-import { createEditorTransaction } from 'solid-tiptap'
-import { useLocalize } from '../../../context/localize'
-import { InlineForm } from '../InlineForm'
-import validateImage from '../../../utils/validateUrl'
-
-type BubbleMenuProps = {
- editor: Editor
- ref: (el: HTMLDivElement) => void
-}
-
-export const EditorBubbleMenu = (props: BubbleMenuProps) => {
- const { t } = useLocalize()
- const [textSizeBubbleOpen, setTextSizeBubbleOpen] = createSignal(false)
- const [listBubbleOpen, setListBubbleOpen] = createSignal(false)
- const [linkEditorOpen, setLinkEditorOpen] = createSignal(false)
-
- const isActive = (name: string, attributes?: unknown) =>
- createEditorTransaction(
- () => props.editor,
- (editor) => {
- return editor && editor.isActive(name, attributes)
- }
- )
-
- const isBold = isActive('bold')
- const isItalic = isActive('italic')
- const isH1 = isActive('heading', { level: 1 })
- const isH2 = isActive('heading', { level: 2 })
- const isH3 = isActive('heading', { level: 3 })
- const isBlockQuote = isActive('blockquote')
- const isOrderedList = isActive('isOrderedList')
- const isBulletList = isActive('isBulletList')
- const isLink = isActive('link')
-
- const toggleLinkForm = () => {
- setLinkEditorOpen(true)
- }
-
- const toggleTextSizePopup = () => {
- if (listBubbleOpen()) {
- setListBubbleOpen(false)
- }
-
- setTextSizeBubbleOpen((prev) => !prev)
- }
- const toggleListPopup = () => {
- if (textSizeBubbleOpen()) {
- setTextSizeBubbleOpen(false)
- }
-
- setListBubbleOpen((prev) => !prev)
- }
-
- const handleLinkFormSubmit = (value: string) => {
- props.editor.chain().focus().setLink({ href: value }).run()
- }
-
- const currentUrl = createEditorTransaction(
- () => props.editor,
- (editor) => {
- return (editor && editor.getAttributes('link').href) || ''
- }
- )
-
- const handleClearLinkForm = () => {
- if (currentUrl()) {
- props.editor.chain().focus().unsetLink().run()
- }
- setLinkEditorOpen(false)
- }
-
- return (
- <>
-
- >
- )
-}
diff --git a/src/components/Editor/EditorBubbleMenu/index.ts b/src/components/Editor/EditorBubbleMenu/index.ts
deleted file mode 100644
index c4d82a89..00000000
--- a/src/components/Editor/EditorBubbleMenu/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { EditorBubbleMenu } from './EditorBubbleMenu'
diff --git a/src/components/Editor/EditorBubbleMenu/EditorBubbleMenu.module.scss b/src/components/Editor/ImageBubbleMenu/ImageBubbleMenu.module.scss
similarity index 100%
rename from src/components/Editor/EditorBubbleMenu/EditorBubbleMenu.module.scss
rename to src/components/Editor/ImageBubbleMenu/ImageBubbleMenu.module.scss
diff --git a/src/components/Editor/ImageBubbleMenu/ImageBubbleMenu.tsx b/src/components/Editor/ImageBubbleMenu/ImageBubbleMenu.tsx
new file mode 100644
index 00000000..dc29029f
--- /dev/null
+++ b/src/components/Editor/ImageBubbleMenu/ImageBubbleMenu.tsx
@@ -0,0 +1,15 @@
+import type { Editor } from '@tiptap/core'
+import styles from './ImageBubbleMenu.module.scss'
+
+type BubbleMenuProps = {
+ editor: Editor
+ ref: (el: HTMLDivElement) => void
+}
+
+export const ImageBubbleMenu = (props: BubbleMenuProps) => {
+ return (
+
+ )
+}
diff --git a/src/components/Editor/ImageBubbleMenu/index.ts b/src/components/Editor/ImageBubbleMenu/index.ts
new file mode 100644
index 00000000..8eb0eb1a
--- /dev/null
+++ b/src/components/Editor/ImageBubbleMenu/index.ts
@@ -0,0 +1 @@
+export { ImageBubbleMenu } from './ImageBubbleMenu'
diff --git a/src/components/Editor/EditorBubbleMenu/LinkForm/LinkForm.module.scss b/src/components/Editor/TextBubbleMenu/LinkForm/LinkForm.module.scss
similarity index 100%
rename from src/components/Editor/EditorBubbleMenu/LinkForm/LinkForm.module.scss
rename to src/components/Editor/TextBubbleMenu/LinkForm/LinkForm.module.scss
diff --git a/src/components/Editor/EditorBubbleMenu/LinkForm/LinkForm.tsx b/src/components/Editor/TextBubbleMenu/LinkForm/LinkForm.tsx
similarity index 100%
rename from src/components/Editor/EditorBubbleMenu/LinkForm/LinkForm.tsx
rename to src/components/Editor/TextBubbleMenu/LinkForm/LinkForm.tsx
diff --git a/src/components/Editor/EditorBubbleMenu/LinkForm/index.ts b/src/components/Editor/TextBubbleMenu/LinkForm/index.ts
similarity index 100%
rename from src/components/Editor/EditorBubbleMenu/LinkForm/index.ts
rename to src/components/Editor/TextBubbleMenu/LinkForm/index.ts
diff --git a/src/components/Editor/TextBubbleMenu/TextBubbleMenu.module.scss b/src/components/Editor/TextBubbleMenu/TextBubbleMenu.module.scss
new file mode 100644
index 00000000..12eb9215
--- /dev/null
+++ b/src/components/Editor/TextBubbleMenu/TextBubbleMenu.module.scss
@@ -0,0 +1,85 @@
+.bubbleMenu {
+ background: #fff;
+ box-shadow: 0 4px 10px rgba(#000, 0.25);
+
+ .bubbleMenuButton {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ flex-wrap: nowrap;
+ opacity: 0.5;
+ padding: 1rem;
+
+ .triangle {
+ margin-left: 4px;
+ }
+
+ .colorWheel {
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ border-radius: 50%;
+ background: #f6e3a1;
+ }
+ }
+
+ .bubbleMenuButtonActive {
+ opacity: 1;
+ }
+
+ .delimiter {
+ background: #999;
+ display: inline-block;
+ height: 1.4em;
+ margin: 0 0.2em;
+ vertical-align: text-bottom;
+ width: 1px;
+ }
+
+ .dropDownHolder {
+ position: relative;
+ cursor: pointer;
+ display: inline-flex;
+ flex-flow: row nowrap;
+ align-items: center;
+
+ .dropDown {
+ position: absolute;
+ padding: 6px;
+ top: calc(100% + 8px);
+ left: 50%;
+ transform: translateX(-50%);
+ box-shadow: 0 4px 10px rgb(0 0 0 / 25%);
+ background: #fff;
+ color: #898c94;
+
+ & > header {
+ font-size: 10px;
+ border-bottom: 1px solid #898c94;
+ }
+
+ .actions {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ gap: 12px;
+ flex-wrap: nowrap;
+ margin-bottom: 8px;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+
+ .bubbleMenuButton {
+ min-width: 40px;
+ }
+ }
+ }
+ }
+
+ .dropDownEnter,
+ .dropDownExit {
+ height: 0;
+ color: transparent;
+ }
+}
diff --git a/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx b/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx
new file mode 100644
index 00000000..3ffa2d08
--- /dev/null
+++ b/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx
@@ -0,0 +1,256 @@
+import { Switch, Match, createSignal, Show } from 'solid-js'
+import type { Editor } from '@tiptap/core'
+import styles from './TextBubbleMenu.module.scss'
+import { Icon } from '../../_shared/Icon'
+import { clsx } from 'clsx'
+import { createEditorTransaction } from 'solid-tiptap'
+import { useLocalize } from '../../../context/localize'
+import { InlineForm } from '../InlineForm'
+import validateImage from '../../../utils/validateUrl'
+
+type BubbleMenuProps = {
+ editor: Editor
+ ref: (el: HTMLDivElement) => void
+}
+
+export const TextBubbleMenu = (props: BubbleMenuProps) => {
+ const { t } = useLocalize()
+ const [textSizeBubbleOpen, setTextSizeBubbleOpen] = createSignal(false)
+ const [listBubbleOpen, setListBubbleOpen] = createSignal(false)
+ const [linkEditorOpen, setLinkEditorOpen] = createSignal(false)
+
+ const isActive = (name: string, attributes?: unknown) =>
+ createEditorTransaction(
+ () => props.editor,
+ (editor) => {
+ return editor && editor.isActive(name, attributes)
+ }
+ )
+
+ const isBold = isActive('bold')
+ const isItalic = isActive('italic')
+ const isH1 = isActive('heading', { level: 1 })
+ const isH2 = isActive('heading', { level: 2 })
+ const isH3 = isActive('heading', { level: 3 })
+ const isBlockQuote = isActive('blockquote')
+ const isOrderedList = isActive('isOrderedList')
+ const isBulletList = isActive('isBulletList')
+ const isLink = isActive('link')
+
+ const toggleLinkForm = () => {
+ setLinkEditorOpen(true)
+ }
+
+ const toggleTextSizePopup = () => {
+ if (listBubbleOpen()) {
+ setListBubbleOpen(false)
+ }
+
+ setTextSizeBubbleOpen((prev) => !prev)
+ }
+ const toggleListPopup = () => {
+ if (textSizeBubbleOpen()) {
+ setTextSizeBubbleOpen(false)
+ }
+
+ setListBubbleOpen((prev) => !prev)
+ }
+
+ const handleLinkFormSubmit = (value: string) => {
+ props.editor.chain().focus().setLink({ href: value }).run()
+ }
+
+ const currentUrl = createEditorTransaction(
+ () => props.editor,
+ (editor) => {
+ return (editor && editor.getAttributes('link').href) || ''
+ }
+ )
+
+ const handleClearLinkForm = () => {
+ if (currentUrl()) {
+ props.editor.chain().focus().unsetLink().run()
+ }
+ setLinkEditorOpen(false)
+ }
+
+ return (
+
+ )
+}
diff --git a/src/components/Editor/TextBubbleMenu/index.ts b/src/components/Editor/TextBubbleMenu/index.ts
new file mode 100644
index 00000000..5dd90ad9
--- /dev/null
+++ b/src/components/Editor/TextBubbleMenu/index.ts
@@ -0,0 +1 @@
+export { TextBubbleMenu } from './TextBubbleMenu'
diff --git a/src/components/Nav/HeaderAuth.tsx b/src/components/Nav/HeaderAuth.tsx
index ba568081..b5a49ac4 100644
--- a/src/components/Nav/HeaderAuth.tsx
+++ b/src/components/Nav/HeaderAuth.tsx
@@ -50,6 +50,7 @@ export const HeaderAuth = (props: HeaderAuthProps) => {
const showNotifications = createMemo(() => isAuthenticated() && !isEditorPage())
const showSaveButton = createMemo(() => isAuthenticated() && isEditorPage())
const showCreatePostButton = createMemo(() => isAuthenticated() && !isEditorPage())
+ const showAuthenticatedControls = createMemo(() => isAuthenticated() && isEditorPage())
const handleBurgerButtonClick = () => {
toggleEditorPanel()
@@ -120,7 +121,7 @@ export const HeaderAuth = (props: HeaderAuthProps) => {
diff --git a/src/graphql/query/article-load.ts b/src/graphql/query/article-load.ts
index 6bec8004..5073a1b9 100644
--- a/src/graphql/query/article-load.ts
+++ b/src/graphql/query/article-load.ts
@@ -3,7 +3,6 @@ import { gql } from '@urql/core'
export default gql`
query LoadShoutQuery($slug: String!) {
loadShout(slug: $slug) {
- _id: slug
id
title
subtitle
@@ -15,12 +14,11 @@ export default gql`
# community
mainTopic
topics {
- # id
+ id
title
body
slug
stat {
- _id: shouts
shouts
authors
followers
@@ -35,7 +33,6 @@ export default gql`
createdAt
publishedAt
stat {
- _id: viewed
viewed
reacted
rating