Skip to content

Commit

Permalink
sync
Browse files Browse the repository at this point in the history
  • Loading branch information
zbeyens committed Nov 26, 2024
1 parent 54f98c6 commit bbcc212
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 9 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@
"clsx": "^2.1.1",
"cmdk": "^1.0.4",
"date-fns": "^4.1.0",
"html2canvas": "^1.4.1",
"lucide-react": "0.456.0",
"next": "^15.0.3",
"pdf-lib": "^1.17.1",
"prismjs": "^1.29.0",
"react": "^18.3.1",
"react-day-picker": "8.10.1",
Expand Down
76 changes: 76 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/components/plate-ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const buttonVariants = cva(
},
size: {
icon: 'size-[28px] rounded-md px-1.5',
lg: 'h-10 rounded-md px-4',
lg: 'h-9 rounded-md px-4',
md: 'h-8 px-3 text-sm',
none: '',
sm: 'h-[28px] rounded-md px-2.5',
Expand Down
5 changes: 2 additions & 3 deletions src/components/plate-ui/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export const EditorContainer = ({
editorContainerVariants({ variant }),
className
)}
role="button"
{...props}
/>
);
Expand Down Expand Up @@ -75,9 +74,9 @@ const editorVariants = cva(
true: 'ring-2 ring-ring ring-offset-2',
},
variant: {
ai: 'w-full px-0 text-sm',
ai: 'w-full px-0 text-base md:text-sm',
aiChat:
'max-h-[min(70vh,320px)] w-full max-w-[700px] overflow-y-auto px-3 py-2 text-sm',
'max-h-[min(70vh,320px)] w-full max-w-[700px] overflow-y-auto px-3 py-2 text-base md:text-sm',
default:
'size-full px-16 pb-72 pt-4 text-base sm:px-[max(64px,calc(50%-350px))]',
demo: 'size-full px-16 pb-72 pt-4 text-base sm:px-[max(64px,calc(50%-350px))]',
Expand Down
93 changes: 93 additions & 0 deletions src/components/plate-ui/export-toolbar-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
'use client';

import React from 'react';

import type { DropdownMenuProps } from '@radix-ui/react-dropdown-menu';

import { toDOMNode, useEditorRef } from '@udecode/plate-common/react';
import { ArrowDownToLineIcon } from 'lucide-react';

import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuTrigger,
useOpenState,
} from './dropdown-menu';
import { ToolbarButton } from './toolbar';

export function ExportToolbarButton({ children, ...props }: DropdownMenuProps) {
const editor = useEditorRef();
const openState = useOpenState();

const getCanvas = async () => {
const { default: html2canvas } = await import('html2canvas');

const style = document.createElement('style');
document.head.append(style);
style.sheet?.insertRule(
'body > div:last-child img { display: inline-block !important; }'
);

const canvas = await html2canvas(toDOMNode(editor, editor)!);
style.remove();

return canvas;
};

const downloadFile = (href: string, filename: string) => {
const element = document.createElement('a');
element.setAttribute('href', href);
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.append(element);
element.click();
element.remove();
};

const exportToPdf = async () => {
const canvas = await getCanvas();

const PDFLib = await import('pdf-lib');
const pdfDoc = await PDFLib.PDFDocument.create();
const page = pdfDoc.addPage([canvas.width, canvas.height]);
const imageEmbed = await pdfDoc.embedPng(canvas.toDataURL('PNG'));
const { height, width } = imageEmbed.scale(1);
page.drawImage(imageEmbed, {
height,
width,
x: 0,
y: 0,
});
const pdfBase64 = await pdfDoc.saveAsBase64({ dataUri: true });

downloadFile(pdfBase64, 'plate.pdf');
};

const exportToImage = async () => {
const canvas = await getCanvas();
downloadFile(canvas.toDataURL('image/png'), 'plate.png');
};

return (
<DropdownMenu modal={false} {...openState} {...props}>
<DropdownMenuTrigger asChild>
<ToolbarButton pressed={openState.open} tooltip="Export" isDropdown>
<ArrowDownToLineIcon className="size-4" />
</ToolbarButton>
</DropdownMenuTrigger>

<DropdownMenuContent align="start">
<DropdownMenuGroup>
<DropdownMenuItem onSelect={exportToPdf}>
Export as PDF
</DropdownMenuItem>
<DropdownMenuItem onSelect={exportToImage}>
Export as Image
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
);
}
8 changes: 8 additions & 0 deletions src/components/plate-ui/fixed-toolbar-buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
VideoPlugin,
} from '@udecode/plate-media/react';
import {
ArrowUpToLineIcon,
BaselineIcon,
BoldIcon,
Code2Icon,
Expand All @@ -41,6 +42,7 @@ import { AlignDropdownMenu } from './align-dropdown-menu';
import { ColorDropdownMenu } from './color-dropdown-menu';
import { CommentToolbarButton } from './comment-toolbar-button';
import { EmojiDropdownMenu } from './emoji-dropdown-menu';
import { ExportToolbarButton } from './export-toolbar-button';
import { RedoToolbarButton, UndoToolbarButton } from './history-toolbar-button';
import { IndentListToolbarButton } from './indent-list-toolbar-button';
import { IndentTodoToolbarButton } from './indent-todo-toolbar-button';
Expand Down Expand Up @@ -75,6 +77,12 @@ export function FixedToolbarButtons() {
</AIToolbarButton>
</ToolbarGroup>

<ToolbarGroup>
<ExportToolbarButton>
<ArrowUpToLineIcon />
</ExportToolbarButton>
</ToolbarGroup>

<ToolbarGroup>
<InsertDropdownMenu />
<TurnIntoDropdownMenu />
Expand Down
2 changes: 1 addition & 1 deletion src/components/plate-ui/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { cn, withVariants } from '@udecode/cn';
import { type VariantProps, cva } from 'class-variance-authority';

export const inputVariants = cva(
'flex w-full rounded-md bg-transparent text-sm file:border-0 file:bg-background file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
'flex w-full rounded-md bg-transparent text-base file:border-0 file:bg-background file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
{
defaultVariants: {
h: 'md',
Expand Down
1 change: 0 additions & 1 deletion src/components/plate-ui/media-audio-element.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export const MediaAudioElement = withHOC(
>
<figure className="group relative" contentEditable={false}>
<div className="h-16">
{/* eslint-disable-next-line jsx-a11y/media-has-caption */}
<audio className="size-full" src={unsafeUrl} controls />
</div>

Expand Down
Loading

0 comments on commit bbcc212

Please sign in to comment.