feat(481-1 페이지 이동): B05~B09 좌측 아래 [?] [<] [>] — 이웃 진행 단계 단추 누름 · B05 · B06 [노선 보기] · [횡단 보기] 지움
- ui_template_help: [?] 뒤 [<] [>] · 다섯 주소 목록만(b09-print · B03 · B04 · M01 · M02 뺌) · B09 [>] 흐림 · ui-step-nav 이벤트 - ui_template_workflow_layout: ui-step-nav 듣개 — 켜진 칸 ±1 단계 단추 click(onStepClick 한 길) · 꺼진 단계 = 그 단추 title 알림 - CSS: [<] [>] = [?] 같은 정사각 · 늘어남 규칙에서 뺌(overlay · B09 도크 한 줄) - design_dock · design_shared · locale_b2: switchView 단추 · 글 지움 - 시험: test_280_2_step_nav(새) · test_design_view_parity(단추 셋) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
/* [?] 설명서(54-2) — 단추는 글자 폭만 · 모달은 왼쪽 차례 · 오른쪽 글 */
|
||||
/* [?] 설명서(54-2) — 단추는 글자 폭만 · 모달은 왼쪽 차례 · 오른쪽 글 · [<] [>](280-2)도 같은 정사각 */
|
||||
.ui-sidebar-actions .ui-help-btn,
|
||||
.ui-help-btn {
|
||||
.ui-help-btn,
|
||||
.ui-sidebar-actions .ui-step-nav-btn,
|
||||
.ui-step-nav-btn {
|
||||
flex: none;
|
||||
/* 정사각 — 너비 = 높이(글 한 줄 · 위아래 여백 · 테두리) */
|
||||
width: calc(1em + 2 * var(--spacing-8) + 2px);
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
* 페이지 = 주소(#/b05-…)의 B0N · 먼저 여는 항목 = 좌측 패널에서 보이는 `[data-help-topic]` 중 마지막
|
||||
* (지금 연 상자 · 구조물 종류) · 없으면 첫 파일(00_설명서).
|
||||
* 단추 자리 = `.ui-sidebar-actions` 안 `[data-help-row]`(없으면 그 줄 자신)의 맨 앞.
|
||||
* [<] [>](요구 280-2) = [?] 바로 뒤 · B05~B09 다섯 주소만 · 누르면 `ui-step-nav` 를 올려 보냄 →
|
||||
* 진행 단계 틀(`createWorkflowLayout`)이 이웃 단계 단추를 누름(저장 · 막힘은 각 페이지 `onStepClick`).
|
||||
* ========================================================================== */
|
||||
|
||||
import "./ui_template_help.css";
|
||||
import { API_BASE_URL } from "@config/config_frontend";
|
||||
import { API_BASE_URL, ROUTES } from "@config/config_frontend";
|
||||
import { createButton, el } from "./ui_template_elements";
|
||||
import { openModal } from "./ui_template_modal";
|
||||
|
||||
@@ -19,6 +21,16 @@ interface HelpItem {
|
||||
}
|
||||
|
||||
const TEXT = { button: "?", tip: "설명서", title: "설명서", close: "닫기", empty: "설명 글 없음" };
|
||||
const STEP_TEXT = { prev: "<", next: ">", prevTip: "이전 단계", nextTip: "다음 단계" };
|
||||
|
||||
/** [<] [>] 를 붙이는 주소 — 목록으로 거름(b09-print · B03 · B04 · M01 · M02 뺌) */
|
||||
const STEP_NAV_ROUTES = [
|
||||
ROUTES.B05_PROFILE,
|
||||
ROUTES.B06_SECTION,
|
||||
ROUTES.B07_DESIGN_DETAIL,
|
||||
ROUTES.B08_QUANTITY,
|
||||
ROUTES.B09_ESTIMATION,
|
||||
] as const;
|
||||
|
||||
function currentPage(): string {
|
||||
const n = /^#\/b0(\d)/i.exec(location.hash)?.[1];
|
||||
@@ -161,8 +173,28 @@ export function createHelpButton(): HTMLButtonElement {
|
||||
return button;
|
||||
}
|
||||
|
||||
function createStepNavButton(step: -1 | 1, disabled: boolean): HTMLButtonElement {
|
||||
const button = createButton({
|
||||
label: step < 0 ? STEP_TEXT.prev : STEP_TEXT.next,
|
||||
variant: "ghost",
|
||||
onClick: () =>
|
||||
button.dispatchEvent(new CustomEvent("ui-step-nav", { bubbles: true, detail: step })),
|
||||
});
|
||||
button.classList.add("ui-step-nav-btn");
|
||||
button.dataset.stepNav = String(step);
|
||||
button.title = button.ariaLabel = step < 0 ? STEP_TEXT.prevTip : STEP_TEXT.nextTip;
|
||||
button.disabled = disabled;
|
||||
return button;
|
||||
}
|
||||
|
||||
/** 아래 단추 묶음에 [?] 를 한 번 — `[data-help-row]` 가 있으면 그 줄 · 없으면 묶음 자신의 맨 앞 */
|
||||
export function placeHelpButton(actions: HTMLElement): void {
|
||||
if (actions.querySelector(".ui-help-btn")) return;
|
||||
(actions.querySelector<HTMLElement>("[data-help-row]") ?? actions).prepend(createHelpButton());
|
||||
const row = actions.querySelector<HTMLElement>("[data-help-row]") ?? actions;
|
||||
const route = location.hash.replace(/^#\/?/, "").split("?")[0];
|
||||
const index = (STEP_NAV_ROUTES as readonly string[]).indexOf(route);
|
||||
if (index < 0) return void row.prepend(createHelpButton());
|
||||
// B09 = 마지막 단계 — [>] 흐림
|
||||
const last = index === STEP_NAV_ROUTES.length - 1;
|
||||
row.prepend(createHelpButton(), createStepNavButton(-1, false), createStepNavButton(1, last));
|
||||
}
|
||||
|
||||
@@ -145,8 +145,6 @@ export const ui_locales_b2 = {
|
||||
B05_Route_Btn_TempSave: ["저장", "Save"],
|
||||
B05_Route_Btn_GoCross: ["횡단 이동", "Go to Cross"],
|
||||
/* 좌측 패널 아래 단추 [보기 전환] — 가려는 쪽 이름(계획서 24-2b). */
|
||||
Design_Btn_ToCross: ["횡단 보기", "Cross view"],
|
||||
Design_Btn_ToProfile: ["노선 보기", "Route view"],
|
||||
B05_Route_TempSave_Success: ["변경 내용을 저장했습니다.", "Changes saved."],
|
||||
B05_Route_TempSave_Failed: ["저장에 실패했습니다.", "Failed to save."],
|
||||
B05_Route_Reset_Confirm: [
|
||||
|
||||
@@ -376,8 +376,8 @@
|
||||
gap: var(--btn-group-gap);
|
||||
}
|
||||
|
||||
.ui-sidebar-actions > .ui-btn:not(.ui-help-btn),
|
||||
.ui-sidebar-actions [data-help-row] > .ui-btn:not(.ui-help-btn) {
|
||||
.ui-sidebar-actions > .ui-btn:not(.ui-help-btn, .ui-step-nav-btn),
|
||||
.ui-sidebar-actions [data-help-row] > .ui-btn:not(.ui-help-btn, .ui-step-nav-btn) {
|
||||
flex: 1 1 0;
|
||||
min-width: auto;
|
||||
padding-inline: var(--spacing-4);
|
||||
@@ -469,7 +469,7 @@
|
||||
}
|
||||
|
||||
/* 단추 크기 = 「구조물 배치」 단추(`b05-route__irregular-btn`) · 색은 단추 갈래(filled · ghost) 그대로 */
|
||||
.ui-panel-form .ui-btn:not(.ui-help-btn) {
|
||||
.ui-panel-form .ui-btn:not(.ui-help-btn, .ui-step-nav-btn) {
|
||||
padding: var(--spacing-8);
|
||||
border-radius: var(--radius-inputs);
|
||||
font-size: var(--text-caption);
|
||||
|
||||
@@ -2,6 +2,7 @@ import "./ui_template_workflow_layout.css";
|
||||
import { ROUTES } from "@config/config_frontend";
|
||||
import { t } from "./ui_template_locale";
|
||||
import { createWorkflowOverlays } from "./ui_template_overlay";
|
||||
import { showToast } from "./ui_template_elements";
|
||||
import { navigateTo } from "../A00_Common/router";
|
||||
import { setDrawerSteps } from "../A00_Common/app_shell";
|
||||
import { fetchDashboardMe } from "../B01_Dashboard/B01_Dashboard_Api_Fetch";
|
||||
@@ -206,6 +207,14 @@ export function createWorkflowLayout(options: WorkflowLayoutOptions): WorkflowLa
|
||||
".ui-workflow-layout__step:not(.ui-workflow-layout__step--home)",
|
||||
),
|
||||
];
|
||||
// 좌측 아래 [<] [>](요구 280-2) = 이웃 단계 단추 누름 — 막힘 · 저장 · 이동은 그 단추의 `onStepClick` 한 길
|
||||
root.addEventListener("ui-step-nav", (event) => {
|
||||
const active = steps.findIndex((step) => step.classList.contains("is-active"));
|
||||
const target = active < 0 ? undefined : steps[active + (event as CustomEvent<number>).detail];
|
||||
if (!(target instanceof HTMLButtonElement)) return;
|
||||
if (target.disabled) showToast(target.title || t("WF_State_NotStarted"));
|
||||
else target.click();
|
||||
});
|
||||
return {
|
||||
root,
|
||||
setOptionsOpen: overlays.setTitleOpen,
|
||||
|
||||
Reference in New Issue
Block a user