Files
Homarr/src/widgets/notebook/NotebookEditor.tsx

171 lines
4.8 KiB
TypeScript
Raw Normal View History

2023-09-03 17:52:35 +02:00
import { ActionIcon, ScrollArea } from '@mantine/core';
import { useDebouncedValue } from '@mantine/hooks';
import { Link, RichTextEditor } from '@mantine/tiptap';
2023-09-03 17:52:35 +02:00
import { IconEdit, IconEditOff } from '@tabler/icons-react';
import { BubbleMenu, useEditor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
2023-09-03 17:52:35 +02:00
import { useState } from 'react';
import { useConfigStore } from '~/config/store';
import { useColorTheme } from '~/tools/color';
import { api } from '~/utils/api';
import { useEditModeStore } from '../../components/Dashboard/Views/useEditModeStore';
import { useConfigContext } from '../../config/provider';
import { WidgetLoading } from '../loading';
import { INotebookWidget } from './NotebookWidgetTile';
Link.configure({
openOnClick: true,
});
export function Editor({ widget }: { widget: INotebookWidget }) {
const [content, setContent] = useState(widget.properties.content);
const { enabled } = useEditModeStore();
const [isEditing, setIsEditing] = useState(false);
const { config, name: configName } = useConfigContext();
const updateConfig = useConfigStore((x) => x.updateConfig);
const { primaryColor } = useColorTheme();
const { mutateAsync } = api.notebook.update.useMutation();
const [debouncedContent] = useDebouncedValue(content, 500);
const editor = useEditor({
extensions: [StarterKit, Link],
content,
editable: false,
onUpdate: (e) => {
setContent(e.editor.getHTML());
},
});
const handleEditToggle = (previous: boolean) => {
const current = !previous;
if (!editor) return current;
editor.setEditable(current);
updateConfig(
configName!,
(previous) => {
const currentWidget = previous.widgets.find((x) => x.id === widget.id);
currentWidget!.properties.content = debouncedContent;
return {
...previous,
widgets: [
...previous.widgets.filter((iterationWidget) => iterationWidget.id !== widget.id),
currentWidget!,
],
};
},
true
);
void mutateAsync({
configName: configName!,
content: debouncedContent,
widgetId: widget.id,
});
return current;
};
if (!config || !configName) return <WidgetLoading />;
return (
<>
<RichTextEditor
p={0}
mt={0}
2023-09-03 17:52:35 +02:00
h="100%"
editor={editor}
styles={(theme) => ({
root: {
'& .ProseMirror': {
padding: '0 !important',
},
2023-09-03 17:52:35 +02:00
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : 'white',
border: 'none',
2023-09-03 17:52:35 +02:00
borderRadius: '0.5rem',
display: 'flex',
flexDirection: 'column',
},
toolbar: {
2023-09-03 17:52:35 +02:00
backgroundColor: 'transparent',
padding: '0.5rem',
},
content: {
2023-09-03 17:52:35 +02:00
backgroundColor: 'transparent',
padding: '0.5rem',
},
})}
>
<RichTextEditor.Toolbar
style={{
display: isEditing && widget.properties.showToolbar === true ? 'flex' : 'none',
}}
>
<RichTextEditor.ControlsGroup>
<RichTextEditor.Bold />
<RichTextEditor.Italic />
<RichTextEditor.Strikethrough />
<RichTextEditor.ClearFormatting />
<RichTextEditor.Code />
</RichTextEditor.ControlsGroup>
<RichTextEditor.ControlsGroup>
<RichTextEditor.H1 />
<RichTextEditor.H2 />
<RichTextEditor.H3 />
<RichTextEditor.H4 />
</RichTextEditor.ControlsGroup>
<RichTextEditor.ControlsGroup>
<RichTextEditor.Blockquote />
<RichTextEditor.Hr />
<RichTextEditor.BulletList />
<RichTextEditor.OrderedList />
</RichTextEditor.ControlsGroup>
<RichTextEditor.ControlsGroup>
<RichTextEditor.Link />
<RichTextEditor.Unlink />
</RichTextEditor.ControlsGroup>
</RichTextEditor.Toolbar>
{editor && (
<BubbleMenu editor={editor}>
<RichTextEditor.ControlsGroup>
<RichTextEditor.Bold />
<RichTextEditor.Italic />
<RichTextEditor.Link />
</RichTextEditor.ControlsGroup>
</BubbleMenu>
)}
2023-09-03 17:52:35 +02:00
<ScrollArea>
<RichTextEditor.Content />
</ScrollArea>
</RichTextEditor>
2023-09-03 17:52:35 +02:00
{!enabled && (
<ActionIcon
style={{
zIndex: 1,
}}
top={7}
right={7}
pos="absolute"
color={primaryColor}
variant="light"
size={30}
radius={'md'}
onClick={() => setIsEditing(handleEditToggle)}
>
{isEditing ? <IconEditOff size={20} /> : <IconEdit size={20} />}
</ActionIcon>
)}
</>
);
}