This commit is contained in:
root
2026-07-05 22:50:31 +00:00
parent b0ae5dd740
commit 99c2c2f755
+88 -1
View File
@@ -232,7 +232,12 @@
<!-- DETAIL MODAL FOR STUDY ELEMENT --> <!-- DETAIL MODAL FOR STUDY ELEMENT -->
<dialog ref="detailModal" class="modal" :class="{ 'modal-open': activeElement }"> <dialog ref="detailModal" class="modal" :class="{ 'modal-open': activeElement }">
<div v-if="activeElement" class="modal-box max-w-4xl bg-base-200 border border-base-content/10 p-8 rounded-3xl shadow-2xl relative flex flex-col max-h-[85vh]"> <div
v-if="activeElement"
class="modal-box max-w-4xl bg-base-200 border border-base-content/10 p-8 rounded-3xl shadow-2xl relative flex flex-col max-h-[85vh]"
@touchstart.passive="handleTouchStart"
@touchend="handleTouchEnd"
>
<!-- Control buttons (Print & Close) --> <!-- Control buttons (Print & Close) -->
<div class="absolute right-4 top-3 flex items-center gap-0"> <div class="absolute right-4 top-3 flex items-center gap-0">
<button @click="printSingleElement(activeElement)" class="btn btn-sm btn-circle btn-ghost" title="PDF/인쇄"> <button @click="printSingleElement(activeElement)" class="btn btn-sm btn-circle btn-ghost" title="PDF/인쇄">
@@ -612,6 +617,88 @@ function closeModal() {
activeElement.value = null activeElement.value = null
} }
// Swipe navigation variables & helpers
let touchStartX = 0
let touchStartY = 0
let touchStartTime = 0
let touchHasException = false
function isSwipeException(target: HTMLElement | null): boolean {
let el = target
while (el) {
const tagName = el.tagName.toLowerCase()
if (tagName === 'img' || tagName === 'canvas' || tagName === 'embed' || tagName === 'iframe') {
return true
}
const classes = el.classList
if (
classes.contains('katex') ||
classes.contains('math-inline') ||
classes.contains('math-display') ||
classes.contains('mermaid') ||
classes.contains('katex-display') ||
classes.contains('katex-html') ||
Array.from(classes).some(c => c.toLowerCase().includes('pdf'))
) {
return true
}
el = el.parentElement
}
return false
}
function navigateStudyElement(direction: 'prev' | 'next') {
if (!activeElement.value) return
const list = filteredElements.value
if (list.length === 0) return
const currentIndex = list.findIndex(
se => se.questionId === activeElement.value?.questionId && se.source === activeElement.value?.source
)
if (currentIndex === -1) return
let targetIndex = currentIndex
if (direction === 'prev') {
targetIndex = currentIndex - 1
} else {
targetIndex = currentIndex + 1
}
if (targetIndex >= 0 && targetIndex < list.length) {
openModal(list[targetIndex])
}
}
function handleTouchStart(e: TouchEvent) {
if (e.touches.length !== 1) return
const touch = e.touches[0]
touchStartX = touch.clientX
touchStartY = touch.clientY
touchStartTime = Date.now()
touchHasException = isSwipeException(e.target as HTMLElement)
}
function handleTouchEnd(e: TouchEvent) {
if (touchHasException || e.changedTouches.length !== 1) return
const touch = e.changedTouches[0]
const diffX = touch.clientX - touchStartX
const diffY = touch.clientY - touchStartY
const timeElapsed = Date.now() - touchStartTime
const minSwipeDistance = 50
const maxVerticalDistance = 100
const maxSwipeTime = 400
if (timeElapsed < maxSwipeTime && Math.abs(diffX) >= minSwipeDistance && Math.abs(diffY) < maxVerticalDistance) {
if (diffX < 0) {
navigateStudyElement('next')
} else {
navigateStudyElement('prev')
}
}
}
// Print and export PDF helpers // Print and export PDF helpers
function printSingleElement(se: StudyElement) { function printSingleElement(se: StudyElement) {
const printWindow = window.open('', '_blank') const printWindow = window.open('', '_blank')