Skip to content

Commit

Permalink
refactor as dropdown menu, add variable functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
buckhalt committed Nov 26, 2024
1 parent 0ef8ca5 commit 83ea60b
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 40 deletions.
5 changes: 5 additions & 0 deletions components/DropdownMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,18 @@ const DropdownLabel = ({ children }: PropsWithChildren) => (
</DropdownMenuPrimitive.Label>
);

const DropdownSeparator = () => (
<DropdownMenuPrimitive.Separator className="border-t border-surface-2" />
);

const DropdownMenu = {
Root: DropdownMenuPrimitive.Root,
RadioGroup: DropdownMenuPrimitive.RadioGroup,
Trigger: DropdownTrigger,
Content: DropdownMenuContent,
Label: DropdownLabel,
Item: DropdownItem,
Separator: DropdownSeparator,
};

export default DropdownMenu;
77 changes: 51 additions & 26 deletions components/block-editor/PlusMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,68 @@
import { type Editor } from '@tiptap/react';
import { Plus } from 'lucide-react';
import { createVariableNode } from '~/lib/block-editor/extensions/Variable/utils';
import { type TiptapContent, contentMap } from '~/lib/block-editor/types';
import devProtocol from '~/lib/db/sample-data/dev-protocol';
import { type TVariableDefinition } from '~/schemas/protocol/variables';
import { Button } from '../Button';
import Popover from '../Popover';
import Heading from '../typography/Heading';
import DropdownMenu from '../DropdownMenu';

const Menu = ({ editor }: { editor: Editor | null }) => {
export default function PlusMenu({ editor }: { editor: Editor | null }) {
if (!editor) return null;
const { variables } = devProtocol;

const handleCommand = (type: TiptapContent) => () => {
const endPos = editor.state.doc.content.size;
editor.chain().focus().insertContentAt(endPos, contentMap[type]).run();
editor.view.focus();
};

const addVariable = (variable: TVariableDefinition) => {
const endPos = editor.state.doc.content.size;
const variableNode = createVariableNode({
newVariable: variable,
view: editor.view,
key: variable.label.en,
});
const transaction = editor.view.state.tr.insert(endPos, variableNode);
editor.view.dispatch(transaction);
};

return (
<div className="grid gap-2 overflow-scroll p-2">
<Heading variant="h4">Add block</Heading>
{Object.keys(contentMap).map((type) => (
<Button
key={type}
onClick={handleCommand(type as TiptapContent)}
variant="outline"
size="sm"
color="primary"
>
{type}
<DropdownMenu.Root>
<DropdownMenu.Trigger>
<Button variant="outline" size="icon" color="primary">
<Plus />
</Button>
))}
</div>
);
};
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.Label>Add content</DropdownMenu.Label>
{Object.keys(contentMap).map((type) => (
<DropdownMenu.Item
key={type}
onSelect={handleCommand(type as TiptapContent)}
textValue={type}
>
{type}
</DropdownMenu.Item>
))}

// plus button that renders after the editor content and between nodes
export default function PlusMenu({ editor }: { editor: Editor | null }) {
return (
<Popover content={<Menu editor={editor} />}>
<Button variant="outline" size="icon" color="primary">
<Plus />
</Button>
</Popover>
<DropdownMenu.Separator />

<DropdownMenu.Label>Add variable</DropdownMenu.Label>
{variables &&
Object.entries(variables).map(([key, variable]) => (
<DropdownMenu.Item
key={key}
onSelect={() => {
addVariable(variable);
}}
textValue={variable.label.en}
>
{variable.label.en}
</DropdownMenu.Item>
))}
</DropdownMenu.Content>
</DropdownMenu.Root>
);
}
2 changes: 1 addition & 1 deletion components/block-editor/SidePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default function SidePanel() {
);
})}

<Heading variant="h4">Format</Heading>
<Heading variant="h4">Content</Heading>
{FORMATS.map(({ name, type }) =>
renderDraggableItem(name, (e) => handleDrag(e, type)),
)}
Expand Down
39 changes: 28 additions & 11 deletions lib/block-editor/extensions/Variable/utils.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { type EditorView } from '@tiptap/pm/view';
import type { TVariableDefinition } from '~/schemas/protocol/variables';

export const handleVariableDrop = (view: EditorView, event: DragEvent) => {
// Get the variable data
const jsonData = event.dataTransfer?.getData('application/json');
if (!jsonData) return false;
const newVariable = JSON.parse(jsonData) as TVariableDefinition;
const key = event.dataTransfer?.getData('application/x-variable-key');

if (!key) return false;

const { hint, variable, label } = view.state.schema.nodes;

export const createVariableNode = ({
newVariable,
view,
key,
}: {
newVariable: TVariableDefinition;
view: EditorView;
key: string;
}) => {
const { label, hint, variable } = view.state.schema.nodes;
// create the label node
const labelNode = label?.create(
{},
Expand Down Expand Up @@ -43,6 +42,24 @@ export const handleVariableDrop = (view: EditorView, event: DragEvent) => {
[labelNode, hintNode],
);

return variableNode;
};

export const handleVariableDrop = (view: EditorView, event: DragEvent) => {
// Get the variable data
const jsonData = event.dataTransfer?.getData('application/json');
if (!jsonData) return false;
const newVariable = JSON.parse(jsonData) as TVariableDefinition;
const key = event.dataTransfer?.getData('application/x-variable-key');

if (!key) return false;

const variableNode = createVariableNode({
newVariable,
view,
key,
});

const coordinates = view.posAtCoords({
left: event.clientX,
top: event.clientY,
Expand Down
4 changes: 2 additions & 2 deletions lib/block-editor/types.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
export type TiptapContent =
| 'paragraph'
| 'h1'
| 'h2'
| 'h3'
| 'h4'
| 'paragraph'
| 'bulletList'
| 'group'
| 'variable';

export const contentMap = {
paragraph: { type: 'paragraph' },
h1: {
type: 'heading',
attrs: { level: 1 },
Expand All @@ -26,6 +25,7 @@ export const contentMap = {
type: 'heading',
attrs: { level: 4 },
},
paragraph: { type: 'paragraph' },
bulletList: {
type: 'bulletList',
content: [
Expand Down

0 comments on commit 83ea60b

Please sign in to comment.