feat: support fullscreen mode in NoteEditorDialog

- Added `isEditorFullscreen` state to track fullscreen mode for the Markdown editor.
- Integrated `MutationObserver` to detect changes related to the `.w-md-editor-fullscreen` class.
- Adjusted dialog and editor styles dynamically based on fullscreen state using `cn`.
- Enhanced UX by resetting fullscreen state on dialog close.
This commit is contained in:
Antonio Gatta 2025-12-20 11:38:31 +01:00
parent 45ac425484
commit cdb074193f
2 changed files with 27 additions and 7 deletions

View file

@ -1,7 +1,7 @@
'use client' 'use client'
import { Controller, useForm, useWatch } from 'react-hook-form' import { Controller, useForm, useWatch } from 'react-hook-form'
import { useEffect } from 'react' import { useEffect, useState } from 'react'
import { useQueryClient } from '@tanstack/react-query' import { useQueryClient } from '@tanstack/react-query'
import { zodResolver } from '@hookform/resolvers/zod' import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod' import { z } from 'zod'
@ -11,6 +11,7 @@ import { useCreateNote, useUpdateNote, useNote } from '@/lib/hooks/use-notes'
import { QUERY_KEYS } from '@/lib/api/query-client' import { QUERY_KEYS } from '@/lib/api/query-client'
import { MarkdownEditor } from '@/components/ui/markdown-editor' import { MarkdownEditor } from '@/components/ui/markdown-editor'
import { InlineEdit } from '@/components/common/InlineEdit' import { InlineEdit } from '@/components/common/InlineEdit'
import { cn } from "@/lib/utils";
const createNoteSchema = z.object({ const createNoteSchema = z.object({
title: z.string().optional(), title: z.string().optional(),
@ -53,6 +54,7 @@ export function NoteEditorDialog({ open, onOpenChange, notebookId, note }: NoteE
}, },
}) })
const watchTitle = useWatch({ control, name: 'title' }) const watchTitle = useWatch({ control, name: 'title' })
const [isEditorFullscreen, setIsEditorFullscreen] = useState(false)
useEffect(() => { useEffect(() => {
if (!open) { if (!open) {
@ -67,6 +69,14 @@ export function NoteEditorDialog({ open, onOpenChange, notebookId, note }: NoteE
reset({ title, content }) reset({ title, content })
}, [open, note, fetchedNote, reset]) }, [open, note, fetchedNote, reset])
useEffect(() => {
const observer = new MutationObserver(() => {
setIsEditorFullscreen(!!document.querySelector('.w-md-editor-fullscreen'))
})
observer.observe(document.body, {subtree: true, attributes: true, attributeFilter: ['class']})
return () => observer.disconnect()
}, [])
const onSubmit = async (data: CreateNoteFormData) => { const onSubmit = async (data: CreateNoteFormData) => {
if (note) { if (note) {
await updateNote.mutateAsync({ await updateNote.mutateAsync({
@ -99,12 +109,16 @@ export function NoteEditorDialog({ open, onOpenChange, notebookId, note }: NoteE
const handleClose = () => { const handleClose = () => {
reset() reset()
setIsEditorFullscreen(false)
onOpenChange(false) onOpenChange(false)
} }
return ( return (
<Dialog open={open} onOpenChange={handleClose}> <Dialog open={open} onOpenChange={handleClose}>
<DialogContent className="sm:max-w-3xl w-full max-h-[90vh] overflow-hidden p-0"> <DialogContent className={cn(
"sm:max-w-3xl w-full max-h-[90vh] overflow-hidden p-0",
isEditorFullscreen && "!max-w-screen !max-h-screen border-none w-screen h-screen"
)}>
<DialogTitle className="sr-only"> <DialogTitle className="sr-only">
{isEditing ? 'Edit note' : 'Create note'} {isEditing ? 'Edit note' : 'Create note'}
</DialogTitle> </DialogTitle>
@ -126,7 +140,10 @@ export function NoteEditorDialog({ open, onOpenChange, notebookId, note }: NoteE
/> />
</div> </div>
<div className="flex-1 overflow-y-auto px-6 py-4"> <div className={cn(
"flex-1 overflow-y-auto",
!isEditorFullscreen && "px-6 py-4")
}>
<Controller <Controller
control={control} control={control}
name="content" name="content"
@ -137,7 +154,10 @@ export function NoteEditorDialog({ open, onOpenChange, notebookId, note }: NoteE
onChange={field.onChange} onChange={field.onChange}
height={420} height={420}
placeholder="Write your note content here..." placeholder="Write your note content here..."
className="rounded-md border" className={cn(
"w-full h-full min-h-[420px] [&_.w-md-editor]:!static [&_.w-md-editor]:!w-full [&_.w-md-editor]:!h-full",
!isEditorFullscreen && "rounded-md border"
)}
/> />
)} )}
/> />
@ -152,8 +172,8 @@ export function NoteEditorDialog({ open, onOpenChange, notebookId, note }: NoteE
<Button type="button" variant="outline" onClick={handleClose}> <Button type="button" variant="outline" onClick={handleClose}>
Cancel Cancel
</Button> </Button>
<Button <Button
type="submit" type="submit"
disabled={isSaving || (isEditing && noteLoading)} disabled={isSaving || (isEditing && noteLoading)}
> >
{isSaving {isSaving

View file

@ -60,7 +60,7 @@ function DialogContent({
<DialogPrimitive.Content <DialogPrimitive.Content
data-slot="dialog-content" data-slot="dialog-content"
className={cn( className={cn(
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:pointer-events-none fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-[calc(100%-2rem)] has-[.w-md-editor-fullscreen]:max-w-[calc(100%-2rem)] has-[.w-md-editor-fullscreen]:h-[90vh] [&_*:is(.w-md-editor-fullscreen)]:!static [&_*:is(.w-md-editor-fullscreen)]:!h-[calc(90vh-(var(--spacing)*41))]", "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:pointer-events-none fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-[calc(100%-2rem)]",
className className
)} )}
{...props} {...props}