Fullscreen mode for content editor
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import type { FormEvent, ChangeEvent } from 'react';
|
import type { FormEvent, ChangeEvent } from 'react';
|
||||||
import { createBrowserSupabase } from '../../lib/supabase';
|
import { createBrowserSupabase } from '../../lib/supabase';
|
||||||
import {
|
import {
|
||||||
@@ -16,6 +16,8 @@ import {
|
|||||||
ListsToggle,
|
ListsToggle,
|
||||||
BlockTypeSelect,
|
BlockTypeSelect,
|
||||||
InsertImage,
|
InsertImage,
|
||||||
|
Separator,
|
||||||
|
ButtonWithTooltip,
|
||||||
} from '@mdxeditor/editor';
|
} from '@mdxeditor/editor';
|
||||||
import '@mdxeditor/editor/style.css';
|
import '@mdxeditor/editor/style.css';
|
||||||
import type { Dict } from '../../lib/i18n';
|
import type { Dict } from '../../lib/i18n';
|
||||||
@@ -71,34 +73,103 @@ async function imageUploadHandler(file: File): Promise<string> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ContentEditor({ content, onChange }: ContentEditorProps) {
|
function ExpandIcon() {
|
||||||
return (
|
return (
|
||||||
<MDXEditor
|
<svg
|
||||||
markdown={content}
|
width="24"
|
||||||
onChange={onChange}
|
height="24"
|
||||||
plugins={[
|
viewBox="0 0 24 24"
|
||||||
headingsPlugin(),
|
fill="none"
|
||||||
listsPlugin(),
|
stroke="currentColor"
|
||||||
linkPlugin(),
|
strokeWidth="2"
|
||||||
imagePlugin({ imageUploadHandler: imageUploadHandler }),
|
strokeLinecap="round"
|
||||||
quotePlugin(),
|
strokeLinejoin="round"
|
||||||
thematicBreakPlugin(),
|
aria-hidden="true"
|
||||||
markdownShortcutPlugin(),
|
>
|
||||||
toolbarPlugin({
|
<path d="M8 3H5a2 2 0 0 0-2 2v3" />
|
||||||
toolbarContents: () => (
|
<path d="M16 3h3a2 2 0 0 1 2 2v3" />
|
||||||
<>
|
<path d="M8 21H5a2 2 0 0 1-2-2v-3" />
|
||||||
<UndoRedo />
|
<path d="M16 21h3a2 2 0 0 0 2-2v-3" />
|
||||||
<BoldItalicUnderlineToggles />
|
</svg>
|
||||||
<BlockTypeSelect />
|
);
|
||||||
<ListsToggle />
|
}
|
||||||
|
|
||||||
<InsertImage />
|
function CollapseIcon() {
|
||||||
</>
|
return (
|
||||||
),
|
<svg
|
||||||
}),
|
width="24"
|
||||||
]}
|
height="24"
|
||||||
contentEditableClassName="prose prose-sm max-w-none textarea"
|
viewBox="0 0 24 24"
|
||||||
/>
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<path d="M3 8h3a2 2 0 0 0 2-2V3" />
|
||||||
|
<path d="M21 8h-3a2 2 0 0 1-2-2V3" />
|
||||||
|
<path d="M3 16h3a2 2 0 0 1 2 2v3" />
|
||||||
|
<path d="M21 16h-3a2 2 0 0 0-2 2v3" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ContentEditor({ content, onChange }: ContentEditorProps) {
|
||||||
|
const [expanded, setExpanded] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!expanded) return;
|
||||||
|
const previousOverflow = document.body.style.overflow;
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
function handleKeyDown(e: KeyboardEvent) {
|
||||||
|
if (e.key === 'Escape') setExpanded(false);
|
||||||
|
}
|
||||||
|
document.addEventListener('keydown', handleKeyDown);
|
||||||
|
return () => {
|
||||||
|
document.body.style.overflow = previousOverflow;
|
||||||
|
document.removeEventListener('keydown', handleKeyDown);
|
||||||
|
};
|
||||||
|
}, [expanded]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={expanded ? 'content-editor content-editor--expanded' : 'content-editor'}>
|
||||||
|
<MDXEditor
|
||||||
|
className={expanded ? 'mdxeditor-full-height' : undefined}
|
||||||
|
markdown={content}
|
||||||
|
onChange={onChange}
|
||||||
|
plugins={[
|
||||||
|
headingsPlugin(),
|
||||||
|
listsPlugin(),
|
||||||
|
linkPlugin(),
|
||||||
|
imagePlugin({ imageUploadHandler: imageUploadHandler }),
|
||||||
|
quotePlugin(),
|
||||||
|
thematicBreakPlugin(),
|
||||||
|
markdownShortcutPlugin(),
|
||||||
|
toolbarPlugin({
|
||||||
|
toolbarContents: () => (
|
||||||
|
<>
|
||||||
|
<UndoRedo />
|
||||||
|
<BoldItalicUnderlineToggles />
|
||||||
|
<BlockTypeSelect />
|
||||||
|
<ListsToggle />
|
||||||
|
<Separator />
|
||||||
|
<InsertImage />
|
||||||
|
<Separator />
|
||||||
|
<ButtonWithTooltip
|
||||||
|
type="button"
|
||||||
|
title={expanded ? 'Collapse' : 'Expand'}
|
||||||
|
onClick={() => setExpanded((v) => !v)}
|
||||||
|
>
|
||||||
|
{expanded ? <CollapseIcon /> : <ExpandIcon />}
|
||||||
|
</ButtonWithTooltip>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
contentEditableClassName="prose prose-sm max-w-none textarea"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default function EventEditor({ dict: t, event }: Props) {
|
export default function EventEditor({ dict: t, event }: Props) {
|
||||||
|
|||||||
@@ -45,6 +45,21 @@
|
|||||||
resize: vertical;
|
resize: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-editor--expanded {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
background: var(--surface);
|
||||||
|
padding: var(--space-4);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.mdxeditor {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.form-error {
|
.form-error {
|
||||||
background: var(--danger-soft);
|
background: var(--danger-soft);
|
||||||
color: var(--danger);
|
color: var(--danger);
|
||||||
|
|||||||
Reference in New Issue
Block a user