diff --git a/apps/web/src/app/test/report-playground/ReportPlayground.tsx b/apps/web/src/app/test/report-playground/ReportPlayground.tsx
index b29822570..e0dba5c83 100644
--- a/apps/web/src/app/test/report-playground/ReportPlayground.tsx
+++ b/apps/web/src/app/test/report-playground/ReportPlayground.tsx
@@ -42,6 +42,10 @@ export const ReportPlayground: React.FC = () => {
{ wait: 150 }
);
+ const logValueChanges = (value: ReportElements) => {
+ console.log('value', value);
+ };
+
const usedValue: ReportElements = hasBeenSuccessFullAtLeastOnce ? data?.elements || [] : value;
return (
@@ -68,7 +72,7 @@ export const ReportPlayground: React.FC = () => {
-
+
);
diff --git a/apps/web/src/components/ui/dropdown-menu/dropdown-menu.tsx b/apps/web/src/components/ui/dropdown-menu/dropdown-menu.tsx
index 3da024305..e6677eac5 100644
--- a/apps/web/src/components/ui/dropdown-menu/dropdown-menu.tsx
+++ b/apps/web/src/components/ui/dropdown-menu/dropdown-menu.tsx
@@ -69,7 +69,7 @@ function DropdownMenuItem({
data-inset={inset}
data-variant={variant}
className={cn(
- "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+ "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...props}
diff --git a/apps/web/src/components/ui/report/DynamicReportEditor.tsx b/apps/web/src/components/ui/report/DynamicReportEditor.tsx
index 67a59a098..6b136ac25 100644
--- a/apps/web/src/components/ui/report/DynamicReportEditor.tsx
+++ b/apps/web/src/components/ui/report/DynamicReportEditor.tsx
@@ -2,14 +2,12 @@ import dynamic from 'next/dynamic';
import { ReportEditorSkeleton } from './ReportEditorSkeleton';
import { ReportEditor } from './ReportEditor';
-// export const DynamicReportEditor = dynamic(
-// () => import('@/components/ui/report/ReportEditor').then((mod) => mod.ReportEditor),
-// {
-// ssr: false,
-// loading: () =>
-// }
-// );
-
-const DynamicReportEditor = ReportEditor;
+export const DynamicReportEditor = dynamic(
+ () => import('@/components/ui/report/ReportEditor').then((mod) => mod.ReportEditor),
+ {
+ ssr: false,
+ loading: () =>
+ }
+);
export default DynamicReportEditor;
diff --git a/apps/web/src/components/ui/report/elements/CodeBlockNode.tsx b/apps/web/src/components/ui/report/elements/CodeBlockNode.tsx
index 762df7f48..5f02d2be0 100644
--- a/apps/web/src/components/ui/report/elements/CodeBlockNode.tsx
+++ b/apps/web/src/components/ui/report/elements/CodeBlockNode.tsx
@@ -46,7 +46,7 @@ export function CodeBlockElement(props: PlateElementProps) {
{isLangSupported(element.lang) && (
@@ -61,7 +61,7 @@ export function CodeBlockElement(props: PlateElementProps) {
);
}
-function CodeBlockCombobox() {
+const CodeBlockCombobox = React.memo(() => {
const [open, setOpen] = React.useState(false);
const readOnly = useReadOnly();
const editor = useEditorRef();
@@ -83,8 +83,8 @@ function CodeBlockCombobox() {
return (
-
setSearchValue('')}>
@@ -120,7 +120,9 @@ function CodeBlockCombobox() {
);
-}
+});
+
+CodeBlockCombobox.displayName = 'CodeBlockCombobox';
function CopyButton({
value,
@@ -137,6 +139,7 @@ function CopyButton({
return (
: }
onClick={() => {
void navigator.clipboard.writeText(typeof value === 'function' ? value() : value);
@@ -159,7 +162,7 @@ export function CodeSyntaxLeaf(props: PlateLeafProps) {
const languages: { label: string; value: string }[] = [
// { label: 'Auto', value: 'auto' },
- { label: 'Plain Text', value: 'plaintext' },
+ { label: 'Plain text', value: 'plaintext' },
// { label: 'ABAP', value: 'abap' },
// { label: 'Agda', value: 'agda' },
// { label: 'Arduino', value: 'arduino' },
diff --git a/apps/web/src/components/ui/report/elements/InlineCombobox.tsx b/apps/web/src/components/ui/report/elements/InlineCombobox.tsx
index f0f3181d7..a83c0c58e 100644
--- a/apps/web/src/components/ui/report/elements/InlineCombobox.tsx
+++ b/apps/web/src/components/ui/report/elements/InlineCombobox.tsx
@@ -340,7 +340,7 @@ function InlineComboboxGroupLabel({
return (
);
}
diff --git a/apps/web/src/components/ui/report/elements/MediaEmbedNode.tsx b/apps/web/src/components/ui/report/elements/MediaEmbedNode.tsx
index b140d5b22..fb7ef4785 100644
--- a/apps/web/src/components/ui/report/elements/MediaEmbedNode.tsx
+++ b/apps/web/src/components/ui/report/elements/MediaEmbedNode.tsx
@@ -9,13 +9,19 @@ import type { PlateElementProps } from 'platejs/react';
import { parseTwitterUrl, parseVideoUrl } from '@platejs/media';
import { MediaEmbedPlugin, useMediaState } from '@platejs/media/react';
import { ResizableProvider, useResizableValue } from '@platejs/resizable';
-import { PlateElement, withHOC } from 'platejs/react';
+import { PlateElement, useFocused, useReadOnly, useSelected, withHOC } from 'platejs/react';
import { cn } from '@/lib/utils';
import { Caption, CaptionTextarea } from './CaptionNode';
import { MediaToolbar } from './MediaToolbar';
import { mediaResizeHandleVariants, Resizable, ResizeHandle } from './ResizeHandle';
+import { Code3 } from '../../icons';
+import { PopoverAnchor, PopoverBase, PopoverContent } from '../../popover';
+import { useEffect, useState } from 'react';
+import { Title } from '../../typography';
+import { Input } from '../../inputs';
+import { Button } from '../../buttons';
export const MediaEmbedElement = withHOC(
ResizableProvider,
@@ -34,10 +40,15 @@ export const MediaEmbedElement = withHOC(
});
const width = useResizableValue('width');
const provider = embed?.provider;
+ const hasElement = !!embed?.url;
+
+ if (!hasElement) {
+ return ;
+ }
return (
-
+
) => {
+ const readOnly = useReadOnly();
+ const selected = useSelected();
+ const focused = useFocused();
+
+ const isFocused = focused && selected && !readOnly;
+
+ return (
+
+
+
+
+
+
+
+
+
Add a media embed
+
+ {props.children}
+
+
+ {
+ console.log('onOpenAutoFocus', e);
+ e.preventDefault();
+ }}>
+ Add a media embed
+
+
+
+ Add media
+
+
+
+ );
+};
diff --git a/apps/web/src/components/ui/report/elements/MediaPlaceholderElement.tsx b/apps/web/src/components/ui/report/elements/MediaPlaceholderElement.tsx
index 8e9acc5fe..0c5fe9c52 100644
--- a/apps/web/src/components/ui/report/elements/MediaPlaceholderElement.tsx
+++ b/apps/web/src/components/ui/report/elements/MediaPlaceholderElement.tsx
@@ -41,6 +41,11 @@ const CONTENT: Record<
accept: ['video/*'],
content: 'Add a video',
icon:
+ },
+ [KEYS.mediaEmbed]: {
+ accept: ['*'],
+ content: 'Add a media embed',
+ icon:
}
};
diff --git a/apps/web/src/components/ui/report/elements/TableNode/TableNode.tsx b/apps/web/src/components/ui/report/elements/TableNode/TableNode.tsx
index 3c7633d08..dbaa041e7 100644
--- a/apps/web/src/components/ui/report/elements/TableNode/TableNode.tsx
+++ b/apps/web/src/components/ui/report/elements/TableNode/TableNode.tsx
@@ -18,20 +18,6 @@ import {
} from '@platejs/table/react';
import { PopoverAnchor } from '@radix-ui/react-popover';
import { cva } from 'class-variance-authority';
-// import {
-// ArrowDown,
-// ArrowLeft,
-// ArrowRight,
-// ArrowUp,
-// CombineIcon,
-// EraserIcon,
-// Grid2X2Icon,
-// GripVertical,
-// PaintBucketIcon,
-// SquareSplitHorizontalIcon,
-// Trash2Icon,
-// XIcon
-// } from 'lucide-react';
import {
ArrowDown,
ArrowLeft,
diff --git a/apps/web/src/components/ui/report/elements/transforms.ts b/apps/web/src/components/ui/report/elements/transforms.ts
index dab7ca586..0dff33c3c 100644
--- a/apps/web/src/components/ui/report/elements/transforms.ts
+++ b/apps/web/src/components/ui/report/elements/transforms.ts
@@ -11,7 +11,8 @@ import { insertEquation, insertInlineEquation } from '@platejs/math';
import {
insertAudioPlaceholder,
insertFilePlaceholder,
- insertMedia,
+ insertPlaceholder,
+ insertImagePlaceholder,
insertVideoPlaceholder
} from '@platejs/media';
import { SuggestionPlugin } from '@platejs/suggestion/react';
@@ -41,16 +42,19 @@ const insertBlockMap: Record void
[KEYS.codeBlock]: (editor) => insertCodeBlock(editor, { select: true }),
[KEYS.equation]: (editor) => insertEquation(editor, { select: true }),
[KEYS.file]: (editor) => insertFilePlaceholder(editor, { select: true }),
- [KEYS.img]: (editor) =>
- insertMedia(editor, {
- select: true,
- type: KEYS.img
- }),
- [KEYS.mediaEmbed]: (editor) =>
- insertMedia(editor, {
- select: true,
- type: KEYS.mediaEmbed
- }),
+ [KEYS.img]: (editor) => {
+ insertImagePlaceholder(editor, {
+ select: true
+ });
+ },
+ [KEYS.mediaEmbed]: (editor) => {
+ editor.tf.insertNodes(
+ editor.api.create.block({
+ type: KEYS.mediaEmbed
+ }),
+ { select: true }
+ );
+ },
[KEYS.table]: (editor) => editor.getTransforms(TablePlugin).insert.table({}, { select: true }),
[KEYS.toc]: (editor) => insertToc(editor, { select: true }),
[KEYS.video]: (editor) => insertVideoPlaceholder(editor, { select: true })
diff --git a/apps/web/src/components/ui/report/plugins/media-kit.tsx b/apps/web/src/components/ui/report/plugins/media-kit.tsx
index 7782bcba2..9e172c6d0 100644
--- a/apps/web/src/components/ui/report/plugins/media-kit.tsx
+++ b/apps/web/src/components/ui/report/plugins/media-kit.tsx
@@ -12,25 +12,31 @@ import {
import { KEYS } from 'platejs';
import { AudioElement } from '../elements/AudioNode';
-import { MediaEmbedElement } from '../elements/MediaEmbedNode';
+import { MediaEmbedElement, MediaEmbedPlaceholder } from '../elements/MediaEmbedNode';
import { FileElement } from '../elements/MediaFileNode';
import { ImageElement } from '../elements/MediaImageNode';
import { PlaceholderElement } from '../elements/MediaPlaceholderElement';
import { MediaPreviewDialog } from '../elements/MediaPreviewDialog';
import { MediaUploadToast } from '../elements/MediaUploadToast';
import { VideoElement } from '../elements/MediaVideoNode';
+import { MediaPluginOptions } from '@platejs/media';
export const MediaKit = [
ImagePlugin.configure({
options: { disableUploadInsert: true },
render: { afterEditable: MediaPreviewDialog, node: ImageElement }
}),
- MediaEmbedPlugin.withComponent(MediaEmbedElement),
- // VideoPlugin.withComponent(VideoElement),
- // AudioPlugin.withComponent(AudioElement),
- // FilePlugin.withComponent(FileElement),
+ MediaEmbedPlugin.configure({
+ node: {
+ component: MediaEmbedElement,
+ isSelectable: true,
+ isElement: true
+ },
+ options: {}
+ }),
+
PlaceholderPlugin.configure({
- options: { disableEmptyPlaceholder: true },
+ options: { disableEmptyPlaceholder: false },
render: { afterEditable: MediaUploadToast, node: PlaceholderElement }
}),
CaptionPlugin.configure({
@@ -40,4 +46,7 @@ export const MediaKit = [
}
}
})
+ // VideoPlugin.withComponent(VideoElement),
+ // AudioPlugin.withComponent(AudioElement),
+ // FilePlugin.withComponent(FileElement),
];
diff --git a/apps/web/src/components/ui/toolbar/Toolbar.tsx b/apps/web/src/components/ui/toolbar/Toolbar.tsx
index e925d51a0..e13f5d4d4 100644
--- a/apps/web/src/components/ui/toolbar/Toolbar.tsx
+++ b/apps/web/src/components/ui/toolbar/Toolbar.tsx
@@ -262,7 +262,7 @@ export const ToolbarMenuGroup = ({
className
)}>
{label && (
-
+
{label}
)}
diff --git a/apps/web/src/styles/theme-reset.ts b/apps/web/src/styles/theme-reset.ts
index 72fe4b011..c2a46c497 100644
--- a/apps/web/src/styles/theme-reset.ts
+++ b/apps/web/src/styles/theme-reset.ts
@@ -1,10 +1,10 @@
import React from 'react';
export const FONT_BASE_THEME = {
- '--font-heading': 'ui-sans-serif, -apple-system, BlinkMacSystemFont',
- '--font-sans': 'ui-sans-serif, -apple-system, BlinkMacSystemFont',
- '--font-mono':
- 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
+ // '--font-heading': 'ui-sans-serif, -apple-system, BlinkMacSystemFont',
+ // '--font-sans': 'ui-sans-serif, -apple-system, BlinkMacSystemFont',
+ // '--font-mono':
+ // 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
'--spacing': '0.25rem',
'--breakpoint-xl': '80rem',
'--breakpoint-2xl': '96rem',
@@ -89,7 +89,8 @@ export const THEME_RESET_COLORS = {
'popover-foreground': '240 10% 3.9%',
primary: '240 5.9% 10%',
'primary-foreground': '0 0% 98%',
- ring: '240 10% 3.9%',
+ // Set ring to a super light gray (almost white)
+ ring: '0 0% 96%',
secondary: '240 4.8% 95.9%',
'secondary-foreground': '240 5.9% 10%'
},
diff --git a/packages/server-shared/src/reports/report-elements.ts b/packages/server-shared/src/reports/report-elements.ts
index 689dba8bd..72c26a898 100644
--- a/packages/server-shared/src/reports/report-elements.ts
+++ b/packages/server-shared/src/reports/report-elements.ts
@@ -78,21 +78,25 @@ export const HeaderElementSchema = z
})
.merge(AttributesSchema);
+const ListStylesAttributesSchema = z.object({
+ listStyleType: z
+ .enum(['disc', 'circle', 'square', 'decimal', 'decimal-leading-zero', 'todo'])
+ .optional(),
+ listRestart: z.boolean().optional(),
+ listRestartPolite: z.boolean().optional(),
+ listStart: z.number().int().min(0).optional(),
+ indent: z.number().int().min(0).optional(),
+ checked: z.boolean().optional(), //used with todo list style
+});
+
// Paragraph element with optional list styling and indentation
export const ParagraphElementSchema = z
.object({
type: z.literal('p'),
- listStyleType: z
- .enum(['disc', 'circle', 'square', 'decimal', 'decimal-leading-zero'])
- .optional(),
- listRestart: z.boolean().optional(),
- listRestartPolite: z.boolean().optional(),
- listStart: z.number().int().min(0).optional(),
-
- indent: z.number().int().min(0).optional(),
children: z.array(z.union([TextSchema, AnchorSchema, MentionSchema])),
})
- .merge(AttributesSchema);
+ .merge(AttributesSchema)
+ .merge(ListStylesAttributesSchema);
// Blockquote element
export const BlockquoteElementSchema = z