From 6bb0a5312d585bcbdec36b919a829c2295c72a3d Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 26 Oct 2026 22:13:40 +0900 Subject: [PATCH] =?UTF-8?q?refactor(B03):=20=ED=8C=8C=EC=9D=BC=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=ED=99=94=EB=A9=B4=20=EB=A7=88=EB=AC=B4=EB=A6=AC=20?= =?UTF-8?q?=E2=80=94=20=ED=8C=8C=EC=9D=BC=20=EB=86=93=EA=B8=B0=20=EC=B9=B8?= =?UTF-8?q?=20=C2=B7=20=EB=AA=A8=EB=8B=AC=20=C2=B7=20=ED=99=95=EC=9D=B8?= =?UTF-8?q?=EC=B0=BD=20=C2=B7=20=EA=B3=A0=EB=A5=B4=EB=8A=94=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=C2=B7=20=EB=AA=A9=EB=A1=9D=20=EC=A4=84=20=EB=B6=80?= =?UTF-8?q?=ED=92=88=20(PLAN=20553-1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 놓기 칸 = 파일 놓기 칸 부품(한 줄로 눕힘) · 임시 보관함 창 = 모달 + 고르는 카드 + 빈 상태 · 교체 확인 = 확인창 - 업로드 도중 window.confirm 둘 → 확인창 부품(글 그대로 · 단추 이름으로 선택 안내) · 예정노선 고름 줄 = 목록 줄 - 모달 CSS · 임시 목록 옛 CSS 걷음 · 가이드 촬영 선택자 · 지킴 시험 Co-Authored-By: Claude Sonnet 5.5 --- A05_EduDetail/guide/B03/_scenes.json | 2 +- B03_FileInput/B03_FileInput_UI_Page.ts | 44 ++----- B03_FileInput/B03_FileInput_UI_Style.css | 78 +---------- B03_FileInput/B03_FileInput_UI_Style_Temp.css | 68 +--------- B03_FileInput/B03_FileInput_UI_TempPicker.ts | 122 ++++++++---------- B03_FileInput/B03_FileInput_UI_Upload.ts | 61 +++------ resources/tester/test_553_1_pages.py | 14 ++ 7 files changed, 100 insertions(+), 289 deletions(-) diff --git a/A05_EduDetail/guide/B03/_scenes.json b/A05_EduDetail/guide/B03/_scenes.json index 3d6328975..3cd582843 100644 --- a/A05_EduDetail/guide/B03/_scenes.json +++ b/A05_EduDetail/guide/B03/_scenes.json @@ -262,7 +262,7 @@ "callouts": [ { "n": 1, - "sel": ".b03-file__temp-modal-actions" + "sel": ".b03-file__temp-modal .ui-modal__actions" } ] }, diff --git a/B03_FileInput/B03_FileInput_UI_Page.ts b/B03_FileInput/B03_FileInput_UI_Page.ts index 4a63ac235..07a26c07d 100644 --- a/B03_FileInput/B03_FileInput_UI_Page.ts +++ b/B03_FileInput/B03_FileInput_UI_Page.ts @@ -6,6 +6,7 @@ import { } from "@config/config_frontend"; import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale"; import { createBanner } from "@ui/ui_template_banner"; +import { createDrop } from "@ui/ui_template_drop"; import { createButton, createIconButton, createTag } from "@ui/ui_template_elements"; import { createPanelHead } from "@ui/ui_template_panel_head"; import { createProgressBar, type ProgressBarHandle } from "@ui/ui_template_progress"; @@ -84,19 +85,15 @@ export async function renderB03FileInput(root: HTMLElement): Promise { const subtitle = createText(L("B03_File_Subtitle"), "muted", 14); subtitle.classList.add("b03-file__subtitle"); - const fileInput = document.createElement("input"); - fileInput.type = "file"; - fileInput.multiple = true; - fileInput.accept = UPLOAD_ALLOWED_EXT.join(","); - fileInput.className = "b03-file__native-input"; - - const dropzone = document.createElement("div"); - dropzone.className = "b03-file__dropzone"; - dropzone.tabIndex = 0; - const dropzoneLabel = document.createElement("strong"); - dropzoneLabel.textContent = L("B03_File_Select_Label"); // 설명은 좌측 안내 패널 몫이다(2026-09-03 사용자 지시) — 여기는 자리 이름만 남긴다. - dropzone.append(dropzoneLabel, fileInput); + const drop = createDrop({ + accept: UPLOAD_ALLOWED_EXT.join(","), + multiple: true, + text: L("B03_File_Select_Label"), + onFiles: (files) => onFileSelected(files), + }); + const dropzone = drop.root; + dropzone.classList.add("b03-file__dropzone"); const pageError = document.createElement("p"); pageError.className = "ui-text ui-text--error b03-file__error"; @@ -530,29 +527,6 @@ export async function renderB03FileInput(root: HTMLElement): Promise { const { detectPausedUploads, pollAnalysis, relockWhileInitialPipelineRuns, startChunkedUpload } = flow; - function onB03_File_Select_Change(): void { - onFileSelected(fileInput.files ? Array.from(fileInput.files) : []); - fileInput.value = ""; - } - - function onB03_File_Drop(event: DragEvent): void { - event.preventDefault(); - dropzone.classList.remove("is-dragging"); - onFileSelected(event.dataTransfer?.files ? Array.from(event.dataTransfer.files) : []); - } - - fileInput.addEventListener("change", onB03_File_Select_Change); - dropzone.addEventListener("click", () => fileInput.click()); - dropzone.addEventListener("keydown", (event) => { - if (event.key === "Enter" || event.key === " ") fileInput.click(); - }); - dropzone.addEventListener("dragover", (event) => { - event.preventDefault(); - dropzone.classList.add("is-dragging"); - }); - dropzone.addEventListener("dragleave", () => dropzone.classList.remove("is-dragging")); - dropzone.addEventListener("drop", onB03_File_Drop); - uploadButton = createButton({ label: L("B03_File_Upload_Button"), variant: "filled", diff --git a/B03_FileInput/B03_FileInput_UI_Style.css b/B03_FileInput/B03_FileInput_UI_Style.css index ae9a2ca63..dd8bffd9b 100644 --- a/B03_FileInput/B03_FileInput_UI_Style.css +++ b/B03_FileInput/B03_FileInput_UI_Style.css @@ -29,7 +29,6 @@ margin-top: 0; /* 단일 layout gap에 의해 제어되도록 설정 */ } -.b03-file__native-input, .b03-file__slot-input { display: none; } @@ -58,49 +57,13 @@ height: 100%; } -/* 한 줄 바(2026-09-03) — 종전 160px 블록은 안내 문구를 담느라 컸다. 문구는 좌측 - 패널로 갔으므로 여기는 「끌어 놓거나 눌러서 고르는 자리」 표시만 한다. */ +/* 한 줄 바(2026-09-03) — 파일 놓기 칸 부품을 [아이콘 · 글 · 고르기] 한 줄로 눕힌다. 종전 160px 블록은 + 안내 문구를 담느라 컸고 문구는 좌측 패널로 갔다. 칸을 꽉 채워 세 칸 높이를 맞춘다. */ .b03-file__dropzone { - padding: var(--spacing-12) var(--spacing-16); - border: 1px dashed var(--color-border); - border-radius: var(--radius-cards); - background: var(--color-surface); - display: flex; flex-direction: row; flex-wrap: wrap; - align-items: baseline; justify-content: center; - gap: var(--spacing-8); - cursor: pointer; - text-align: center; - transition: - background var(--transition-base), - border-color var(--transition-base), - box-shadow var(--transition-base); -} - -.b03-file__dropzone:hover { - background: var(--color-accent-soft); - border-color: var(--color-accent); -} - -.b03-file__dropzone:focus-visible, -.b03-file__dropzone.is-dragging { - outline: none; - background: var(--color-accent-soft); - border-color: var(--color-accent); - box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-accent) 15%, transparent); -} - -.b03-file__dropzone strong { - color: var(--color-text); - font-size: var(--text-body-sm); - font-weight: var(--font-weight-medium); -} - -.b03-file__dropzone span { - font-size: var(--text-body-sm); - color: var(--color-text-secondary); + padding: var(--spacing-8) var(--spacing-12); } /* 빈 오류 줄이 자리를 잡고 있으면 토글 아래가 통째로 비어 보인다 — 글자가 있을 때만 자리를 차지한다. */ @@ -122,41 +85,6 @@ display: flex; } -/* 완료 슬롯 재업로드 확인 모달 — 페이지 위를 덮는 단순 확인창. */ -.b03-file__modal-backdrop { - position: fixed; - inset: 0; - z-index: 1000; - display: flex; - align-items: center; - justify-content: center; - background: var(--color-scrim); -} - -.b03-file__modal { - display: flex; - flex-direction: column; - gap: var(--spacing-12); - max-width: 420px; - padding: var(--spacing-24); - border: 1px solid var(--color-border); - border-radius: var(--radius-cards); - background: var(--color-surface-raised); - box-shadow: var(--shadow-lg); -} - -.b03-file__modal p { - margin: 0; - color: var(--color-text-secondary); - white-space: pre-line; -} - -.b03-file__modal-actions { - display: flex; - gap: var(--spacing-8); - justify-content: flex-end; -} - /* 계획노선 | 지형(LAS) — 컨테이너를 둘로 나눈다(2026-08-31 사용자 지시). 노선은 카드 5장(shapefile 한 벌), 지형은 4장이라 폭을 5:4 비슷하게 준다. diff --git a/B03_FileInput/B03_FileInput_UI_Style_Temp.css b/B03_FileInput/B03_FileInput_UI_Style_Temp.css index c9aa2a262..d81242f0b 100644 --- a/B03_FileInput/B03_FileInput_UI_Style_Temp.css +++ b/B03_FileInput/B03_FileInput_UI_Style_Temp.css @@ -1,7 +1,6 @@ /* ============================================================================= * B03_FileInput_UI_Style_Temp.css - * 임시 보관함 불러오기 — 업로드 컨테이너 안 버튼 + 선택 모달 - * 모달 껍데기(.b03-file__modal / -backdrop)는 기존 확인 모달 스타일을 그대로 쓴다. + * 임시 보관함 불러오기 — 업로드 컨테이너 안 버튼 + 선택 모달(모달 부품) * ========================================================================== */ /* 버튼 하나만 담는 자리 — 테두리를 또 두르면 버튼 테두리와 이중이 된다 @@ -11,73 +10,10 @@ align-items: center; } -.b03-file__temp-modal { - min-width: min(560px, 92vw); - max-height: 80vh; -} - -/* 제목은 브라우저 기본 h3 서식이 남지 않게 템플릿 값으로 맞춘다. */ -.b03-file__temp-modal h3 { - margin: 0; - font-family: var(--font-display); - font-size: var(--text-body); - font-weight: var(--font-weight-bold); - color: var(--color-text); -} - +/* 임시 보관함 목록 — 모달 · 카드(고르는 카드) 부품 · 목록 칸만 */ .b03-file__temp-list { display: flex; flex-direction: column; gap: var(--spacing-8); overflow-y: auto; } - -.b03-file__temp-empty { - padding: var(--spacing-16); - text-align: center; - font-family: var(--font-body); - font-size: var(--text-body-sm); - color: var(--color-text-muted); -} - -/* 목록 항목은