mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-03-25 10:02:27 -04:00
119 lines
3.5 KiB
TypeScript
119 lines
3.5 KiB
TypeScript
import {FaceSmileIcon} from '@heroicons/react/24/outline'
|
|
import {CodeBracketIcon, PhotoIcon} from '@heroicons/react/24/solid'
|
|
import {Editor} from '@tiptap/react'
|
|
import {MouseEventHandler, useState} from 'react'
|
|
import {Row} from 'web/components/layout/row'
|
|
import {useT} from 'web/lib/locale'
|
|
|
|
import {FileUploadButton} from '../buttons/file-upload-button'
|
|
import {LoadingIndicator} from '../widgets/loading-indicator'
|
|
import {Tooltip} from '../widgets/tooltip'
|
|
import {EmbedModal} from './embed-modal'
|
|
import type {UploadMutation} from './upload-extension'
|
|
|
|
/* Toolbar, with buttons for images and embeds */
|
|
export function StickyFormatMenu(props: {
|
|
editor: Editor | null
|
|
hideEmbed?: boolean
|
|
children?: React.ReactNode
|
|
}) {
|
|
const {editor, hideEmbed, children} = props
|
|
const upload = editor?.storage.upload.mutation
|
|
const t = useT()
|
|
|
|
const [iframeOpen, setIframeOpen] = useState(false)
|
|
|
|
return (
|
|
<Row className="text-ink-600 h-8 items-center">
|
|
<UploadButton key={'upload-button'} upload={upload} />
|
|
{!hideEmbed && (
|
|
<ToolbarButton
|
|
key={'embed-button'}
|
|
label={t('sticky_format_menu.add_embed', 'Add embed')}
|
|
onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
|
|
e.stopPropagation()
|
|
e.preventDefault()
|
|
setIframeOpen(true)
|
|
}}
|
|
>
|
|
<CodeBracketIcon className="h-5 w-5" aria-hidden="true" />
|
|
</ToolbarButton>
|
|
)}
|
|
<ToolbarButton
|
|
key={'emoji-button'}
|
|
label={t('sticky_format_menu.add_emoji', 'Add emoji')}
|
|
onClick={() => insertEmoji(editor)}
|
|
>
|
|
<FaceSmileIcon className="h-5 w-5" />
|
|
</ToolbarButton>
|
|
|
|
<EmbedModal editor={editor} open={iframeOpen} setOpen={setIframeOpen} />
|
|
<div className="grow" />
|
|
{children}
|
|
</Row>
|
|
)
|
|
}
|
|
|
|
function UploadButton(props: {upload: UploadMutation}) {
|
|
const {upload} = props
|
|
const t = useT()
|
|
|
|
return (
|
|
<Tooltip
|
|
text={t('sticky_format_menu.upload_image', 'Upload image')}
|
|
className="flex items-stretch"
|
|
placement="bottom"
|
|
>
|
|
<FileUploadButton
|
|
onFiles={(files) => upload?.mutate(files)}
|
|
className="hover:text-ink-700 disabled:text-ink-300 active:text-ink-800 text-ink-400 relative flex rounded px-3 py-1 pl-4 transition-colors"
|
|
>
|
|
<Row className={'items-center justify-start gap-2'}>
|
|
<PhotoIcon className="h-5 w-5" aria-hidden="true" />
|
|
{upload?.isLoading && (
|
|
<LoadingIndicator
|
|
className="absolute bottom-0 left-0 right-0 top-0"
|
|
spinnerClassName="!h-6 !w-6 !border-2"
|
|
/>
|
|
)}
|
|
</Row>
|
|
</FileUploadButton>
|
|
</Tooltip>
|
|
)
|
|
}
|
|
|
|
function ToolbarButton(props: {
|
|
label: string
|
|
onClick: MouseEventHandler
|
|
children: React.ReactNode
|
|
}) {
|
|
const {label, onClick, children} = props
|
|
|
|
return (
|
|
<Tooltip text={label} className="flex items-stretch" placement="bottom">
|
|
<button
|
|
type="button"
|
|
onClick={onClick}
|
|
className="text-ink-400 hover:text-ink-700 active:text-ink-800 disabled:text-ink-300 flex rounded px-3 py-1 transition-colors"
|
|
>
|
|
{children}
|
|
</button>
|
|
</Tooltip>
|
|
)
|
|
}
|
|
|
|
/** insert a colon, and a space if necessary, to bring up emoji selector */
|
|
const insertEmoji = (editor: Editor | null) => {
|
|
if (!editor) return
|
|
|
|
const textBefore = editor.view.state.selection.$from.nodeBefore?.text
|
|
const addSpace = textBefore && !textBefore.endsWith(' ')
|
|
|
|
editor
|
|
.chain()
|
|
.focus()
|
|
.createParagraphNear()
|
|
.insertContent(addSpace ? ' :' : ':')
|
|
.run()
|
|
}
|