feat(B03): 파일 입력 양식 정리 — 안내는 좌측 패널, 본문은 고르는 자리만
사용자 지적(2026-09-03) — 선택 항목이 너무 크고 대중없이 놓임. 안내는 B04·B05 와 같은 공용 좌측 패널로 빼고 본문은 고르는 자리만 남김. - `B03_FileInput_UI_Guide.ts` 신설 — 필요한 파일 / 고르는 방법 / 알아 둘 것 3묶음을 공용 오버레이 `optionsContent` 에 실음. 문단 구획은 공용 `ui-sidebar-section`. - 선택 영역 160px 블록 → 한 줄 바. 긴 문구는 패널로 옮기고 힌트는 한 줄로 교체. - 카드 `min-height: 220px` 폐지, [선택]을 제목 줄 오른쪽 끝 작은 버튼으로 이동, 빈 칸은 제목 줄만 남김. 진행바·속도·예상완료는 올라가는 동안만 표시. - 여백 정리 — 컨테이너 패딩 32 → 20, 그룹 제목 24 → 16px, 격자 간격 24 → 12. - 좌측 패널이 열리면 본문을 밀어내는 규칙 추가 — B03 은 일반 레이아웃이라 공용 워크플로 레이아웃의 padding 규칙이 없어 패널이 카드를 덮었음. 검증: 카드 높이 232 → 66px(빈 칸)·117px(파일 있음), 선택 영역 160 → 47px, 문서 높이 1408px 로 한 화면 남짓. typecheck·prettier 통과. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
/* =============================================================================
|
||||
* B03_FileInput_UI_Guide.ts
|
||||
* 파일 입력 좌측 안내 패널 (2026-09-03 사용자 지시).
|
||||
*
|
||||
* 종전에는 고르는 방법·필요한 파일 목록이 **선택 영역과 카드 안에** 길게 들어가 있어
|
||||
* 카드 한 장이 220px씩 차지했다. 안내는 한 번 읽으면 되는 것이라 다른 단계(B04·B05)와
|
||||
* 같은 자리 — 공용 오버레이의 좌측 패널(`createWorkflowOverlays.optionsContent`) — 로
|
||||
* 옮기고, 본문은 고르는 자리만 남긴다.
|
||||
*
|
||||
* 문단 구획은 공용 `ui-sidebar-section`을 쓴다(B04·B05 좌측 패널과 같은 테두리·간격).
|
||||
* ========================================================================== */
|
||||
|
||||
import { ui_locales, currentLanguageIndex } from "@ui/ui_template_locale";
|
||||
|
||||
function L(key: keyof typeof ui_locales): string {
|
||||
return ui_locales[key][currentLanguageIndex];
|
||||
}
|
||||
|
||||
/** 안내 문단 하나 — 제목 + 항목 목록. */
|
||||
function section(
|
||||
titleKey: keyof typeof ui_locales,
|
||||
itemKeys: (keyof typeof ui_locales)[],
|
||||
): HTMLElement {
|
||||
const group = document.createElement("section");
|
||||
group.className = "ui-sidebar-section b03-file__guide-group";
|
||||
|
||||
const title = document.createElement("h3");
|
||||
title.className = "b03-file__guide-title";
|
||||
title.textContent = L(titleKey);
|
||||
|
||||
const list = document.createElement("ul");
|
||||
list.className = "b03-file__guide-list";
|
||||
for (const key of itemKeys) {
|
||||
const item = document.createElement("li");
|
||||
item.textContent = L(key);
|
||||
list.append(item);
|
||||
}
|
||||
|
||||
group.append(title, list);
|
||||
return group;
|
||||
}
|
||||
|
||||
/** 좌측 패널 본문 — 필요한 파일 · 고르는 방법 · 알아 둘 것. */
|
||||
export function createInputGuide(): HTMLElement {
|
||||
const guide = document.createElement("div");
|
||||
guide.className = "b03-file__guide";
|
||||
guide.append(
|
||||
section("B03_Guide_Files_Title", [
|
||||
"B03_Guide_Files_Route",
|
||||
"B03_Guide_Files_Terrain",
|
||||
"B03_Guide_Files_Optional",
|
||||
]),
|
||||
section("B03_Guide_How_Title", [
|
||||
"B03_Guide_How_Drop",
|
||||
"B03_Guide_How_Card",
|
||||
"B03_Guide_How_Temp",
|
||||
]),
|
||||
section("B03_Guide_Notes_Title", [
|
||||
"B03_Guide_Notes_Replace",
|
||||
"B03_Guide_Notes_Crs",
|
||||
"B03_Guide_Notes_LasFree",
|
||||
]),
|
||||
);
|
||||
return guide;
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import { navigateTo } from "../A00_Common/router";
|
||||
import { attachTempBatch } from "../B01_Dashboard/B01_Dashboard_Api_Temp";
|
||||
import { clearRouteLatestCache } from "../B05_Profile/B05_Profile_Api_Fetch";
|
||||
import { invalidateSectionDetail } from "../B06_Section/B06_Section_Section_Store";
|
||||
import { createInputGuide } from "./B03_FileInput_UI_Guide";
|
||||
import { createTempPicker } from "./B03_FileInput_UI_TempPicker";
|
||||
import { workflowSteps } from "../A00_Common/b_page_scaffold";
|
||||
import {
|
||||
@@ -842,10 +843,15 @@ export async function renderB03FileInput(root: HTMLElement): Promise<void> {
|
||||
content: [uploadControlPanel, cardsContainer],
|
||||
});
|
||||
layout.content.classList.add("b03-file__main-layout");
|
||||
// 고르는 방법·필요한 파일 안내는 좌측 패널로 뺐다 — 본문은 고르는 자리만 남긴다
|
||||
// (2026-09-03 사용자 지시). 자리·여닫기는 B04·B05 좌측 패널과 같은 공용 오버레이다.
|
||||
const overlays = createWorkflowOverlays({
|
||||
title: L("B03_File_Title"),
|
||||
progressContent,
|
||||
showTitlePanel: false,
|
||||
optionsContent: createInputGuide(),
|
||||
// 공용 워크플로 레이아웃(B04·B05)이 하는 일을 여기서도 한다 — 패널이 열리면 본문을
|
||||
// 그만큼 밀어내지 않으면 안내가 카드 위를 덮는다.
|
||||
onOptionsOpenChange: (isOpen) => layout.root.classList.toggle("is-options-open", isOpen),
|
||||
});
|
||||
layout.root.append(overlays.root);
|
||||
pageRoot = layout.root;
|
||||
|
||||
@@ -19,9 +19,10 @@
|
||||
.b03-file__control-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-20);
|
||||
gap: var(--spacing-16);
|
||||
background: var(--color-canvas, #ffffff);
|
||||
padding: var(--spacing-32);
|
||||
/* 여백 32 → 20 (2026-09-03) — 고르는 자리만 남기고 안내를 좌측 패널로 뺐다. */
|
||||
padding: var(--spacing-20);
|
||||
border-radius: var(--radius-large, 24px); /* Wiza 24px 대형 둥글기 */
|
||||
border: 1px solid var(--color-mist, #e6e2e3);
|
||||
box-shadow: var(--shadow-lg);
|
||||
@@ -43,15 +44,17 @@
|
||||
}
|
||||
|
||||
/* Wiza 스타일 가이드의 Lavender Glow 그라데이션 및 soft purple border hover */
|
||||
/* 한 줄 바(2026-09-03) — 종전 160px 블록은 안내 문구를 담느라 컸다. 문구는 좌측
|
||||
패널로 갔으므로 여기는 「끌어 놓거나 눌러서 고르는 자리」 표시만 한다. */
|
||||
.b03-file__dropzone {
|
||||
min-height: 160px;
|
||||
padding: var(--spacing-32) var(--spacing-24);
|
||||
border: 2px dashed var(--color-mist, #e6e2e3);
|
||||
border-radius: var(--radius-large, 24px);
|
||||
padding: var(--spacing-12) var(--spacing-16);
|
||||
border: 1px dashed var(--color-mist, #e6e2e3);
|
||||
border-radius: var(--radius-cards, 8px);
|
||||
background: var(--color-paper, #f6f7fa);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
justify-content: center;
|
||||
gap: var(--spacing-8);
|
||||
cursor: pointer;
|
||||
@@ -77,7 +80,7 @@
|
||||
|
||||
.b03-file__dropzone strong {
|
||||
color: var(--color-deep-iris, #26114a);
|
||||
font-size: var(--text-body, 16px);
|
||||
font-size: var(--text-body-sm, 14px);
|
||||
font-weight: var(--font-weight-medium, 500);
|
||||
}
|
||||
|
||||
@@ -185,14 +188,67 @@
|
||||
.b03-file__columns {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: var(--spacing-24);
|
||||
gap: var(--spacing-16);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
/* 좌측 안내 패널이 열리면 본문을 그만큼 밀어낸다 — 공용 워크플로 레이아웃(B04·B05)의
|
||||
`.ui-workflow-layout__body` 규칙과 같은 값. 접히면 손잡이 폭만 남긴다. */
|
||||
.b03-file__main-layout {
|
||||
transition: padding-left var(--transition-base);
|
||||
}
|
||||
|
||||
.b03-file.is-options-open .b03-file__main-layout {
|
||||
padding-left: min(var(--wf-left-panel-width), calc(100vw - var(--spacing-48)));
|
||||
}
|
||||
|
||||
.b03-file:not(.is-options-open) .b03-file__main-layout {
|
||||
padding-left: var(--spacing-24);
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.b03-file.is-options-open .b03-file__main-layout {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* --- 좌측 안내 패널 (2026-09-03) — 본문에서 뺀 설명이 사는 자리. --- */
|
||||
.b03-file__guide {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-12);
|
||||
padding: var(--spacing-12);
|
||||
}
|
||||
|
||||
.b03-file__guide-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-8);
|
||||
padding: var(--spacing-12);
|
||||
}
|
||||
|
||||
.b03-file__guide-title {
|
||||
margin: 0;
|
||||
font-size: var(--text-body-sm, 14px);
|
||||
font-weight: var(--font-weight-medium, 500);
|
||||
color: var(--color-text, #26114a);
|
||||
}
|
||||
|
||||
.b03-file__guide-list {
|
||||
margin: 0;
|
||||
padding-left: var(--spacing-16);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-4);
|
||||
font-size: var(--text-caption, 12px);
|
||||
line-height: 1.55;
|
||||
color: var(--color-text-secondary, #615e6e);
|
||||
}
|
||||
|
||||
.b03-file__group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-20);
|
||||
gap: var(--spacing-12);
|
||||
}
|
||||
|
||||
.b03-file__group-hint {
|
||||
@@ -201,17 +257,18 @@
|
||||
margin: calc(var(--spacing-8) * -1) 0 0 0;
|
||||
}
|
||||
|
||||
/* 제목 24px → 본문 크기(2026-09-03) — 컨테이너가 둘뿐이라 큰 제목이 자리만 먹었다. */
|
||||
.b03-file__group-title {
|
||||
font-size: var(--text-subheading, 24px);
|
||||
font-size: var(--text-body, 16px);
|
||||
color: var(--color-deep-iris, #26114a);
|
||||
font-family: var(--font-britti-sans, inherit);
|
||||
margin: 0 0 var(--spacing-8) 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.b03-file__group-content {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: var(--spacing-24);
|
||||
gap: var(--spacing-12);
|
||||
}
|
||||
|
||||
/* 업로드 중에는 화면 조작을 막는다 — 중복 업로드·단계 이동 방지(2026-08-08 사용자 지시). */
|
||||
@@ -235,16 +292,17 @@
|
||||
}
|
||||
|
||||
/* Wiza 8px radius 카드 */
|
||||
/* 카드 한 장 = 파일 한 칸. 빈 칸은 **한 줄**로 끝난다(2026-09-03 사용자 지시) —
|
||||
파일이 붙거나 올라가는 중에만 아래 내용(파일명·진행바)이 펼쳐진다. */
|
||||
.b03-file__card {
|
||||
min-height: 220px;
|
||||
padding: var(--spacing-24); /* 내부 전체 패딩 확대 */
|
||||
padding: var(--spacing-12) var(--spacing-16);
|
||||
border: 1px solid var(--color-mist, #e6e2e3);
|
||||
border-radius: var(--radius-cards, 8px);
|
||||
background: var(--color-canvas, #ffffff);
|
||||
box-shadow: var(--shadow-sm);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-20);
|
||||
gap: var(--spacing-8);
|
||||
transition:
|
||||
transform var(--transition-base, 0.2s),
|
||||
border-color var(--transition-base, 0.2s),
|
||||
@@ -277,9 +335,11 @@
|
||||
|
||||
/* 카드가 좁아졌다(컨테이너 2열 × 카드 2열, 2026-08-31). 격자로 고정하면 제목이
|
||||
글자 단위로 접히므로, 자리가 모자라면 배지·삭제 버튼이 다음 줄로 내려가게 한다. */
|
||||
/* 제목·상태·[선택]이 **한 줄**에 선다(2026-09-03) — 줄바꿈을 허용하면 [선택]이 아래로
|
||||
내려가 카드가 두 줄이 됐다. 자리가 모자라면 제목이 줄어든다(min-width: 0). */
|
||||
.b03-file__card-header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-wrap: nowrap;
|
||||
gap: var(--spacing-8);
|
||||
align-items: center;
|
||||
}
|
||||
@@ -300,11 +360,10 @@
|
||||
|
||||
.b03-file__card-heading {
|
||||
min-width: 0;
|
||||
flex: 1 1 55%;
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
margin-top: 2px; /* 제목 상단 여유 추가 */
|
||||
gap: 1px;
|
||||
}
|
||||
|
||||
.b03-file__card-label {
|
||||
@@ -357,25 +416,29 @@
|
||||
}
|
||||
|
||||
.b03-file__card-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
gap: var(--spacing-16); /* 버튼 하단 및 내부 간격 확대 */
|
||||
padding-bottom: var(--spacing-8); /* 파일 선택 버튼 하단 패딩 확보 */
|
||||
gap: var(--spacing-8);
|
||||
}
|
||||
|
||||
/* 빈 칸은 제목 줄만 남긴다 — 파일이 붙으면 이름·크기가, 올라가는 중에는 진행바가 선다. */
|
||||
.b03-file__card--empty .b03-file__card-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* [선택]은 제목 줄 오른쪽 끝의 작은 버튼 — 종전 전폭 40px 버튼이 카드 높이를 키웠다. */
|
||||
.b03-file__card-select {
|
||||
width: 100%;
|
||||
min-height: 40px; /* 버튼 높이 증가 */
|
||||
flex: 0 0 auto;
|
||||
min-height: 26px;
|
||||
padding: 0 var(--spacing-8);
|
||||
border: 1px solid var(--color-mist, #e6e2e3);
|
||||
border-radius: var(--radius-buttons, 8px);
|
||||
color: var(--color-deep-iris, #26114a);
|
||||
background: var(--color-canvas, #ffffff);
|
||||
font-weight: var(--font-weight-medium, 500);
|
||||
font-size: var(--text-body-sm, 14px);
|
||||
font-size: var(--text-caption, 12px);
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
margin-bottom: var(--spacing-8); /* 파일 선택 버튼 하단 마진 추가 */
|
||||
transition:
|
||||
background var(--transition-base, 0.2s),
|
||||
border-color var(--transition-base, 0.2s);
|
||||
@@ -395,12 +458,18 @@
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
/* 진행바·속도·예상완료는 **올라가는 동안만** 보인다(2026-09-03) — 끝난 카드에 남겨 두면
|
||||
읽을 일 없는 세 줄이 카드 높이를 그대로 차지했다. */
|
||||
.b03-file__progress-section {
|
||||
display: flex;
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-8);
|
||||
}
|
||||
|
||||
.b03-file__card--uploading .b03-file__progress-section {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.b03-file__progress-bar-container {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
|
||||
@@ -208,10 +208,10 @@ export function createFileCardTemplate(): HTMLTemplateElement {
|
||||
<span class="b03-file__card-ext"></span>
|
||||
</div>
|
||||
<div class="b03-file__card-badge-container"></div>
|
||||
<button class="b03-file__card-select" type="button"></button>
|
||||
<button class="b03-file__card-remove" type="button"></button>
|
||||
</div>
|
||||
<div class="b03-file__card-content">
|
||||
<button class="b03-file__card-select" type="button"></button>
|
||||
<input class="b03-file__slot-input" type="file" />
|
||||
<div class="b03-file__file-info">
|
||||
<span class="b03-file__file-name"></span>
|
||||
|
||||
Reference in New Issue
Block a user