refactor(B09): 264 공기 옵션 카드 = 좌측 패널 공용 카드 꼴
- createPanelCard · 공용 칸(createInputField · createSelectField) · 공용 체크박스로 짜기 - B05 스타일 CSS 덧칠 import 지움 · 동작 · 저장 칸 그대로 - 숨김 = style.display(공용 카드 flex 가 hidden 을 덮음) · 두 칸 줄은 바깥 div 로 감싸 접기 유지 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STqEqztUthVFBmEP18wBSz
This commit is contained in:
@@ -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 || {}, {});
|
||||
|
||||
Reference in New Issue
Block a user