mirror of
https://github.com/penxio/penx.git
synced 2026-04-19 03:03:06 -04:00
152 lines
3.8 KiB
TypeScript
152 lines
3.8 KiB
TypeScript
import {
|
|
CheckSquare,
|
|
Code,
|
|
Heading1,
|
|
Heading2,
|
|
Heading3,
|
|
ImageIcon,
|
|
List,
|
|
ListOrdered,
|
|
MessageSquarePlus,
|
|
Text,
|
|
TextQuote,
|
|
} from 'lucide-react'
|
|
import { Command, createSuggestionItems, renderItems } from 'novel/extensions'
|
|
import { uploadFn } from './image-upload'
|
|
|
|
export const suggestionItems = createSuggestionItems([
|
|
{
|
|
title: 'Text',
|
|
description: 'Just start typing with plain text.',
|
|
searchTerms: ['p', 'paragraph'],
|
|
icon: <Text size={18} />,
|
|
command: ({ editor, range }) => {
|
|
editor
|
|
.chain()
|
|
.focus()
|
|
.deleteRange(range)
|
|
.toggleNode('paragraph', 'paragraph')
|
|
.run()
|
|
},
|
|
},
|
|
{
|
|
title: 'To-do List',
|
|
description: 'Track tasks with a to-do list.',
|
|
searchTerms: ['todo', 'task', 'list', 'check', 'checkbox'],
|
|
icon: <CheckSquare size={18} />,
|
|
command: ({ editor, range }) => {
|
|
editor.chain().focus().deleteRange(range).toggleTaskList().run()
|
|
},
|
|
},
|
|
{
|
|
title: 'Heading 1',
|
|
description: 'Big section heading.',
|
|
searchTerms: ['title', 'big', 'large'],
|
|
icon: <Heading1 size={18} />,
|
|
command: ({ editor, range }) => {
|
|
editor
|
|
.chain()
|
|
.focus()
|
|
.deleteRange(range)
|
|
.setNode('heading', { level: 1 })
|
|
.run()
|
|
},
|
|
},
|
|
{
|
|
title: 'Heading 2',
|
|
description: 'Medium section heading.',
|
|
searchTerms: ['subtitle', 'medium'],
|
|
icon: <Heading2 size={18} />,
|
|
command: ({ editor, range }) => {
|
|
editor
|
|
.chain()
|
|
.focus()
|
|
.deleteRange(range)
|
|
.setNode('heading', { level: 2 })
|
|
.run()
|
|
},
|
|
},
|
|
{
|
|
title: 'Heading 3',
|
|
description: 'Small section heading.',
|
|
searchTerms: ['subtitle', 'small'],
|
|
icon: <Heading3 size={18} />,
|
|
command: ({ editor, range }) => {
|
|
editor
|
|
.chain()
|
|
.focus()
|
|
.deleteRange(range)
|
|
.setNode('heading', { level: 3 })
|
|
.run()
|
|
},
|
|
},
|
|
{
|
|
title: 'Bullet List',
|
|
description: 'Create a simple bullet list.',
|
|
searchTerms: ['unordered', 'point'],
|
|
icon: <List size={18} />,
|
|
command: ({ editor, range }) => {
|
|
editor.chain().focus().deleteRange(range).toggleBulletList().run()
|
|
},
|
|
},
|
|
{
|
|
title: 'Numbered List',
|
|
description: 'Create a list with numbering.',
|
|
searchTerms: ['ordered'],
|
|
icon: <ListOrdered size={18} />,
|
|
command: ({ editor, range }) => {
|
|
editor.chain().focus().deleteRange(range).toggleOrderedList().run()
|
|
},
|
|
},
|
|
{
|
|
title: 'Quote',
|
|
description: 'Capture a quote.',
|
|
searchTerms: ['blockquote'],
|
|
icon: <TextQuote size={18} />,
|
|
command: ({ editor, range }) =>
|
|
editor
|
|
.chain()
|
|
.focus()
|
|
.deleteRange(range)
|
|
.toggleNode('paragraph', 'paragraph')
|
|
.toggleBlockquote()
|
|
.run(),
|
|
},
|
|
{
|
|
title: 'Code',
|
|
description: 'Capture a code snippet.',
|
|
searchTerms: ['codeblock'],
|
|
icon: <Code size={18} />,
|
|
command: ({ editor, range }) =>
|
|
editor.chain().focus().deleteRange(range).toggleCodeBlock().run(),
|
|
},
|
|
{
|
|
title: 'Image',
|
|
description: 'Upload an image from your computer.',
|
|
searchTerms: ['photo', 'picture', 'media'],
|
|
icon: <ImageIcon size={18} />,
|
|
command: ({ editor, range }) => {
|
|
editor.chain().focus().deleteRange(range).run()
|
|
// upload image
|
|
const input = document.createElement('input')
|
|
input.type = 'file'
|
|
input.accept = 'image/*'
|
|
input.onchange = async () => {
|
|
if (input.files?.length) {
|
|
const file = input.files[0]
|
|
const pos = editor.view.state.selection.from
|
|
uploadFn(file, editor.view, pos)
|
|
}
|
|
}
|
|
input.click()
|
|
},
|
|
},
|
|
])
|
|
|
|
export const slashCommand = Command.configure({
|
|
suggestion: {
|
|
items: () => suggestionItems,
|
|
render: renderItems,
|
|
},
|
|
})
|