diff --git a/A00_Common/design/design_page.ts b/A00_Common/design/design_page.ts index bfa6f04c4..dfff7f67f 100644 --- a/A00_Common/design/design_page.ts +++ b/A00_Common/design/design_page.ts @@ -49,6 +49,12 @@ import { peekSectionDetail, } from "../../B06_Section/B06_Section_Section_Store"; import "./design_page.css"; +// 클래스로 붙이는 부품(체크 · 빈 상태 · 범례 · 보조 글 · 표)의 CSS — B05 · B06 화면 파일이 시험 때문에 import 없이 클래스만 씀(553-2) +import "@ui/ui_template_checkbox"; +import "@ui/ui_template_empty"; +import "@ui/ui_template_flow_legend"; +import "@ui/ui_template_table"; +import "@ui/ui_template_text"; export type { DesignPageShared } from "./design_shared"; diff --git a/B05_Profile/B05_Profile_UI_IrregularStations.ts b/B05_Profile/B05_Profile_UI_IrregularStations.ts index ba28b9afb..c5678d42e 100644 --- a/B05_Profile/B05_Profile_UI_IrregularStations.ts +++ b/B05_Profile/B05_Profile_UI_IrregularStations.ts @@ -249,7 +249,7 @@ export function createIrregularStationsSection( const list = document.createElement("ul"); list.className = "b05-route__irregular-list"; const help = document.createElement("p"); - help.className = "b05-route__note"; + help.className = "ui-text ui-text--muted b05-route__note"; // 부품 보조 글(553-2) help.textContent = "구조물을 설치할 위치를 측점번호+잔여거리로 추가합니다. 목록에서 고르면 수정·삭제할 수 있습니다."; @@ -307,9 +307,13 @@ export function createIrregularStationsSection( function renderList(): void { list.replaceChildren(); if (!stations.length) { + // 부품 빈 상태 작은 꼴(553-2) const empty = document.createElement("li"); - empty.className = "b05-route__irregular-empty"; - empty.textContent = "추가된 비정규 측점이 없습니다."; + empty.className = "ui-empty ui-empty--small b05-route__irregular-empty"; + const text = document.createElement("p"); + text.className = "ui-empty__text"; + text.textContent = "추가된 비정규 측점이 없습니다."; + empty.append(text); list.append(empty); return; } diff --git a/B05_Profile/B05_Profile_UI_Panel_Fields.ts b/B05_Profile/B05_Profile_UI_Panel_Fields.ts index 066ca8a4a..7c886b8b3 100644 --- a/B05_Profile/B05_Profile_UI_Panel_Fields.ts +++ b/B05_Profile/B05_Profile_UI_Panel_Fields.ts @@ -74,12 +74,17 @@ export function numberField(label: string, value = ""): WrappedInput { } export function checkbox(label: string, checked: boolean): WrappedInput { + // 부품 「체크」 클래스(553-2) — 시험이 별칭 없이 이 파일을 돌려 클래스로 붙임 const wrapper = document.createElement("label"); - wrapper.className = "b05-route__check"; + wrapper.className = "ui-checkbox b05-route__check"; const input = document.createElement("input"); input.type = "checkbox"; + input.className = "ui-checkbox__input"; input.checked = checked; - wrapper.append(input, document.createTextNode(label)); + const caption = document.createElement("span"); + caption.className = "ui-checkbox__text"; + caption.textContent = label; + wrapper.append(input, caption); return Object.assign(input, { wrapper }); } diff --git a/B05_Profile/B05_Profile_UI_Panel_Settings.ts b/B05_Profile/B05_Profile_UI_Panel_Settings.ts index daf80e9aa..d23861941 100644 --- a/B05_Profile/B05_Profile_UI_Panel_Settings.ts +++ b/B05_Profile/B05_Profile_UI_Panel_Settings.ts @@ -133,7 +133,7 @@ export function createSettingsPart(callbacks: SettingsPartCallbacks) { }); }); const criteriaNote = document.createElement("p"); - criteriaNote.className = "b05-route__note"; + criteriaNote.className = "ui-text ui-text--muted b05-route__note"; // 부품 보조 글(553-2) const gradeAdvanced = document.createElement("details"); const gradeSummary = document.createElement("summary"); gradeSummary.textContent = "기준값 직접 지정"; diff --git a/B05_Profile/B05_Profile_UI_Profile_CrossModal.css b/B05_Profile/B05_Profile_UI_Profile_CrossModal.css index 4f7cff4dc..3c5316050 100644 --- a/B05_Profile/B05_Profile_UI_Profile_CrossModal.css +++ b/B05_Profile/B05_Profile_UI_Profile_CrossModal.css @@ -10,7 +10,7 @@ width: min(380px, calc(100% - 24px)); padding: var(--spacing-12, 12px); border: 1px solid var(--color-border); - border-radius: var(--radius-8, 6px); + border-radius: var(--radius-cards); background: var(--color-surface-raised); color: var(--color-text-body); box-shadow: 0 4px 16px color-mix(in srgb, var(--color-text-body) 18%, transparent); @@ -39,7 +39,7 @@ height: 200px; overflow: hidden; border: 1px solid var(--color-border); - border-radius: var(--radius-8, 6px); + border-radius: var(--radius-inputs); background: var(--color-surface); } diff --git a/B05_Profile/B05_Profile_UI_Profile_MassHaul.ts b/B05_Profile/B05_Profile_UI_Profile_MassHaul.ts index 33f9f2a81..6f98cb611 100644 --- a/B05_Profile/B05_Profile_UI_Profile_MassHaul.ts +++ b/B05_Profile/B05_Profile_UI_Profile_MassHaul.ts @@ -293,9 +293,13 @@ export function createRouteMassHaulPanel( bar.replaceChildren(); scroll.replaceChildren(); legendLayer.replaceChildren(); - const empty = document.createElement("span"); - empty.className = "b05-profile__masshaul-empty"; - empty.textContent = message; + // 부품 빈 상태 작은 꼴(553-2) + const empty = document.createElement("div"); + empty.className = "ui-empty ui-empty--small b05-profile__masshaul-empty"; + const text = document.createElement("p"); + text.className = "ui-empty__text"; + text.textContent = message; + empty.append(text); bar.append(empty); } diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Chrome.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Chrome.ts index f79b34212..bd281e2dc 100644 --- a/B05_Profile/B05_Profile_UI_RouteEdit_Chrome.ts +++ b/B05_Profile/B05_Profile_UI_RouteEdit_Chrome.ts @@ -135,9 +135,11 @@ export function createRouteEditChrome(
노선을 읽는 중… - - 예상노선(원본) - 계획노선 + + 예상노선(원본) + 계획노선
-
- 예상노선(원본) - 창을 연 노선 - 미리 보기 +
+ 예상노선(원본) + 창을 연 노선 + 미리 보기
휠 = 확대 · 축소   끌기 = 이동   ↺ ↻ = 회전
@@ -287,7 +290,7 @@ export function openRecommendModal(params: RecommendParams): void { for (const key of WEIGHT_KEYS) { const bar = document.createElement("div"); bar.className = "b05-routerec__bar"; - const numField = createInputField({ type: "number", min: 0, max: 100, compact: true }); + const numField = createInputField({ type: "number", min: 0, max: 100, size: 32 }); // 부품 입력 단 32(553-2) numField.input.step = "1"; numField.input.inputMode = "numeric"; numField.input.classList.add("b05-routerec__num"); @@ -321,7 +324,7 @@ export function openRecommendModal(params: RecommendParams): void { row.title = field.title; const name = document.createElement("span"); name.textContent = field.label; - const input = createInputField({ type: "number", min: 0, compact: true }); + const input = createInputField({ type: "number", min: 0, size: 32 }); // 부품 입력 단 32(553-2) input.input.inputMode = "decimal"; input.input.step = "0.1"; input.input.dataset.criteria = key; @@ -332,7 +335,7 @@ export function openRecommendModal(params: RecommendParams): void { criteriaBox.append(row); } - const targetField = createInputField({ type: "number", min: 0, max: 100, compact: true }); + const targetField = createInputField({ type: "number", min: 0, max: 100, size: 32 }); // 부품 입력 단 32(553-2) targetField.input.inputMode = "decimal"; targetField.input.step = "0.1"; targetField.input.dataset.criteria = TARGET_GRADE_KEY; diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Recommend_Profile.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Recommend_Profile.ts index b96c4cf5e..d4a2944c2 100644 --- a/B05_Profile/B05_Profile_UI_RouteEdit_Recommend_Profile.ts +++ b/B05_Profile/B05_Profile_UI_RouteEdit_Recommend_Profile.ts @@ -10,8 +10,6 @@ * (`initial_profile` · 438 직선화 · 종단곡선 포함)을 펴서 같은 그림에 선 하나 · 한 줄로 더한다. * ========================================================================== */ -import { renderDataTableHtml, type DataColumn } from "@ui/ui_template_data_table"; - /** 후보 하나의 균형 종단 — 서버 `metrics.profile`. */ export interface BalanceProfile { stationsM: number[]; @@ -183,35 +181,37 @@ export function profileSvg( ${initialPath}`; } -/** 그림 아래 범례 — 그린 선만. */ +/** 그림 아래 범례 — 그린 선만 · 부품 「범례」(553-2) · 색 = 그린 선 값. */ export function profileLegend(hasPlan: boolean, hasInitial: boolean): string { - const item = (cls: string, name: string): string => `${name}`; - return `
${[ - item("is-ground", "지반선"), - hasPlan ? item("is-plan", "균형 계획선") : "", - hasInitial ? item("is-initial", "적용될 초기 종단") : "", + const item = (cls: string, kind: string, color: string, name: string): string => + `${name}`; + return `
${[ + item("is-ground", "line", "var(--draw-text-secondary)", "지반선"), + hasPlan ? item("is-plan", "line", "var(--draw-primary)", "균형 계획선") : "", + hasInitial ? item("is-initial", "dash", "var(--map-route)", "적용될 초기 종단") : "", ].join("")}
`; } -const CANDIDATE_COLUMNS: DataColumn[] = [ - { key: "name", label: "후보" }, - { key: "cut", label: "절토" }, - { key: "fill", label: "성토" }, - { key: "mass", label: "누가토량" }, - { key: "grade", label: "최대 종단경사" }, -]; +const CANDIDATE_COLUMNS = ["후보", "절토", "성토", "누가토량", "최대 종단경사"]; -/** 이 모달에서 셈한 후보들 — 갈래 이름 · 절 · 성 · 누가토량(±) · 최대 종단경사 표. 비면 빈 글. */ +const escapeHtml = (text: string): string => + text.replace(/&/g, "&").replace(//g, ">"); + +/** 이 모달에서 셈한 후보들 — 갈래 이름 · 절 · 성 · 누가토량(±) · 최대 종단경사 표. 비면 빈 글. + * 꼴 = 부품 「표」 데이터표(`ui-table--data` · 553-2) — 이름 칸 왼쪽 · 수 칸 오른쪽. */ export function candidatesTable(rows: Array<[string, BalanceProfile]>): string { if (!rows.length) return ""; - return renderDataTableHtml({ - columns: CANDIDATE_COLUMNS, - rows: rows.map(([name, b]) => ({ - name, - cut: m3(b.cutM3), - fill: m3(b.fillM3), - mass: signedM3(b.massEndM3), - grade: pct(b.maxGradePct), - })), + const end = (i: number): string => (i ? ' class="is-end"' : ""); + const head = CANDIDATE_COLUMNS.map((label, i) => `${label}`); + const body = rows.map(([name, b]) => { + const cells = [ + escapeHtml(name), + m3(b.cutM3), + m3(b.fillM3), + signedM3(b.massEndM3), + pct(b.maxGradePct), + ]; + return `${cells.map((cell, i) => `${cell}`).join("")}`; }); + return `
${head.join("")}${body.join("")}
`; } diff --git a/B05_Profile/B05_Profile_UI_Structures_List.ts b/B05_Profile/B05_Profile_UI_Structures_List.ts index 2570cf353..755186369 100644 --- a/B05_Profile/B05_Profile_UI_Structures_List.ts +++ b/B05_Profile/B05_Profile_UI_Structures_List.ts @@ -177,9 +177,13 @@ export function renderStructureList(params: StructureListParams): void { ].sort((left, right) => left.anchor - right.anchor); if (!rows.length) { + // 부품 빈 상태 작은 꼴(553-2) const empty = document.createElement("li"); - empty.className = "b05-route__irregular-empty"; - empty.textContent = "배치된 구조물이 없습니다."; + empty.className = "ui-empty ui-empty--small b05-route__irregular-empty"; + const text = document.createElement("p"); + text.className = "ui-empty__text"; + text.textContent = "배치된 구조물이 없습니다."; + empty.append(text); list.append(empty); return; } diff --git a/B05_Profile/B05_Profile_UI_Structures_Panel_Options.ts b/B05_Profile/B05_Profile_UI_Structures_Panel_Options.ts index aaa4756b0..7ffd8e5dc 100644 --- a/B05_Profile/B05_Profile_UI_Structures_Panel_Options.ts +++ b/B05_Profile/B05_Profile_UI_Structures_Panel_Options.ts @@ -243,7 +243,7 @@ export function markRequired( const box = entry.input.closest("[data-option-keys]")?.parentElement; if (!box || box.querySelector(":scope > .b05-structure__required-note")) continue; const note = document.createElement("p"); - note.className = "b05-structure__required-note"; + note.className = "ui-text ui-text--error b05-structure__required-note"; // 부품 상태 글(553-2) note.textContent = "필수 칸 비어 있음 — [저장] 전 채움"; box.append(note); } diff --git a/B05_Profile/B05_Profile_UI_Style.css b/B05_Profile/B05_Profile_UI_Style.css index ae4585097..b60d85b8b 100644 --- a/B05_Profile/B05_Profile_UI_Style.css +++ b/B05_Profile/B05_Profile_UI_Style.css @@ -295,8 +295,7 @@ html.is-bm-route .b05-route__view-controls { } .b05-route__panel-body, -.b05-route__field, -.b05-route__metrics { +.b05-route__field { display: flex; flex-direction: column; min-width: 0; @@ -325,16 +324,14 @@ html.is-bm-route .b05-route__view-controls { } .b05-route__field, -.b05-route__check, -.b05-route__metrics { +.b05-route__check { color: var(--color-text-body); font-size: var(--text-caption); } .b05-route__field input, .b05-route__field select, -.b05-route__panel-section > select, -.b05-route__textarea { +.b05-route__panel-section > select { width: 100%; min-width: 0; padding: var(--spacing-8); @@ -392,12 +389,12 @@ html.is-bm-route .b05-route__view-controls { } .b05-route__irregular-item:hover { - border-color: var(--color-royal-amethyst, rgb(109 40 217)); + border-color: var(--color-accent); } .b05-route__irregular-item.is-selected { - border-color: var(--color-royal-amethyst, rgb(109 40 217)); - background: color-mix(in srgb, var(--color-royal-amethyst, rgb(109 40 217)) 12%, transparent); + border-color: var(--color-accent); + background: color-mix(in srgb, var(--color-accent) 12%, transparent); } .b05-route__irregular-item strong { @@ -417,10 +414,8 @@ html.is-bm-route .b05-route__view-controls { white-space: nowrap; } +/* 빈 목록 = 부품 빈 상태 작은 꼴(553-2) */ .b05-route__irregular-empty { - padding: var(--spacing-4) 0; - color: var(--color-text-muted); - font-size: var(--text-caption); list-style: none; } @@ -440,38 +435,6 @@ html.is-bm-route .b05-route__view-controls { gap: var(--spacing-8); } -.b05-route__button-grid, -.b05-route__palette { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - min-width: 0; - gap: var(--spacing-8); -} - -.b05-route__chip { - padding: var(--spacing-8); - border: 1px solid var(--color-border); - border-radius: var(--radius-inputs); - background: var(--color-surface); - color: var(--color-text-body); - font-size: var(--text-caption); - cursor: pointer; -} - -.b05-route__chip.is-ep, -.b05-route__chip.is-fp { - color: var(--color-danger); -} - -.b05-route__chip.is-bp { - color: var(--color-success); -} - -.b05-route__chip.is-cp, -.b05-route__stale { - color: var(--color-warning); -} - /* 사이드 최하단 고정 영역 — 공용 ui-sidebar-actions(sticky·배경·상단 구분선)를 그대로 쓰되, 안쪽은 [구조물 목록][중간 구분선][액션 버튼 행] 세로 배치로 되돌린다 (2026-08-18 사용자 지시). */ @@ -494,23 +457,12 @@ html.is-bm-route .b05-route__view-controls { flex: 1; } -.b05-route__stale { - font-size: var(--text-caption); - font-weight: var(--font-weight-medium); -} - .b05-route__panel details { color: var(--color-text-body); font-size: var(--text-caption); } -/* 계획선 설계 폼 안내문 */ -.b05-route__note { - margin: 0; - color: var(--color-text-muted, var(--color-plum-velvet)); - font-size: var(--text-caption); - line-height: 1.4; -} +/* 계획선 설계 폼 안내문 = 부품 보조 글(553-2) */ /* 종단면도 상단 절·성토 균형 지표 바 */ .b05-route-profile__balance { @@ -536,31 +488,31 @@ html.is-bm-route .b05-route__view-controls { } .b05-route-profile__balance-item em { - color: var(--color-text-muted, var(--color-plum-velvet)); + color: var(--color-text-muted); font-style: normal; } .b05-route-profile__balance-item.is-cut em { - color: rgb(220 38 38); + color: var(--color-danger); } .b05-route-profile__balance-item.is-fill em { - color: rgb(37 99 235); + color: var(--color-info); } .b05-route-profile__balance-item.is-over, .b05-route-profile__balance-item.is-unsaved { - color: rgb(180 83 9); + color: var(--color-warning); font-weight: var(--font-weight-medium); } .b05-route-profile__balance-item.is-edited em { - color: var(--color-royal-amethyst, rgb(109 40 217)); + color: var(--color-accent); } .b05-route-profile__balance-warning { overflow: hidden; - color: rgb(180 83 9); + color: var(--color-warning); text-overflow: ellipsis; } diff --git a/B05_Profile/B05_Profile_UI_Style_MassHaul.css b/B05_Profile/B05_Profile_UI_Style_MassHaul.css index 81aa3736b..e912ce858 100644 --- a/B05_Profile/B05_Profile_UI_Style_MassHaul.css +++ b/B05_Profile/B05_Profile_UI_Style_MassHaul.css @@ -62,7 +62,7 @@ height: var(--b05-masshaul-height, 280px); border-top: 1px solid var(--color-border); background: var(--color-surface-raised); - box-shadow: 0 -4px 12px rgb(0 0 0 / 18%); + box-shadow: var(--shadow-lg); } /* 공용 리사이저는 절대배치라 오버레이 위 경계에 그대로 앉는다. */ @@ -134,10 +134,9 @@ pointer-events: none; } +/* 빈 곡선 = 부품 빈 상태 작은 꼴(553-2) · 옆 여백만 */ .b05-profile__masshaul-empty { - padding: var(--spacing-8) var(--spacing-16); - color: var(--color-text-secondary); - font-size: var(--text-caption); + padding-inline: var(--spacing-16); } /* 2차 슬라이드 손잡이 — 다른 패널들과 **같은 표준 삼각형 손잡이**를 그대로 쓴다 @@ -174,7 +173,7 @@ height: var(--b05-table-height, 204px); border-top: 1px solid var(--color-border); background: var(--color-surface-raised); - box-shadow: 0 -4px 12px rgb(0 0 0 / 18%); + box-shadow: var(--shadow-lg); } .b05-profile__table-overlay > .ui-resizer--vertical { diff --git a/B05_Profile/B05_Profile_UI_Style_RouteEdit.css b/B05_Profile/B05_Profile_UI_Style_RouteEdit.css index f0b92666f..a7da0314e 100644 --- a/B05_Profile/B05_Profile_UI_Style_RouteEdit.css +++ b/B05_Profile/B05_Profile_UI_Style_RouteEdit.css @@ -46,7 +46,7 @@ .b05-routeedit__hint-body, .b05-routeedit__info { border: 1px solid color-mix(in srgb, var(--color-border) 65%, transparent); - border-radius: var(--radius-8, 6px); + border-radius: var(--radius-cards); background: color-mix(in srgb, var(--color-surface-raised) 72%, transparent); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); @@ -153,20 +153,9 @@ white-space: nowrap; } -.b05-routeedit__legend i { - display: inline-block; - width: 22px; - height: 0; - margin-right: 2px; - vertical-align: middle; -} - -.b05-routeedit__legend i.is-expected { - border-top: 2px dashed var(--color-text-secondary, #9ca3af); -} - -.b05-routeedit__legend i.is-planned { - border-top: 2px solid var(--map-route, #f97316); +/* 범례 = 부품 「범례」 세로(553-2) · 줄 사이만 붙임 */ +.b05-routeedit__legend.ui-legend { + gap: 0; } /* 오른쪽 덮는 판 — 패널 양식(382-1 · `ui_template_side_panels` · 손잡이 · 머리 · 폭 끌기) 을 지도 위에 얹음 · @@ -193,7 +182,7 @@ } .b05-routeedit__side-wrap .ui-side-panels__panel { - box-shadow: 0 12px 40px rgb(0 0 0 / 45%); + box-shadow: var(--shadow-lg); } .b05-routeedit__side-wrap .ui-side-panels__body { @@ -261,7 +250,7 @@ overflow: hidden; width: 100%; border: 1px solid var(--color-border); - border-radius: var(--radius-8, 6px); + border-radius: var(--radius-cards); background: var(--color-surface); } @@ -363,7 +352,7 @@ height: 32px; padding: 0 var(--spacing-8); border: 1px solid color-mix(in srgb, var(--color-border) 65%, transparent); - border-radius: var(--radius-8, 6px); + border-radius: var(--radius-cards); background: color-mix(in srgb, var(--color-surface-raised) 72%, transparent); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); @@ -395,8 +384,8 @@ gap: var(--spacing-8); max-width: var(--b05-bottom-half); padding: var(--spacing-8) var(--spacing-12); - border: 1px solid color-mix(in srgb, #22c55e 60%, transparent); - border-radius: var(--radius-8, 6px); + border: 1px solid color-mix(in srgb, var(--color-success) 60%, transparent); + border-radius: var(--radius-cards); background: color-mix(in srgb, var(--color-surface-raised) 82%, transparent); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); @@ -430,7 +419,7 @@ align-items: center; justify-content: center; padding: var(--spacing-16); - background: rgb(0 0 0 / 55%); + background: var(--color-scrim); color: #fff; text-align: center; } @@ -448,12 +437,12 @@ min-width: 12rem; padding: var(--spacing-8); border: 1px solid var(--color-border); - border-radius: var(--radius-8, 6px); + border-radius: var(--radius-cards); /* 모달 본체와 **같은 토큰**을 쓴다 — `--color-surface-2` 는 이 테마에 없어 밝은 기본값으로 떨어지면서 다크 화면에서 글자가 안 읽혔다(2026-09-07 실화면). */ background: var(--color-surface-raised); color: var(--color-text-body); - box-shadow: 0 4px 14px rgb(0 0 0 / 45%); + box-shadow: var(--shadow-lg); font-size: var(--text-caption); } diff --git a/B05_Profile/B05_Profile_UI_Style_RouteRecommend.css b/B05_Profile/B05_Profile_UI_Style_RouteRecommend.css index 55ccb906e..2a3cd930a 100644 --- a/B05_Profile/B05_Profile_UI_Style_RouteRecommend.css +++ b/B05_Profile/B05_Profile_UI_Style_RouteRecommend.css @@ -76,7 +76,7 @@ margin-bottom: var(--spacing-8); padding: var(--spacing-8); border: 1px solid transparent; - border-radius: var(--radius-8, 6px); + border-radius: var(--radius-inputs); } /* 고른 갈래 — 알약과 같은 강조색 테두리. */ @@ -227,7 +227,7 @@ height: 460px; overflow: hidden; border: 1px solid var(--color-border); - border-radius: var(--radius-8, 6px); + border-radius: var(--radius-inputs); background: var(--color-surface); } @@ -244,34 +244,11 @@ font-size: var(--text-body-sm); } -.b05-routerec__legend { - display: flex; - flex-wrap: wrap; - gap: var(--spacing-12); - color: var(--color-text-secondary); - font-size: var(--text-body-sm); -} - -.b05-routerec__legend i { - display: inline-block; - width: 22px; - margin-right: 6px; - vertical-align: middle; -} - -.b05-routerec__legend i.is-expected { - border-top: 2px dashed var(--color-text-secondary, #9ca3af); -} - -.b05-routerec__legend i.is-current { - border-top: 2px solid var(--map-route, #f97316); +/* 범례 = 부품 「범례」(553-2) · 창을 연 노선은 지도처럼 흐림 */ +.b05-routerec__legend .is-current { opacity: 0.55; } -.b05-routerec__legend i.is-preview { - border-top: 3px solid var(--color-primary); -} - /* 옵션 겹창 — 지도 왼쪽 위 작은 칸(회전 단추는 오른쪽 위 · PLAN 77-4). 지도 끌기를 막지 않게 제 칸만. */ .b05-routerec__side { position: absolute; @@ -286,9 +263,9 @@ overflow: auto; padding: var(--spacing-8); border: 1px solid var(--color-border); - border-radius: var(--radius-8, 6px); + border-radius: var(--radius-inputs); background: color-mix(in srgb, var(--color-surface) 92%, transparent); - box-shadow: var(--shadow-sm, 0 2px 6px rgb(0 0 0 / 0.15)); + box-shadow: var(--shadow-sm); color: var(--color-text-body); font-size: var(--text-caption); } @@ -326,16 +303,11 @@ accent-color: var(--color-primary); } -/* 값 칸 — 슬라이더 옆에서 숫자를 직접 넣는다. 합 100 을 못 맞추면 빨간 테두리. */ -.b05-routerec__num { +/* 값 칸 = 부품 입력 단 32(553-2) — 슬라이더 옆에서 숫자를 직접 넣는다. 합 100 을 못 맞추면 빨간 테두리. */ +.b05-routerec__num.ui-input { width: 100%; min-width: 3.2em; - padding: 2px 4px; - border: 1px solid var(--color-border); - border-radius: var(--radius-4, 4px); - background: var(--color-surface); - color: var(--color-text-body); - font-size: var(--text-body); + padding-inline: 4px; font-weight: 600; text-align: center; appearance: textfield; @@ -353,8 +325,8 @@ } .b05-routerec__num.is-invalid { - border-color: var(--color-danger, #dc2626); - box-shadow: 0 0 0 1px var(--color-danger, #dc2626); + border-color: var(--color-danger); + box-shadow: 0 0 0 1px var(--color-danger); } /* 저절로 정해진 비중은 고정 단추가 눌린 채 꺼져(잠김 표시) — 색은 공용 꼴(`ui-btn--glass`)을 쓴다. */ @@ -401,15 +373,10 @@ color: var(--color-text-body); } -.b05-routerec__criteria input, -.b05-routerec__target input { +/* 제약 칸 = 부품 입력 단 32(553-2) — 자리 · 오른쪽 맞춤만 */ +.b05-routerec__criteria input.ui-input, +.b05-routerec__target input.ui-input { width: 100%; - padding: 4px 8px; - border: 1px solid var(--color-border); - border-radius: var(--radius-4, 4px); - background: var(--color-surface); - color: var(--color-text-body); - font-size: var(--text-body); text-align: right; } @@ -497,7 +464,7 @@ width: 100%; height: 96px; border: 1px solid var(--color-border); - border-radius: var(--radius-8, 6px); + border-radius: var(--radius-inputs); background: var(--color-surface); } @@ -521,47 +488,17 @@ stroke-dasharray: 6 3; } +/* 그림 범례 = 부품 「범례」(553-2) */ .b05-routerec__plegend { - display: flex; - gap: var(--spacing-12); - margin-top: var(--spacing-4, 4px); - color: var(--color-text-secondary); - font-size: var(--text-caption); -} - -.b05-routerec__plegend i { - display: inline-block; - width: 16px; - margin-right: var(--spacing-4, 4px); - vertical-align: middle; - border-top: 2px solid var(--color-text-secondary); -} - -.b05-routerec__plegend i.is-plan { - border-top-color: var(--color-primary); -} - -.b05-routerec__plegend i.is-initial { - border-top: 2px dashed var(--map-route, #f97316); + margin-top: var(--spacing-4); } /* 이 모달에서 셈한 후보 표 — 절 · 성 · 반입 · 최대 종단경사. */ -.b05-routerec__cands table { - width: 100%; - border-collapse: collapse; - font-size: var(--text-caption); +/* 후보 표 = 부품 표 데이터표(553-2) — 수 칸 자리 맞춤 · 한 줄 */ +.b05-routerec__cands .ui-table { font-variant-numeric: tabular-nums; } -.b05-routerec__cands th, -.b05-routerec__cands td { - padding: 2px var(--spacing-8); - border-bottom: 1px solid var(--color-border); - text-align: right; +.b05-routerec__cands .ui-table td { white-space: nowrap; } - -.b05-routerec__cands th[scope="row"], -.b05-routerec__cands thead th:first-child { - text-align: left; -} diff --git a/B05_Profile/B05_Profile_UI_Style_Structures.css b/B05_Profile/B05_Profile_UI_Style_Structures.css index 28c3d3d71..46e035862 100644 --- a/B05_Profile/B05_Profile_UI_Style_Structures.css +++ b/B05_Profile/B05_Profile_UI_Style_Structures.css @@ -51,7 +51,7 @@ padding: 0 7px; border-radius: 9px; border: 1.5px solid currentColor; - background: var(--color-surface, #fff); + background: var(--color-surface); font-size: 10px; font-weight: 700; line-height: 1; @@ -117,8 +117,8 @@ padding: 4px 8px; border: 1.5px solid currentColor; border-radius: 6px; - background: var(--color-surface, #fff); - box-shadow: 0 2px 6px rgb(0 0 0 / 18%); + background: var(--color-surface); + box-shadow: var(--shadow-sm); font-size: 11px; line-height: 1.35; white-space: nowrap; @@ -161,7 +161,7 @@ .b05-structure__group { margin: 0; padding: 6px 8px 8px; - border: 1px solid var(--border-color, #3a3f4a); + border: 1px solid var(--color-border); border-radius: 6px; } @@ -197,7 +197,7 @@ height: 0; margin: 2px 0; border: 0; - border-top: 1px solid var(--color-border, #3a3f4a); + border-top: 1px solid var(--color-border); } /* 「제원·수량은 다른 화면이 냅니다」 안내 — 경고가 아니라 안내라 색은 흐리게, @@ -205,9 +205,9 @@ .b05-structure__owner-note { margin: 0; padding: 4px 0 4px 8px; - border-left: 2px solid var(--color-border, #3a3f4a); - color: var(--color-text-muted, #9aa1ad); - font-size: var(--text-caption, 12px); + border-left: 2px solid var(--color-border); + color: var(--color-text-muted); + font-size: var(--text-caption); line-height: 1.5; } @@ -236,20 +236,18 @@ /* 측점 입력이 형식에 안 맞을 때(예: "3+18.0"도 숫자도 아님) 칸을 붉힌다. */ .b05-route__field input.is-invalid { - border-color: #e05b5b; - background: rgba(224, 91, 91, 0.08); + border-color: var(--color-danger); + background: color-mix(in srgb, var(--color-danger) 8%, transparent); } /* 빈 필수 칸 — 칸 테두리 + 그 칸이 든 상자 안 안내 한 줄(54-12) */ .b05-route__field .is-required-empty { - border-color: #e05b5b; + border-color: var(--color-danger); } +/* 상태 글 = 부품 보조 글 오류 꼴(553-2) */ .b05-structure__required-note { grid-column: 1 / -1; - margin: 0; - color: #e05b5b; - font-size: var(--text-caption, 12px); } /* 측점 범위(계산 표시) — C군 등 길이 옵션 기반 구간 타입. 입력 칸이 아니라 기준 @@ -365,15 +363,6 @@ font-size: var(--text-caption); } -/* 물넘이·세월교 개략 단면 결과 — 읽어 보는 안내문이라 입력 칸보다 작게 둔다 - (2026-08-30 사용자: 글자가 너무 크다). */ -.b05-drainage__facility-note { - margin: 0; - font-size: 10px; - line-height: 1.4; - opacity: 0.75; -} - /* 스텝 묶음과 그 안의 버튼·숫자칸도 같은 높이로 선다. */ .b05-structure__stepper { height: var(--b05-control-h); @@ -419,7 +408,7 @@ /* 전면 기울기가 품셈 표준경사 표(0.20~0.50) 밖일 때 — 실무가 S0.7 을 쓰므로 **막지 않고** 테두리로만 알린다(2026-09-09). 말풍선에 까닭이 들어 있다. */ .is-outside-standard { - border-color: var(--color-warning, #c98a00); + border-color: var(--color-warning); } /* 구조물 조합 잇기 줄(PLAN 21-4 · 54-17) — 옵션 칸 꼴(`b05-route__field`) 2행 · 아래 줄은 diff --git a/B05_Profile/B05_Profile_UI_Style_Table.css b/B05_Profile/B05_Profile_UI_Style_Table.css index 6dd46cdc8..d74f1f7b3 100644 --- a/B05_Profile/B05_Profile_UI_Style_Table.css +++ b/B05_Profile/B05_Profile_UI_Style_Table.css @@ -18,7 +18,7 @@ flex: 0 0 auto; flex-direction: column; min-height: 0; - border-top: 2px solid var(--color-text-muted, var(--color-plum-velvet)); + border-top: 2px solid var(--color-text-muted); color: var(--color-text-body); /* 행 높이와 셀 폭에 맞춰 렌더러가 계산해 넣는다 (createProfileTable). */ font-size: var(--b05-table-font, 11px); @@ -37,7 +37,7 @@ /* 구배 / 측점값 / 곡선 묶음의 시작 행은 굵은 선으로 그룹을 구분한다. */ .b05-profile-table__row.is-group-start { - border-top: 2px solid var(--color-text-muted, var(--color-plum-velvet)); + border-top: 2px solid var(--color-text-muted); } .b05-profile-table__row--grade { @@ -62,7 +62,7 @@ width: var(--b05-table-label-width, 60px); height: 100%; padding-inline: var(--spacing-16) var(--spacing-4); - border-right: 2px solid var(--color-text-muted, var(--color-plum-velvet)); + border-right: 2px solid var(--color-text-muted); background: var(--color-surface-raised); color: var(--color-text); font-size: var(--b05-table-label-font, inherit); @@ -121,15 +121,15 @@ } .b05-profile-table__row.is-cut .b05-profile-table__cell { - color: rgb(220 38 38); + color: var(--color-danger); } .b05-profile-table__row.is-fill .b05-profile-table__cell { - color: rgb(37 99 235); + color: var(--color-info); } .b05-profile-table__row.is-plan .b05-profile-table__cell { - color: var(--color-royal-amethyst, rgb(109 40 217)); + color: var(--color-accent); font-weight: var(--font-weight-medium); } @@ -146,8 +146,8 @@ } .b05-profile-table__segment.is-violation { - background: color-mix(in srgb, rgb(220 38 38) 12%, transparent); - color: rgb(180 83 9); + background: color-mix(in srgb, var(--color-danger) 12%, transparent); + color: var(--color-warning); } /* 구배 블록 값. 가로로 안 들어가면 90도 회전해 좁은 블록에도 값을 표기한다. */ @@ -223,12 +223,8 @@ display: flex; flex-direction: column; box-sizing: border-box; - border-inline: 1px solid var(--color-royal-amethyst, rgb(109 40 217)); - background: color-mix( - in srgb, - var(--color-royal-amethyst, rgb(109 40 217)) 14%, - var(--color-surface) - ); + border-inline: 1px solid var(--color-accent); + background: color-mix(in srgb, var(--color-accent) 14%, var(--color-surface)); transform: translateX(-50%); /* 열 자체는 클릭을 통과시키고, 입력 셀만 pointer-events를 되살린다(작업6). */ pointer-events: none; @@ -240,7 +236,7 @@ border-inline-width: 2px; box-shadow: 0 0 0 1px var(--color-surface-raised), - 0 4px 12px rgb(0 0 0 / 28%); + var(--shadow-lg); } .b05-profile-table__irregular-col-cell { @@ -281,11 +277,11 @@ } .b05-profile-table__irregular-col-cell.is-cut { - color: rgb(220 38 38); + color: var(--color-danger); } .b05-profile-table__irregular-col-cell.is-fill { - color: rgb(37 99 235); + color: var(--color-info); } /* MC 측점 이름(507-3 덧) — 굵게 · 경고색 */ @@ -315,7 +311,7 @@ .b05-profile-table__irregular-input:focus, .b05-profile-table__irregular-input:hover { - border-color: var(--color-royal-amethyst, rgb(109 40 217)); + border-color: var(--color-accent); background: var(--color-surface); } diff --git a/resources/tester/helper_349_drainage_live_flow.cjs b/resources/tester/helper_349_drainage_live_flow.cjs index 894f40bcc..55c7f7cd3 100644 --- a/resources/tester/helper_349_drainage_live_flow.cjs +++ b/resources/tester/helper_349_drainage_live_flow.cjs @@ -34,6 +34,9 @@ function el(tag) { replaceChildren(...kids) { this.children = kids; }, + setAttribute(name, value) { + (this.attrs ??= {})[name] = String(value); + }, addEventListener(type, fn) { (this.listeners[type] ??= []).push(fn); }, diff --git a/resources/tester/helper_510_propose.cjs b/resources/tester/helper_510_propose.cjs index 539268144..ad3608fe1 100644 --- a/resources/tester/helper_510_propose.cjs +++ b/resources/tester/helper_510_propose.cjs @@ -24,6 +24,9 @@ function el(tag) { node.children = []; node.append(...items); }, + setAttribute(name, value) { + (this.attrs ??= {})[name] = String(value); + }, addEventListener(type, fn) { (listeners[type] ??= []).push(fn); }, diff --git a/resources/tester/test_63_4_route_profile.py b/resources/tester/test_63_4_route_profile.py index 3f77662cf..03193841d 100644 --- a/resources/tester/test_63_4_route_profile.py +++ b/resources/tester/test_63_4_route_profile.py @@ -122,6 +122,6 @@ def test_균형_종단은_캐시에_안_남는다() -> None: assert result["svg"].count("토공 최소" in result["table"] assert ( - '누가토량' in result["table"] + '누가토량' in result["table"] # 부품 표(553-2) and "반입" not in result["table"] )