From 34b7fafa921d81394bd1f207990f4fa275e82ea4 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 7 Nov 2026 18:23:09 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EB=93=9C=EB=9E=98?= =?UTF-8?q?=EA=B7=B8=20=EC=95=A4=20=EB=93=9C=EB=A1=AD=20=EC=8B=9C=20?= =?UTF-8?q?=EB=B3=B5=EC=82=AC=20=EC=BB=A4=EC=84=9C=20=ED=91=9C=EC=8B=9C?= =?UTF-8?q?=EB=90=98=EB=8F=84=EB=A1=9D=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 드래그 앤 드롭 진입 시 `e.dataTransfer.dropEffect`를 'copy'로 명시적으로 지정하여 운영체제 기본 복사 커서(예: + 아이콘)가 표시되도록 했습니다. - CSS 클래스 변경만으로는 시스템 커서 피드백을 제공하지 못하는 문제를 해결했습니다. --- .jules/palette.md | 3 +++ saas_web.py | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.jules/palette.md b/.jules/palette.md index 2dcd639e..8c3eee5a 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -81,3 +81,6 @@ ## 2024-08-04 - 숫자 입력 필드 빈 문자열 상태 초기화 처리 **학습:** 숫자 입력 필드에서 빈 문자열('')을 입력할 때 브라우저는 이전의 유효하지 않은 상태를 암시적으로 유지하므로, 사용자 정의 검증을 명시적으로 초기화하지 않으면 네이티브 HTML5 유효성 검사가 정상 작동하지 않을 수 있음을 확인했습니다. **실행:** 인라인 검증 스크립트 작성 시 빈 문자열 상태를 별도로 확인하여 this.setCustomValidity('') 및 this.removeAttribute('aria-invalid')를 명시적으로 호출하는 로직을 추가해야 합니다. +## 2024-11-07 - Add copy cursor for drag and drop +**Learning:** Operating systems rely on explicitly setting e.dataTransfer.dropEffect = 'copy' during dragover to show the correct cursor feedback. The visual class change alone is insufficient for native OS interaction cues. +**Action:** Always set dropEffect appropriately alongside CSS state changes when implementing custom drop zones to ensure native UX consistency. diff --git a/saas_web.py b/saas_web.py index 63265e94..6de5a0fc 100644 --- a/saas_web.py +++ b/saas_web.py @@ -372,7 +372,12 @@ async def add_security_headers(request: Request, call_next): zone.addEventListener(eventName, preventDefaults, false); }); ['dragenter', 'dragover'].forEach(eventName => { - zone.addEventListener(eventName, () => zone.classList.add('dragover'), false); + zone.addEventListener(eventName, (e) => { + zone.classList.add('dragover'); + if (e.dataTransfer) { + e.dataTransfer.dropEffect = 'copy'; + } + }, false); }); ['dragleave', 'drop'].forEach(eventName => { zone.addEventListener(eventName, () => zone.classList.remove('dragover'), false);