feat: Added preference to toggle Super note toolbar visibility. When toggled off, the toolbar will only be visible when text is selected as a floating toolbar. [skip e2e]
This commit is contained in:
@@ -45,6 +45,7 @@ export const PrefDefaults = {
|
|||||||
[PrefKey.ComponentPreferences]: {},
|
[PrefKey.ComponentPreferences]: {},
|
||||||
[PrefKey.ActiveThemes]: [],
|
[PrefKey.ActiveThemes]: [],
|
||||||
[PrefKey.ActiveComponents]: [],
|
[PrefKey.ActiveComponents]: [],
|
||||||
|
[PrefKey.AlwaysShowSuperToolbar]: true,
|
||||||
} satisfies {
|
} satisfies {
|
||||||
[key in PrefKey]: PrefValue[key]
|
[key in PrefKey]: PrefValue[key]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export enum PrefKey {
|
|||||||
ComponentPreferences = 'componentPreferences',
|
ComponentPreferences = 'componentPreferences',
|
||||||
ActiveThemes = 'activeThemes',
|
ActiveThemes = 'activeThemes',
|
||||||
ActiveComponents = 'activeComponents',
|
ActiveComponents = 'activeComponents',
|
||||||
|
AlwaysShowSuperToolbar = 'alwaysShowSuperToolbar',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PrefValue = {
|
export type PrefValue = {
|
||||||
@@ -87,4 +88,5 @@ export type PrefValue = {
|
|||||||
[PrefKey.ComponentPreferences]: AllComponentPreferences
|
[PrefKey.ComponentPreferences]: AllComponentPreferences
|
||||||
[PrefKey.ActiveThemes]: string[]
|
[PrefKey.ActiveThemes]: string[]
|
||||||
[PrefKey.ActiveComponents]: string[]
|
[PrefKey.ActiveComponents]: string[]
|
||||||
|
[PrefKey.AlwaysShowSuperToolbar]: boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { PrefKey, Platform, PrefDefaults } from '@standardnotes/snjs'
|
import { PrefKey, Platform } from '@standardnotes/snjs'
|
||||||
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||||
import { WebApplication } from '@/Application/WebApplication'
|
import { WebApplication } from '@/Application/WebApplication'
|
||||||
import { FunctionComponent, useState } from 'react'
|
import { FunctionComponent, useState } from 'react'
|
||||||
@@ -6,6 +6,8 @@ import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
|||||||
import Switch from '@/Components/Switch/Switch'
|
import Switch from '@/Components/Switch/Switch'
|
||||||
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||||
|
import usePreference from '@/Hooks/usePreference'
|
||||||
|
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
@@ -18,16 +20,15 @@ const Defaults: FunctionComponent<Props> = ({ application }) => {
|
|||||||
() => (application.getValue(AndroidConfirmBeforeExitKey) as boolean) ?? true,
|
() => (application.getValue(AndroidConfirmBeforeExitKey) as boolean) ?? true,
|
||||||
)
|
)
|
||||||
|
|
||||||
const [spellcheck, setSpellcheck] = useState(() =>
|
const isMobile = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
|
||||||
application.getPreference(PrefKey.EditorSpellcheck, PrefDefaults[PrefKey.EditorSpellcheck]),
|
|
||||||
)
|
|
||||||
|
|
||||||
const [addNoteToParentFolders, setAddNoteToParentFolders] = useState(() =>
|
const spellcheck = usePreference(PrefKey.EditorSpellcheck)
|
||||||
application.getPreference(PrefKey.NoteAddToParentFolders, PrefDefaults[PrefKey.NoteAddToParentFolders]),
|
|
||||||
)
|
const addNoteToParentFolders = usePreference(PrefKey.NoteAddToParentFolders)
|
||||||
|
|
||||||
|
const alwaysShowSuperToolbar = usePreference(PrefKey.AlwaysShowSuperToolbar)
|
||||||
|
|
||||||
const toggleSpellcheck = () => {
|
const toggleSpellcheck = () => {
|
||||||
setSpellcheck(!spellcheck)
|
|
||||||
application.toggleGlobalSpellcheck().catch(console.error)
|
application.toggleGlobalSpellcheck().catch(console.error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,11 +73,29 @@ const Defaults: FunctionComponent<Props> = ({ application }) => {
|
|||||||
<Switch
|
<Switch
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
application.setPreference(PrefKey.NoteAddToParentFolders, !addNoteToParentFolders).catch(console.error)
|
application.setPreference(PrefKey.NoteAddToParentFolders, !addNoteToParentFolders).catch(console.error)
|
||||||
setAddNoteToParentFolders(!addNoteToParentFolders)
|
|
||||||
}}
|
}}
|
||||||
checked={addNoteToParentFolders}
|
checked={addNoteToParentFolders}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<HorizontalSeparator classes="my-4" />
|
||||||
|
{!isMobile && (
|
||||||
|
<div className="flex justify-between gap-2 md:items-center">
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<Subtitle>Use always-visible toolbar in Super notes</Subtitle>
|
||||||
|
<Text>
|
||||||
|
When enabled, the Super toolbar will always be shown at the top of the note. It can be temporarily
|
||||||
|
toggled using Cmd/Ctrl+Shift+K. When disabled, the Super toolbar will only be shown as a floating
|
||||||
|
toolbar when text is selected.
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
onChange={() => {
|
||||||
|
application.setPreference(PrefKey.AlwaysShowSuperToolbar, !alwaysShowSuperToolbar).catch(console.error)
|
||||||
|
}}
|
||||||
|
checked={alwaysShowSuperToolbar}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</PreferencesSegment>
|
</PreferencesSegment>
|
||||||
</PreferencesGroup>
|
</PreferencesGroup>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import { IndentBlock, OutdentBlock } from '../Blocks/IndentOutdent'
|
|||||||
import { ParagraphBlock } from '../Blocks/Paragraph'
|
import { ParagraphBlock } from '../Blocks/Paragraph'
|
||||||
import { QuoteBlock } from '../Blocks/Quote'
|
import { QuoteBlock } from '../Blocks/Quote'
|
||||||
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
|
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
|
||||||
import { classNames } from '@standardnotes/snjs'
|
import { PrefKey, classNames } from '@standardnotes/snjs'
|
||||||
import { SUPER_TOGGLE_SEARCH, SUPER_TOGGLE_TOOLBAR } from '@standardnotes/ui-services'
|
import { SUPER_TOGGLE_SEARCH, SUPER_TOGGLE_TOOLBAR } from '@standardnotes/ui-services'
|
||||||
import { useApplication } from '@/Components/ApplicationProvider'
|
import { useApplication } from '@/Components/ApplicationProvider'
|
||||||
import { InsertRemoteImageDialog } from '../RemoteImagePlugin/RemoteImagePlugin'
|
import { InsertRemoteImageDialog } from '../RemoteImagePlugin/RemoteImagePlugin'
|
||||||
@@ -58,9 +58,13 @@ import Popover from '@/Components/Popover/Popover'
|
|||||||
import LexicalTableOfContents from '@lexical/react/LexicalTableOfContents'
|
import LexicalTableOfContents from '@lexical/react/LexicalTableOfContents'
|
||||||
import Menu from '@/Components/Menu/Menu'
|
import Menu from '@/Components/Menu/Menu'
|
||||||
import MenuItem, { MenuItemProps } from '@/Components/Menu/MenuItem'
|
import MenuItem, { MenuItemProps } from '@/Components/Menu/MenuItem'
|
||||||
import { remToPx } from '@/Utils'
|
import { debounce, remToPx } from '@/Utils'
|
||||||
import FloatingLinkEditor from './FloatingLinkEditor'
|
import FloatingLinkEditor from './FloatingLinkEditor'
|
||||||
import MenuItemSeparator from '@/Components/Menu/MenuItemSeparator'
|
import MenuItemSeparator from '@/Components/Menu/MenuItemSeparator'
|
||||||
|
import { useStateRef } from '@/Hooks/useStateRef'
|
||||||
|
import { getDOMRangeRect } from '../../Lexical/Utils/getDOMRangeRect'
|
||||||
|
import { getPositionedPopoverStyles } from '@/Components/Popover/GetPositionedPopoverStyles'
|
||||||
|
import usePreference from '@/Hooks/usePreference'
|
||||||
|
|
||||||
const TOGGLE_LINK_AND_EDIT_COMMAND = createCommand<string | null>('TOGGLE_LINK_AND_EDIT_COMMAND')
|
const TOGGLE_LINK_AND_EDIT_COMMAND = createCommand<string | null>('TOGGLE_LINK_AND_EDIT_COMMAND')
|
||||||
|
|
||||||
@@ -215,73 +219,174 @@ const ToolbarPlugin = () => {
|
|||||||
const [canUndo, setCanUndo] = useState(false)
|
const [canUndo, setCanUndo] = useState(false)
|
||||||
const [canRedo, setCanRedo] = useState(false)
|
const [canRedo, setCanRedo] = useState(false)
|
||||||
|
|
||||||
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
const alwaysShowToolbar = usePreference(PrefKey.AlwaysShowSuperToolbar)
|
||||||
|
|
||||||
|
const [isToolbarFixedToTop, setIsToolbarFixedToTop] = useState(alwaysShowToolbar)
|
||||||
|
const isToolbarFixedRef = useStateRef(isToolbarFixedToTop)
|
||||||
|
|
||||||
|
const updateToolbarFloatingPosition = useCallback(() => {
|
||||||
|
const selection = $getSelection()
|
||||||
|
if (!$isRangeSelection(selection)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMobile) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isToolbarFixedRef.current) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const containerElement = containerRef.current
|
||||||
|
|
||||||
|
if (!containerElement) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selection.getTextContent() === '') {
|
||||||
|
containerElement.style.removeProperty('opacity')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const nativeSelection = window.getSelection()
|
||||||
|
const rootElement = activeEditor.getRootElement()
|
||||||
|
|
||||||
|
if (nativeSelection !== null && rootElement !== null && rootElement.contains(nativeSelection.anchorNode)) {
|
||||||
|
const rangeRect = getDOMRangeRect(nativeSelection, rootElement)
|
||||||
|
const containerRect = containerElement.getBoundingClientRect()
|
||||||
|
const rootRect = rootElement.getBoundingClientRect()
|
||||||
|
|
||||||
|
const calculatedStyles = getPositionedPopoverStyles({
|
||||||
|
align: 'start',
|
||||||
|
side: 'top',
|
||||||
|
anchorRect: rangeRect,
|
||||||
|
popoverRect: containerRect,
|
||||||
|
documentRect: rootRect,
|
||||||
|
offset: 8,
|
||||||
|
maxHeightFunction: () => 'none',
|
||||||
|
})
|
||||||
|
|
||||||
|
if (calculatedStyles) {
|
||||||
|
Object.entries(calculatedStyles).forEach(([key, value]) => {
|
||||||
|
if (key === 'transform') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
containerElement.style.setProperty(key, value)
|
||||||
|
})
|
||||||
|
containerElement.style.setProperty('opacity', '1')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [activeEditor, isMobile, isToolbarFixedRef])
|
||||||
|
|
||||||
const $updateToolbar = useCallback(() => {
|
const $updateToolbar = useCallback(() => {
|
||||||
const selection = $getSelection()
|
const selection = $getSelection()
|
||||||
if ($isRangeSelection(selection)) {
|
if (!$isRangeSelection(selection)) {
|
||||||
const anchorNode = selection.anchor.getNode()
|
return
|
||||||
let element =
|
}
|
||||||
anchorNode.getKey() === 'root'
|
|
||||||
? anchorNode
|
|
||||||
: $findMatchingParent(anchorNode, (e) => {
|
|
||||||
const parent = e.getParent()
|
|
||||||
return parent !== null && $isRootOrShadowRoot(parent)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (element === null) {
|
const anchorNode = selection.anchor.getNode()
|
||||||
element = anchorNode.getTopLevelElementOrThrow()
|
let element =
|
||||||
}
|
anchorNode.getKey() === 'root'
|
||||||
|
? anchorNode
|
||||||
|
: $findMatchingParent(anchorNode, (e) => {
|
||||||
|
const parent = e.getParent()
|
||||||
|
return parent !== null && $isRootOrShadowRoot(parent)
|
||||||
|
})
|
||||||
|
|
||||||
const elementKey = element.getKey()
|
if (element === null) {
|
||||||
const elementDOM = activeEditor.getElementByKey(elementKey)
|
element = anchorNode.getTopLevelElementOrThrow()
|
||||||
|
}
|
||||||
|
|
||||||
// Update text format
|
const elementKey = element.getKey()
|
||||||
setIsBold(selection.hasFormat('bold'))
|
const elementDOM = activeEditor.getElementByKey(elementKey)
|
||||||
setIsItalic(selection.hasFormat('italic'))
|
|
||||||
setIsUnderline(selection.hasFormat('underline'))
|
|
||||||
setIsStrikethrough(selection.hasFormat('strikethrough'))
|
|
||||||
setIsSubscript(selection.hasFormat('subscript'))
|
|
||||||
setIsSuperscript(selection.hasFormat('superscript'))
|
|
||||||
setIsCode(selection.hasFormat('code'))
|
|
||||||
setIsHighlight(selection.hasFormat('highlight'))
|
|
||||||
|
|
||||||
// Update links
|
// Update text format
|
||||||
const node = getSelectedNode(selection)
|
setIsBold(selection.hasFormat('bold'))
|
||||||
const parent = node.getParent()
|
setIsItalic(selection.hasFormat('italic'))
|
||||||
if ($isLinkNode(parent) || $isLinkNode(node)) {
|
setIsUnderline(selection.hasFormat('underline'))
|
||||||
setIsLink(true)
|
setIsStrikethrough(selection.hasFormat('strikethrough'))
|
||||||
|
setIsSubscript(selection.hasFormat('subscript'))
|
||||||
|
setIsSuperscript(selection.hasFormat('superscript'))
|
||||||
|
setIsCode(selection.hasFormat('code'))
|
||||||
|
setIsHighlight(selection.hasFormat('highlight'))
|
||||||
|
|
||||||
|
// Update links
|
||||||
|
const node = getSelectedNode(selection)
|
||||||
|
const parent = node.getParent()
|
||||||
|
if ($isLinkNode(parent) || $isLinkNode(node)) {
|
||||||
|
setIsLink(true)
|
||||||
|
} else {
|
||||||
|
setIsLink(false)
|
||||||
|
}
|
||||||
|
setLinkUrl($isLinkNode(parent) ? parent.getURL() : $isLinkNode(node) ? node.getURL() : '')
|
||||||
|
if ($isAutoLinkNode(parent) || $isAutoLinkNode(node)) {
|
||||||
|
setIsAutoLink(true)
|
||||||
|
} else {
|
||||||
|
setIsAutoLink(false)
|
||||||
|
}
|
||||||
|
if ($isLinkTextNode(node, selection)) {
|
||||||
|
setIsLinkText(true)
|
||||||
|
setLinkText(node.getTextContent())
|
||||||
|
} else {
|
||||||
|
setIsLinkText(false)
|
||||||
|
setLinkText('')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementDOM !== null) {
|
||||||
|
if ($isListNode(element)) {
|
||||||
|
const parentList = $getNearestNodeOfType<ListNode>(anchorNode, ListNode)
|
||||||
|
const type = parentList ? parentList.getListType() : element.getListType()
|
||||||
|
setBlockType(type)
|
||||||
} else {
|
} else {
|
||||||
setIsLink(false)
|
const type = $isHeadingNode(element) ? element.getTag() : element.getType()
|
||||||
}
|
if (type in blockTypeToBlockName) {
|
||||||
setLinkUrl($isLinkNode(parent) ? parent.getURL() : $isLinkNode(node) ? node.getURL() : '')
|
setBlockType(type as keyof typeof blockTypeToBlockName)
|
||||||
if ($isAutoLinkNode(parent) || $isAutoLinkNode(node)) {
|
|
||||||
setIsAutoLink(true)
|
|
||||||
} else {
|
|
||||||
setIsAutoLink(false)
|
|
||||||
}
|
|
||||||
if ($isLinkTextNode(node, selection)) {
|
|
||||||
setIsLinkText(true)
|
|
||||||
setLinkText(node.getTextContent())
|
|
||||||
} else {
|
|
||||||
setIsLinkText(false)
|
|
||||||
setLinkText('')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elementDOM !== null) {
|
|
||||||
if ($isListNode(element)) {
|
|
||||||
const parentList = $getNearestNodeOfType<ListNode>(anchorNode, ListNode)
|
|
||||||
const type = parentList ? parentList.getListType() : element.getListType()
|
|
||||||
setBlockType(type)
|
|
||||||
} else {
|
|
||||||
const type = $isHeadingNode(element) ? element.getTag() : element.getType()
|
|
||||||
if (type in blockTypeToBlockName) {
|
|
||||||
setBlockType(type as keyof typeof blockTypeToBlockName)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setElementFormat(($isElementNode(node) ? node.getFormatType() : parent?.getFormatType()) || 'left')
|
|
||||||
}
|
}
|
||||||
}, [activeEditor])
|
|
||||||
|
setElementFormat(($isElementNode(node) ? node.getFormatType() : parent?.getFormatType()) || 'left')
|
||||||
|
|
||||||
|
updateToolbarFloatingPosition()
|
||||||
|
}, [activeEditor, updateToolbarFloatingPosition])
|
||||||
|
|
||||||
|
const clearContainerFloatingStyles = useCallback(() => {
|
||||||
|
const containerElement = containerRef.current
|
||||||
|
if (!containerElement) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
containerElement.style.removeProperty('--translate-x')
|
||||||
|
containerElement.style.removeProperty('--translate-y')
|
||||||
|
containerElement.style.removeProperty('transform')
|
||||||
|
containerElement.style.removeProperty('transform-origin')
|
||||||
|
containerElement.style.removeProperty('opacity')
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const scrollerElem = activeEditor.getRootElement()
|
||||||
|
|
||||||
|
const update = () => {
|
||||||
|
activeEditor.getEditorState().read(() => {
|
||||||
|
updateToolbarFloatingPosition()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const debouncedUpdate = debounce(update, 50)
|
||||||
|
|
||||||
|
window.addEventListener('resize', debouncedUpdate)
|
||||||
|
if (scrollerElem) {
|
||||||
|
scrollerElem.addEventListener('scroll', debouncedUpdate)
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', debouncedUpdate)
|
||||||
|
if (scrollerElem) {
|
||||||
|
scrollerElem.removeEventListener('scroll', debouncedUpdate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [activeEditor, updateToolbarFloatingPosition])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return mergeRegister(
|
return mergeRegister(
|
||||||
@@ -379,14 +484,12 @@ const ToolbarPlugin = () => {
|
|||||||
)
|
)
|
||||||
}, [activeEditor, isLink])
|
}, [activeEditor, isLink])
|
||||||
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null)
|
|
||||||
const dismissButtonRef = useRef<HTMLButtonElement>(null)
|
const dismissButtonRef = useRef<HTMLButtonElement>(null)
|
||||||
|
|
||||||
const [isFocusInEditor, setIsFocusInEditor] = useState(false)
|
const [isFocusInEditor, setIsFocusInEditor] = useState(false)
|
||||||
const [isFocusInToolbar, setIsFocusInToolbar] = useState(false)
|
const [isFocusInToolbar, setIsFocusInToolbar] = useState(false)
|
||||||
const isFocusInEditorOrToolbar = isFocusInEditor || isFocusInToolbar
|
const canShowToolbarOnMobile = isFocusInEditor || isFocusInToolbar
|
||||||
const [isToolbarVisible, setIsToolbarVisible] = useState(true)
|
const canShowAllItems = isMobile || isToolbarFixedToTop
|
||||||
const canShowToolbar = isMobile ? isFocusInEditorOrToolbar : isToolbarVisible
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const container = containerRef.current
|
const container = containerRef.current
|
||||||
@@ -438,24 +541,32 @@ const ToolbarPlugin = () => {
|
|||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
event.preventDefault()
|
if (!alwaysShowToolbar) {
|
||||||
|
|
||||||
if (!isToolbarVisible) {
|
|
||||||
setIsToolbarVisible(true)
|
|
||||||
toolbarStore.move(toolbarStore.first())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const isFocusInContainer = containerRef.current?.contains(document.activeElement)
|
event.preventDefault()
|
||||||
if (isFocusInContainer) {
|
|
||||||
setIsToolbarVisible(false)
|
if (!isToolbarFixedToTop) {
|
||||||
editor.focus()
|
setIsToolbarFixedToTop(true)
|
||||||
} else {
|
clearContainerFloatingStyles()
|
||||||
toolbarStore.move(toolbarStore.first())
|
toolbarStore.move(toolbarStore.first())
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
setIsToolbarFixedToTop(false)
|
||||||
|
editor.focus()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}, [application.keyboardService, editor, isMobile, isToolbarVisible, toolbarStore])
|
}, [
|
||||||
|
alwaysShowToolbar,
|
||||||
|
application.keyboardService,
|
||||||
|
clearContainerFloatingStyles,
|
||||||
|
editor,
|
||||||
|
isMobile,
|
||||||
|
isToolbarFixedToTop,
|
||||||
|
toolbarStore,
|
||||||
|
])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -463,8 +574,15 @@ const ToolbarPlugin = () => {
|
|||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'bg-contrast',
|
'bg-contrast',
|
||||||
'md:w-full md:border-b md:border-border md:px-1 md:py-1 md:translucent-ui:border-[--popover-border-color] md:translucent-ui:bg-[--popover-background-color] md:translucent-ui:[backdrop-filter:var(--popover-backdrop-filter)]',
|
!isEditable ? 'hidden opacity-0' : '',
|
||||||
!canShowToolbar || !isEditable ? 'hidden' : '',
|
isMobile && !canShowToolbarOnMobile ? 'hidden' : '',
|
||||||
|
!isMobile &&
|
||||||
|
'border-b border-border translucent-ui:border-[--popover-border-color] translucent-ui:bg-[--popover-background-color] translucent-ui:[backdrop-filter:var(--popover-backdrop-filter)]',
|
||||||
|
!isMobile
|
||||||
|
? !isToolbarFixedToTop
|
||||||
|
? 'fixed left-0 top-0 z-tooltip translate-x-[--translate-x] translate-y-[--translate-y] rounded border py-0.5 opacity-0'
|
||||||
|
: 'w-full px-1 py-1'
|
||||||
|
: '',
|
||||||
)}
|
)}
|
||||||
id="super-mobile-toolbar"
|
id="super-mobile-toolbar"
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
@@ -487,30 +605,34 @@ const ToolbarPlugin = () => {
|
|||||||
ref={toolbarRef}
|
ref={toolbarRef}
|
||||||
store={toolbarStore}
|
store={toolbarStore}
|
||||||
>
|
>
|
||||||
<ToolbarButton
|
{canShowAllItems && (
|
||||||
name="Table of Contents"
|
<>
|
||||||
iconName="toc"
|
<ToolbarButton
|
||||||
active={isTOCOpen}
|
name="Table of Contents"
|
||||||
onSelect={() => setIsTOCOpen(!isTOCOpen)}
|
iconName="toc"
|
||||||
ref={tocAnchorRef}
|
active={isTOCOpen}
|
||||||
/>
|
onSelect={() => setIsTOCOpen(!isTOCOpen)}
|
||||||
<ToolbarButton
|
ref={tocAnchorRef}
|
||||||
name="Search"
|
/>
|
||||||
iconName="search"
|
<ToolbarButton
|
||||||
onSelect={() => application.keyboardService.triggerCommand(SUPER_TOGGLE_SEARCH)}
|
name="Search"
|
||||||
/>
|
iconName="search"
|
||||||
<ToolbarButton
|
onSelect={() => application.keyboardService.triggerCommand(SUPER_TOGGLE_SEARCH)}
|
||||||
name="Undo"
|
/>
|
||||||
iconName="undo"
|
<ToolbarButton
|
||||||
disabled={!canUndo}
|
name="Undo"
|
||||||
onSelect={() => editor.dispatchCommand(UNDO_COMMAND, undefined)}
|
iconName="undo"
|
||||||
/>
|
disabled={!canUndo}
|
||||||
<ToolbarButton
|
onSelect={() => editor.dispatchCommand(UNDO_COMMAND, undefined)}
|
||||||
name="Redo"
|
/>
|
||||||
iconName="redo"
|
<ToolbarButton
|
||||||
disabled={!canRedo}
|
name="Redo"
|
||||||
onSelect={() => editor.dispatchCommand(REDO_COMMAND, undefined)}
|
iconName="redo"
|
||||||
/>
|
disabled={!canRedo}
|
||||||
|
onSelect={() => editor.dispatchCommand(REDO_COMMAND, undefined)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<ToolbarButton
|
<ToolbarButton
|
||||||
name="Bold"
|
name="Bold"
|
||||||
iconName="bold"
|
iconName="bold"
|
||||||
@@ -586,17 +708,19 @@ const ToolbarPlugin = () => {
|
|||||||
iconName={OutdentBlock.iconName}
|
iconName={OutdentBlock.iconName}
|
||||||
onSelect={() => OutdentBlock.onSelect(editor)}
|
onSelect={() => OutdentBlock.onSelect(editor)}
|
||||||
/>
|
/>
|
||||||
<ToolbarButton
|
{canShowAllItems && (
|
||||||
name="Insert"
|
<ToolbarButton
|
||||||
onSelect={() => {
|
name="Insert"
|
||||||
setIsInsertMenuOpen(!isInsertMenuOpen)
|
onSelect={() => {
|
||||||
}}
|
setIsInsertMenuOpen(!isInsertMenuOpen)
|
||||||
ref={insertAnchorRef}
|
}}
|
||||||
className={isInsertMenuOpen ? 'md:bg-default' : ''}
|
ref={insertAnchorRef}
|
||||||
>
|
className={isInsertMenuOpen ? 'md:bg-default' : ''}
|
||||||
<Icon type="add" size="custom" className="h-4 w-4 md:h-3.5 md:w-3.5" />
|
>
|
||||||
<Icon type="chevron-down" size="custom" className="ml-2 h-4 w-4 md:h-3.5 md:w-3.5" />
|
<Icon type="add" size="custom" className="h-4 w-4 md:h-3.5 md:w-3.5" />
|
||||||
</ToolbarButton>
|
<Icon type="chevron-down" size="custom" className="ml-2 h-4 w-4 md:h-3.5 md:w-3.5" />
|
||||||
|
</ToolbarButton>
|
||||||
|
)}
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
{isMobile && (
|
{isMobile && (
|
||||||
<button
|
<button
|
||||||
|
|||||||
Reference in New Issue
Block a user