@ -30,10 +30,12 @@ const loading = ref(false)
const saving = ref ( false )
const loadError = ref ( '' )
const fullScreen = ref ( false )
const isMobileViewport = ref ( false )
const lastSavedAt = ref < string | null > ( null )
const allowSilentClose = ref ( false )
let removeRouteGuard : ( ( ) => void ) | null = null
let syncDraftTimer : ReturnType < typeof setInterval > | null = null
let viewportMql : MediaQueryList | null = null
let onViewportChange : ( ( event : MediaQueryListEvent ) => void ) | null = null
const modalRect = reactive ( { left : 0 , top : 0 , width : 0 , height : 0 } )
const dragging = ref ( false )
@ -63,13 +65,21 @@ const draftContent = computed({
} )
const isDirty = computed ( ( ) => modalState . value . isDirty )
const editorResizeSignal = computed ( ( ) => ` ${ modalRect . width } x ${ modalRect . height } - ${ fullScreen . value ? 'full' : 'windowed' } ` )
const effectiveFullscreen = computed ( ( ) => fullScreen . value || isMobileViewport . value )
const editorResizeSignal = computed ( ( ) => ` ${ modalRect . width } x ${ modalRect . height } - ${ effectiveFullscreen . value ? 'full' : 'windowed' } ` )
const editorReloadToken = ref ( 0 )
function syncDraftFromEditor ( ) {
quickNoteEditorRef . value ? . flushValue ( )
}
function handleEditorContentChange ( nextValue : string ) {
if ( nextValue === modalState . value . draftContent ) {
return
}
modalState . value = updateDraftContent ( modalState . value , nextValue )
}
function reloadEditor ( ) {
syncDraftFromEditor ( )
editorReloadToken . value += 1
@ -79,28 +89,8 @@ function reloadEditor() {
} )
}
function startDraftSyncTimer ( ) {
if ( ! import . meta . client || syncDraftTimer ) {
return
}
syncDraftTimer = setInterval ( ( ) => {
if ( ! open . value || loading . value || saving . value ) {
return
}
syncDraftFromEditor ( )
} , 120 )
}
function stopDraftSyncTimer ( ) {
if ( ! syncDraftTimer ) {
return
}
clearInterval ( syncDraftTimer )
syncDraftTimer = null
}
const cardStyle = computed ( ( ) => {
if ( fullS creen. value ) {
if ( effectiveFullscreen . value ) {
return { }
}
return {
@ -112,7 +102,7 @@ const cardStyle = computed(() => {
} )
const cardClass = computed ( ( ) => {
if ( fullS creen. value ) {
if ( effectiveFulls creen. value ) {
return 'h-full w-full rounded-none'
}
return 'absolute max-w-none rounded-xl'
@ -137,6 +127,13 @@ function updateModalSizeFromViewport() {
if ( ! import . meta . client ) {
return
}
if ( isMobileViewport . value ) {
modalRect . left = 0
modalRect . top = 0
modalRect . width = window . innerWidth
modalRect . height = window . innerHeight
return
}
const next = createDefaultModalRect ( {
viewportWidth : window . innerWidth ,
viewportHeight : window . innerHeight ,
@ -162,7 +159,7 @@ function updateModalSizeFromViewport() {
}
function handlePointerMove ( event : PointerEvent ) {
if ( resizing . value && ! fullS creen. value ) {
if ( resizing . value && ! effectiveFulls creen. value ) {
if ( ! import . meta . client ) {
return
}
@ -205,7 +202,7 @@ function handlePointerMove(event: PointerEvent) {
modalRect . height = clampedRect . height
return
}
if ( ! dragging . value || fullS creen. value ) {
if ( ! dragging . value || effectiveFulls creen. value ) {
return
}
const clamped = clampModalRect ( {
@ -224,7 +221,7 @@ function handlePointerMove(event: PointerEvent) {
}
function startDragging ( event : PointerEvent ) {
if ( fullS creen. value || event . button !== 0 ) {
if ( effectiveFulls creen. value || event . button !== 0 ) {
return
}
dragging . value = true
@ -250,7 +247,7 @@ function stopResizing() {
}
function startResizing ( event : PointerEvent , direction : ResizeDirection ) {
if ( fullS creen. value || event . button !== 0 || ! import . meta . client ) {
if ( effectiveFulls creen. value || event . button !== 0 || ! import . meta . client ) {
return
}
resizing . value = true
@ -266,6 +263,9 @@ function startResizing(event: PointerEvent, direction: ResizeDirection) {
}
function toggleFullScreen ( ) {
if ( isMobileViewport . value ) {
return
}
fullScreen . value = ! fullScreen . value
if ( fullScreen . value ) {
stopDragging ( )
@ -365,13 +365,11 @@ watch(
}
allowSilentClose . value = false
if ( ! isOpen ) {
stopDraftSyncTimer ( )
fullScreen . value = false
stopDragging ( )
stopResizing ( )
return
}
startDraftSyncTimer ( )
updateModalSizeFromViewport ( )
void loadQuickNote ( )
} ,
@ -381,6 +379,13 @@ onMounted(() => {
if ( ! import . meta . client ) {
return
}
viewportMql = window . matchMedia ( '(max-width: 767px)' )
isMobileViewport . value = viewportMql . matches
onViewportChange = ( event : MediaQueryListEvent ) => {
isMobileViewport . value = event . matches
updateModalSizeFromViewport ( )
}
viewportMql . addEventListener ( 'change' , onViewportChange )
removeRouteGuard = router . beforeEach ( ( to ) => {
syncDraftFromEditor ( )
if ( ! open . value || ! isDirty . value ) {
@ -393,8 +398,12 @@ onMounted(() => {
} )
onBeforeUnmount ( ( ) => {
stopDraftSyncTimer ( )
if ( import . meta . client ) {
if ( viewportMql && onViewportChange ) {
viewportMql . removeEventListener ( 'change' , onViewportChange )
}
onViewportChange = null
viewportMql = null
removeRouteGuard ? . ( )
removeRouteGuard = null
window . removeEventListener ( 'beforeunload' , handleBeforeUnload )
@ -426,7 +435,7 @@ onBeforeUnmount(() => {
< template # header >
< div
class = "flex items-center justify-between gap-3 select-none"
: class = "fullS creen ? 'cursor-default' : 'cursor-move'"
: class = "effectiveFulls creen ? 'cursor-default' : 'cursor-move'"
@ pointerdown = "startDragging"
>
< div class = "min-w-0" >
@ -447,6 +456,7 @@ onBeforeUnmount(() => {
@ click = "reloadEditor"
/ >
< UButton
v - if = "!isMobileViewport"
color = "neutral"
variant = "ghost"
size = "sm"
@ -490,6 +500,7 @@ onBeforeUnmount(() => {
ref = "quickNoteEditorRef"
v - model = "draftContent"
: resize - signal = "editorResizeSignal"
@ content - change = "handleEditorContentChange"
/ >
< / div >
< / div >
@ -522,7 +533,7 @@ onBeforeUnmount(() => {
< / div >
< / template >
< / UCard >
< template v-if ="!fullS creen" >
< template v-if ="!effectiveFulls creen" >
< button
type = "button"
class = "absolute left-0 top-0 z-10 h-full w-1 cursor-w-resize"