Fullscreen mode for content editor

This commit is contained in:
ArtemBozhko
2026-10-09 13:16:13 +03:00
parent 52326657d3
commit d192889478
2 changed files with 114 additions and 28 deletions
+74 -3
View File
@@ -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,9 +73,69 @@ async function imageUploadHandler(file: File): Promise<string> {
} }
} }
function ContentEditor({ content, onChange }: ContentEditorProps) { function ExpandIcon() {
return ( return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="M8 3H5a2 2 0 0 0-2 2v3" />
<path d="M16 3h3a2 2 0 0 1 2 2v3" />
<path d="M8 21H5a2 2 0 0 1-2-2v-3" />
<path d="M16 21h3a2 2 0 0 0 2-2v-3" />
</svg>
);
}
function CollapseIcon() {
return (
<svg
width="24"
height="24"
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 <MDXEditor
className={expanded ? 'mdxeditor-full-height' : undefined}
markdown={content} markdown={content}
onChange={onChange} onChange={onChange}
plugins={[ plugins={[
@@ -91,14 +153,23 @@ function ContentEditor({ content, onChange }: ContentEditorProps) {
<BoldItalicUnderlineToggles /> <BoldItalicUnderlineToggles />
<BlockTypeSelect /> <BlockTypeSelect />
<ListsToggle /> <ListsToggle />
<Separator />
<InsertImage /> <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" 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) {
+15
View File
@@ -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);