diff --git a/B09_Estimation/draft/B09_Draft_Schedule_Panel.ts b/B09_Estimation/draft/B09_Draft_Schedule_Panel.ts index 379a59b63..9bd64b379 100644 --- a/B09_Estimation/draft/B09_Draft_Schedule_Panel.ts +++ b/B09_Estimation/draft/B09_Draft_Schedule_Panel.ts @@ -4,10 +4,12 @@ * 등록 = `B09_Draft_Schedule_UI` 가 DRAFT.panels(카드) · DRAFT.extend(값 맞춤)에 넣음 — * 본 코드 훅 = `…_UI_Shell` 이 「데이터 점검」 아래 · [저장] 묶음 위에 붙이는 한 줄 * 값 = user.schedule(캐시 → [저장] 한 번에) · 공기산출 · 공기집계 표 칸과 같은 값(어디서 고쳐도 한 벌) - * 꼴 = 좌측 패널 공용(B05/B06 「구조물 배치」 칸 — 라벨 위 · 입력 아래 · 두 칸 줄 · 체크) + * 꼴 = 좌측 패널 공용 카드(269 · createPanelCard · 공용 칸 · 체크박스) — draft 덧칠 CSS 없음 * ========================================================================== */ -import "../../B05_Profile/B05_Profile_UI_Style.css"; +import { createPanelCard } from "@ui/ui_template_collapsible"; +import { createInputField, createSelectField } from "@ui/ui_template_elements"; +import { createCheckbox } from "@ui/ui_template_checkbox"; import { num, type Row } from "../B09_Estimation_Calc_Base"; import { parseNumber } from "../B09_Estimation_UI_Tabs"; import { DEFAULTS } from "./B09_Draft_Schedule_Calc"; @@ -46,20 +48,16 @@ export function syncSchedulePanel(payload: Row, user: Row): void { syncNow?.(user.schedule || {}, payload.inputs?.schedule || {}); } -function field(label: string, input: HTMLElement): HTMLLabelElement { - const wrapper = document.createElement("label"); - wrapper.className = "b05-route__field"; - const caption = document.createElement("span"); - caption.textContent = label; - wrapper.append(caption, input); - return wrapper; -} - +/** 두 칸 줄 — 공용 줄 class 가 없어 자리에서(draft 폴더째 지우면 사라짐) · + * 바깥 div 는 꾸밈 없음 = 카드 접기(`display: none`)가 먹게 */ function pair(...items: HTMLElement[]): HTMLDivElement { const row = document.createElement("div"); - row.className = "b05-route__field-row"; + row.style.cssText = + "display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--spacing-8)"; row.append(...items); - return row; + const outer = document.createElement("div"); + outer.append(row); + return outer; } export function createSchedulePanel(user: () => Row, setUser: (next: Row) => void): HTMLElement { @@ -71,11 +69,8 @@ export function createSchedulePanel(user: () => Row, setUser: (next: Row) => voi }; /** 수 칸 — 빈칸 · 기본값 = 지움(기본) · 범위 밖 = 되돌림 */ - const number = (key: string, label: string, min: number, max: number): HTMLLabelElement => { - const input = document.createElement("input"); - input.type = "number"; - input.min = String(min); - input.max = String(max); + const number = (key: string, label: string, min: number, max: number): HTMLElement => { + const { root, input } = createInputField({ label, type: "number", compact: true, min, max }); input.step = "any"; input.dataset.b09Schedule = key; let last: Row = {}; @@ -94,16 +89,12 @@ export function createSchedulePanel(user: () => Row, setUser: (next: Row) => voi else s[key] = v; }); }); - return field(label, input); + return root; }; /** 고르기 칸 — 첫째 = 기본(고르면 지움) · options 없으면 원천에서(기후 자료) */ - const choose = ( - key: string, - label: string, - options?: Array<[string, string]>, - ): HTMLLabelElement => { - const select = document.createElement("select"); + const choose = (key: string, label: string, options?: Array<[string, string]>): HTMLElement => { + const { root, select, setOptions } = createSelectField({ label, options: [], compact: true }); select.dataset.b09Schedule = key; let values: string[] = []; syncs.push((mine, src) => { @@ -115,7 +106,7 @@ export function createSchedulePanel(user: () => Row, setUser: (next: Row) => voi ]); if (list.map(([v]) => v).join() !== values.join()) { values = list.map(([v]) => v); - select.replaceChildren(...list.map(([v, text]) => new Option(text, v))); + setOptions(list.map(([value, text]) => ({ value, text }))); } select.value = values.includes(mine[key]) ? mine[key] : (values[0] ?? ""); }); @@ -125,11 +116,11 @@ export function createSchedulePanel(user: () => Row, setUser: (next: Row) => voi else s[key] = select.value; }), ); - return field(label, select); + return root; }; - const start = document.createElement("input"); - start.type = "date"; + const startField = createInputField({ label: "착공일", type: "date", compact: true }); + const start = startField.input; start.dataset.b09Schedule = "start"; syncs.push((mine, src) => { const at: Row = { ...(src.start || {}), ...(mine.start || {}) }; @@ -146,10 +137,7 @@ export function createSchedulePanel(user: () => Row, setUser: (next: Row) => voi }); const checks = HOLIDAY_LABELS.map(([kind, label]) => { - const wrapper = document.createElement("label"); - wrapper.className = "b05-route__check"; - const input = document.createElement("input"); - input.type = "checkbox"; + const { root, input } = createCheckbox(label); input.dataset.b09Holiday = kind; syncs.push((mine) => { input.checked = !(mine.holiday_off || []).includes(kind); @@ -163,19 +151,20 @@ export function createSchedulePanel(user: () => Row, setUser: (next: Row) => voi else delete s.holiday_off; }), ); - wrapper.append(input, document.createTextNode(label)); - return wrapper; + return root; }); const holidayBox = document.createElement("div"); - holidayBox.className = "b05-route__field"; + holidayBox.className = "ui-field"; const holidayCaption = document.createElement("span"); + holidayCaption.className = "ui-field__label"; holidayCaption.textContent = "공휴일 넣기(그 밖 법정공휴일은 늘 넣음)"; holidayBox.append(holidayCaption, ...checks); - const body = document.createElement("div"); - body.className = "b05-route__panel-body"; - body.append( - field("착공일", start), + const section = createPanelCard("공기 옵션"); + section.dataset.b09SchedulePanel = ""; + section.style.display = "none"; // 원천(서버 공기 자료)이 오면 보임 · hidden 은 공용 카드 flex 가 덮음 + section.append( + startField.root, choose("climate_set", "기후 자료(달마다 덮개는 공기집계 표)"), choose("rest", "쉬는 날", CHOICES.rest), holidayBox, @@ -197,17 +186,9 @@ export function createSchedulePanel(user: () => Row, setUser: (next: Row) => voi choose("c_round", "중복일수 C 끝수", CHOICES.c_round), choose("last_off", "마지막 달 비작업일", CHOICES.last_off), ); - const section = document.createElement("section"); - section.className = "ui-collapsible ui-sidebar-section ui-sidebar-card"; - section.dataset.b09SchedulePanel = ""; - section.hidden = true; // 원천(서버 공기 자료)이 오면 보임 - const heading = document.createElement("h3"); - heading.className = "ui-collapsible__title"; - heading.textContent = "공기 옵션"; - section.append(heading, body); syncNow = (mine, src) => { - section.hidden = !src.climates; + section.style.display = src.climates ? "" : "none"; for (const sync of syncs) sync(mine, src); }; syncNow(user().schedule || {}, {});