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:
parent
45ac425484
commit
cdb074193f
2 changed files with 27 additions and 7 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue