feat(529-1): 단계 틀 인자(아이콘 · [<][>] 묶음 · 도움말 이름) · D · E 단계 빈 길 일곱
- createWorkflowLayout icons 인자(없으면 B 일곱 아이콘 그대로) - [?] [<] [>] 묶음 = B05~B09 · D02~D04 · E02~E05 · 묶음 안에서만 오감 · 설명서 이름 B0N/D0N/E0N - 서버 설명서 주소 D01~D04 · E01~E05 허용 · 우클릭 막기 · 돋보기 d · e 주소 - ROUTES D01~E05 · PLAN_STEP_ROUTES · STAB_STEP_ROUTES · A00_Common/group_workflow(빈 단계 = 틀 · 좌측 [?] 줄 · 단계 막대) - 페이지 폴더마다 draft/<폴더>_Route.ts · tsconfig 에 D0* · E0* · 문구 ui_template_locale_de - 시험: 280-2 대역에 D · E 묶음 · 54-2 D · E 설명서 길 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
/* =============================================================================
|
||||
* group_workflow.ts
|
||||
* D 예정노선 · E 안정성평가 단계 묶음(요구 345 · PLAN 529-1) — B05~B09 틀(`createWorkflowLayout`)을
|
||||
* 단계 목록 · 아이콘 · 주소 인자로 그대로 씀. 빈 단계 = 틀 · 좌측 패널([?] [<] [>]) · 단계 막대만.
|
||||
* 페이지 길 = 각 폴더 `draft/<폴더>_Route.ts` · 본문이 생기면 그 폴더 페이지로 갈아 끼움.
|
||||
* ========================================================================== */
|
||||
|
||||
import { PLAN_STEP_ROUTES, STAB_STEP_ROUTES, type RoutePath } from "@config/config_frontend";
|
||||
import { el } from "@ui/ui_template_elements";
|
||||
import { t, type LocaleKey } from "@ui/ui_template_locale";
|
||||
import { createWorkflowLayout } from "@ui/ui_template_workflow_layout";
|
||||
import { navigateTo, type PageRenderer } from "./router";
|
||||
|
||||
interface GroupFlow {
|
||||
routes: readonly RoutePath[];
|
||||
labels: readonly LocaleKey[];
|
||||
icons: readonly string[];
|
||||
}
|
||||
|
||||
const FLOWS: readonly GroupFlow[] = [
|
||||
{
|
||||
routes: PLAN_STEP_ROUTES,
|
||||
labels: ["DE_Step_PlanBase", "DE_Step_PlanAnalysis", "DE_Step_PlanConfirm"],
|
||||
icons: ["📍", "🧭", "✅"],
|
||||
},
|
||||
{
|
||||
routes: STAB_STEP_ROUTES,
|
||||
labels: ["DE_Step_StabGround", "DE_Step_StabSection", "DE_Step_Stab3D", "DE_Step_StabReport"],
|
||||
icons: ["🪨", "📐", "🧊", "📄"],
|
||||
},
|
||||
];
|
||||
|
||||
/** 단계 틀을 세움 — mainContent · leftPanel 이 없으면 빈 단계 안내 · [?] 줄만 */
|
||||
export function mountGroupStep(
|
||||
root: HTMLElement,
|
||||
route: RoutePath,
|
||||
parts: { mainContent?: HTMLElement; leftPanel?: HTMLElement } = {},
|
||||
): void {
|
||||
const flow = FLOWS.find((f) => f.routes.includes(route));
|
||||
if (!flow) throw new Error(`단계 묶음 밖 주소: ${route}`);
|
||||
const active = flow.routes.indexOf(route);
|
||||
const layout = createWorkflowLayout({
|
||||
title: t(flow.labels[active]),
|
||||
steps: flow.labels.map((key) => t(key)),
|
||||
icons: flow.icons,
|
||||
activeStep: active,
|
||||
routes: flow.routes,
|
||||
leftPanel: parts.leftPanel,
|
||||
mainContent:
|
||||
parts.mainContent ?? el("p", { className: "app-placeholder", text: t("DE_Step_Empty") }),
|
||||
onStepClick: (_index, next) => navigateTo(next as RoutePath),
|
||||
});
|
||||
root.append(layout.root);
|
||||
}
|
||||
|
||||
/** 빈 단계 페이지(길 선언의 load 가 부름) */
|
||||
export const groupStepPage =
|
||||
(route: RoutePath): PageRenderer =>
|
||||
(root) =>
|
||||
mountGroupStep(root, route);
|
||||
@@ -0,0 +1,17 @@
|
||||
/* =============================================================================
|
||||
* D02_PlanBase_Route.ts
|
||||
* 길 선언(PLAN 529-1) — 라우터가 페이지 폴더마다 draft/*_Route.ts 를 glob 해 등록.
|
||||
* 로그인 · 회사 · 현재 프로젝트 필요 · 꼬리말 없음 · 본문 = 빈 단계(틀 · 패널 · 단계 막대)
|
||||
* ========================================================================== */
|
||||
|
||||
import { ROUTES } from "@config/config_frontend";
|
||||
import type { DraftRoute } from "../../A00_Common/router";
|
||||
|
||||
export const ROUTE: DraftRoute = {
|
||||
path: ROUTES.D02_PLAN_BASE,
|
||||
workflow: true,
|
||||
project: true,
|
||||
footerless: true,
|
||||
load: async () =>
|
||||
(await import("../../A00_Common/group_workflow")).groupStepPage(ROUTES.D02_PLAN_BASE),
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/* =============================================================================
|
||||
* D03_PlanAnalysis_Route.ts
|
||||
* 길 선언(PLAN 529-1) — 라우터가 페이지 폴더마다 draft/*_Route.ts 를 glob 해 등록.
|
||||
* 로그인 · 회사 · 현재 프로젝트 필요 · 꼬리말 없음 · 본문 = 빈 단계(틀 · 패널 · 단계 막대)
|
||||
* ========================================================================== */
|
||||
|
||||
import { ROUTES } from "@config/config_frontend";
|
||||
import type { DraftRoute } from "../../A00_Common/router";
|
||||
|
||||
export const ROUTE: DraftRoute = {
|
||||
path: ROUTES.D03_PLAN_ANALYSIS,
|
||||
workflow: true,
|
||||
project: true,
|
||||
footerless: true,
|
||||
load: async () =>
|
||||
(await import("../../A00_Common/group_workflow")).groupStepPage(ROUTES.D03_PLAN_ANALYSIS),
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/* =============================================================================
|
||||
* D04_PlanConfirm_Route.ts
|
||||
* 길 선언(PLAN 529-1) — 라우터가 페이지 폴더마다 draft/*_Route.ts 를 glob 해 등록.
|
||||
* 로그인 · 회사 · 현재 프로젝트 필요 · 꼬리말 없음 · 본문 = 빈 단계(틀 · 패널 · 단계 막대)
|
||||
* ========================================================================== */
|
||||
|
||||
import { ROUTES } from "@config/config_frontend";
|
||||
import type { DraftRoute } from "../../A00_Common/router";
|
||||
|
||||
export const ROUTE: DraftRoute = {
|
||||
path: ROUTES.D04_PLAN_CONFIRM,
|
||||
workflow: true,
|
||||
project: true,
|
||||
footerless: true,
|
||||
load: async () =>
|
||||
(await import("../../A00_Common/group_workflow")).groupStepPage(ROUTES.D04_PLAN_CONFIRM),
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/* =============================================================================
|
||||
* E02_StabGround_Route.ts
|
||||
* 길 선언(PLAN 529-1) — 라우터가 페이지 폴더마다 draft/*_Route.ts 를 glob 해 등록.
|
||||
* 로그인 · 회사 · 현재 프로젝트 필요 · 꼬리말 없음 · 본문 = 빈 단계(틀 · 패널 · 단계 막대)
|
||||
* ========================================================================== */
|
||||
|
||||
import { ROUTES } from "@config/config_frontend";
|
||||
import type { DraftRoute } from "../../A00_Common/router";
|
||||
|
||||
export const ROUTE: DraftRoute = {
|
||||
path: ROUTES.E02_STAB_GROUND,
|
||||
workflow: true,
|
||||
project: true,
|
||||
footerless: true,
|
||||
load: async () =>
|
||||
(await import("../../A00_Common/group_workflow")).groupStepPage(ROUTES.E02_STAB_GROUND),
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/* =============================================================================
|
||||
* E03_StabSection_Route.ts
|
||||
* 길 선언(PLAN 529-1) — 라우터가 페이지 폴더마다 draft/*_Route.ts 를 glob 해 등록.
|
||||
* 로그인 · 회사 · 현재 프로젝트 필요 · 꼬리말 없음 · 본문 = 빈 단계(틀 · 패널 · 단계 막대)
|
||||
* ========================================================================== */
|
||||
|
||||
import { ROUTES } from "@config/config_frontend";
|
||||
import type { DraftRoute } from "../../A00_Common/router";
|
||||
|
||||
export const ROUTE: DraftRoute = {
|
||||
path: ROUTES.E03_STAB_SECTION,
|
||||
workflow: true,
|
||||
project: true,
|
||||
footerless: true,
|
||||
load: async () =>
|
||||
(await import("../../A00_Common/group_workflow")).groupStepPage(ROUTES.E03_STAB_SECTION),
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/* =============================================================================
|
||||
* E04_Stab3D_Route.ts
|
||||
* 길 선언(PLAN 529-1) — 라우터가 페이지 폴더마다 draft/*_Route.ts 를 glob 해 등록.
|
||||
* 로그인 · 회사 · 현재 프로젝트 필요 · 꼬리말 없음 · 본문 = 빈 단계(틀 · 패널 · 단계 막대)
|
||||
* ========================================================================== */
|
||||
|
||||
import { ROUTES } from "@config/config_frontend";
|
||||
import type { DraftRoute } from "../../A00_Common/router";
|
||||
|
||||
export const ROUTE: DraftRoute = {
|
||||
path: ROUTES.E04_STAB_3D,
|
||||
workflow: true,
|
||||
project: true,
|
||||
footerless: true,
|
||||
load: async () =>
|
||||
(await import("../../A00_Common/group_workflow")).groupStepPage(ROUTES.E04_STAB_3D),
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/* =============================================================================
|
||||
* E05_StabReport_Route.ts
|
||||
* 길 선언(PLAN 529-1) — 라우터가 페이지 폴더마다 draft/*_Route.ts 를 glob 해 등록.
|
||||
* 로그인 · 회사 · 현재 프로젝트 필요 · 꼬리말 없음 · 본문 = 빈 단계(틀 · 패널 · 단계 막대)
|
||||
* ========================================================================== */
|
||||
|
||||
import { ROUTES } from "@config/config_frontend";
|
||||
import type { DraftRoute } from "../../A00_Common/router";
|
||||
|
||||
export const ROUTE: DraftRoute = {
|
||||
path: ROUTES.E05_STAB_REPORT,
|
||||
workflow: true,
|
||||
project: true,
|
||||
footerless: true,
|
||||
load: async () =>
|
||||
(await import("../../A00_Common/group_workflow")).groupStepPage(ROUTES.E05_STAB_REPORT),
|
||||
};
|
||||
@@ -14,7 +14,7 @@ from fastapi import APIRouter, HTTPException
|
||||
router = APIRouter(prefix="/api/help", tags=["help"])
|
||||
|
||||
HELP_ROOT = Path(__file__).resolve().parent.parent / "resources" / "help"
|
||||
PAGE_RE = re.compile(r"^B0[2-9]$")
|
||||
PAGE_RE = re.compile(r"^(B0[2-9]|D0[1-4]|E0[1-5])$")
|
||||
|
||||
|
||||
def read_help(page: str, root: Path = HELP_ROOT) -> list[dict[str, str]]:
|
||||
|
||||
@@ -120,8 +120,33 @@ export const ROUTES = {
|
||||
M01_MASTER_DATA: "m01-master-data",
|
||||
// 마스터 템플릿 — 표 양식 · 도면 양식(시스템 · 회사 · 개인 · 프로젝트 층). 화면은 로그인만 확인.
|
||||
M02_MASTER_TEMPLATE: "m02-master-template",
|
||||
// D 예정노선 · E 안정성평가(요구 345) — 길 선언은 페이지 폴더 `draft/*_Route.ts`
|
||||
D01_PLAN_REGISTER: "d01-plan-register",
|
||||
D02_PLAN_BASE: "d02-plan-base",
|
||||
D03_PLAN_ANALYSIS: "d03-plan-analysis",
|
||||
D04_PLAN_CONFIRM: "d04-plan-confirm",
|
||||
E01_STAB_REGISTER: "e01-stab-register",
|
||||
E02_STAB_GROUND: "e02-stab-ground",
|
||||
E03_STAB_SECTION: "e03-stab-section",
|
||||
E04_STAB_3D: "e04-stab-3d",
|
||||
E05_STAB_REPORT: "e05-stab-report",
|
||||
} as const;
|
||||
|
||||
/** D 예정노선 단계 주소(D02 → D04 · 등록 D01 은 단계 밖) */
|
||||
export const PLAN_STEP_ROUTES = [
|
||||
ROUTES.D02_PLAN_BASE,
|
||||
ROUTES.D03_PLAN_ANALYSIS,
|
||||
ROUTES.D04_PLAN_CONFIRM,
|
||||
] as const;
|
||||
|
||||
/** E 안정성평가 단계 주소(E02 → E05 · 생성 E01 은 단계 밖) */
|
||||
export const STAB_STEP_ROUTES = [
|
||||
ROUTES.E02_STAB_GROUND,
|
||||
ROUTES.E03_STAB_SECTION,
|
||||
ROUTES.E04_STAB_3D,
|
||||
ROUTES.E05_STAB_REPORT,
|
||||
] as const;
|
||||
|
||||
export type RouteKey = keyof typeof ROUTES;
|
||||
export type RoutePath = (typeof ROUTES)[RouteKey];
|
||||
|
||||
|
||||
@@ -115,7 +115,12 @@ const toasts = [];
|
||||
let role = "SYSTEM_ADMIN";
|
||||
let help;
|
||||
const STUBS = {
|
||||
"@config/config_frontend": { ROUTES, API_BASE_URL: "" },
|
||||
"@config/config_frontend": {
|
||||
ROUTES,
|
||||
API_BASE_URL: "",
|
||||
PLAN_STEP_ROUTES: ["d02-plan-base", "d03-plan-analysis", "d04-plan-confirm"],
|
||||
STAB_STEP_ROUTES: ["e02-stab-ground", "e03-stab-section", "e04-stab-3d", "e05-stab-report"],
|
||||
},
|
||||
"./ui_template_locale": { t: (key) => key },
|
||||
"./ui_template_modal": { openModal: () => undefined },
|
||||
"./ui_template_elements": {
|
||||
@@ -190,6 +195,13 @@ const ALL = [
|
||||
"b09-print",
|
||||
"m01-master-data",
|
||||
"m02-master-template",
|
||||
// 529-1 D · E 묶음 — 묶음 안에서만 [<] [>] · 등록(D01 · E01) = [?] 만
|
||||
"d01-plan-register",
|
||||
"d02-plan-base",
|
||||
"d04-plan-confirm",
|
||||
"e01-stab-register",
|
||||
"e02-stab-ground",
|
||||
"e05-stab-report",
|
||||
];
|
||||
const rows = {};
|
||||
for (const route of ALL) rows[route] = { helpRow: rowOf(route, true), plain: rowOf(route, false) };
|
||||
|
||||
@@ -32,6 +32,19 @@ def results():
|
||||
return json.loads(proc.stdout)
|
||||
|
||||
|
||||
def test_529_1_D_E_묶음_안에서만_앞뒤(results):
|
||||
rows = results["rows"]
|
||||
for route in ("d01-plan-register", "e01-stab-register"):
|
||||
assert rows[route]["plain"]["labels"] == ["?", "저장"], route
|
||||
for route in ("d02-plan-base", "d04-plan-confirm", "e02-stab-ground", "e05-stab-report"):
|
||||
assert rows[route]["plain"]["labels"] == ["?", "<", ">", "저장"], route
|
||||
# 묶음 첫 단계 [<] · 끝 단계 [>] 흐림(B 묶음과 따로)
|
||||
assert rows["d02-plan-base"]["plain"]["disabled"][:3] == [False, True, False]
|
||||
assert rows["d04-plan-confirm"]["plain"]["disabled"][:3] == [False, False, True]
|
||||
assert rows["e02-stab-ground"]["plain"]["disabled"][:3] == [False, True, False]
|
||||
assert rows["e05-stab-report"]["plain"]["disabled"][:3] == [False, False, True]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("shape", ["helpRow", "plain"])
|
||||
def test_다섯_주소만_물음_앞뒤_차례(results, shape):
|
||||
for route in FIVE:
|
||||
|
||||
@@ -28,11 +28,15 @@ def test_title_order_and_live_edit():
|
||||
assert "고친 글" in read_help("B05", tmp_path)[1]["text"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("page", ["B01", "B10", "../B05", "b05"])
|
||||
@pytest.mark.parametrize("page", ["B01", "B10", "../B05", "b05", "D05", "E06", "C01"])
|
||||
def test_bad_page_refused(page):
|
||||
with pytest.raises(HTTPException):
|
||||
read_help(page)
|
||||
|
||||
|
||||
def test_529_1_D_E_pages_open_empty(tmp_path):
|
||||
assert read_help("D02", tmp_path) == [] and read_help("E05", tmp_path) == []
|
||||
|
||||
|
||||
def test_root_is_repo_resources():
|
||||
assert HELP_ROOT.parts[-2:] == ("resources", "help")
|
||||
|
||||
+1
-1
@@ -34,6 +34,6 @@
|
||||
"@kninnug/constrainautor": ["config/node_modules/@kninnug/constrainautor"],
|
||||
}
|
||||
},
|
||||
"include": ["A00_Common", "A0*", "B0*", "B1*", "M0*", "Z0*", "ui_template", "config/**/*", "common_util"],
|
||||
"include": ["A00_Common", "A0*", "B0*", "B1*", "M0*", "D0*", "E0*", "Z0*", "ui_template", "config/**/*", "common_util"],
|
||||
"exclude": ["0_old", "node_modules", "venv", "dist"]
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
* 페이지 = 주소(#/b05-…)의 B0N · 먼저 여는 항목 = 좌측 패널에서 보이는 `[data-help-topic]` 중 마지막
|
||||
* (지금 연 상자 · 구조물 종류) · 없으면 첫 파일(00_설명서).
|
||||
* 단추 자리 = `.ui-sidebar-actions` 안 `[data-help-row]`(없으면 그 줄 자신)의 맨 앞.
|
||||
* [<] [>](요구 280-2) = [?] 바로 뒤 · B05~B09 다섯 주소만 · 누르면 `ui-step-nav` 를 올려 보냄 →
|
||||
* [<] [>](요구 280-2) = [?] 바로 뒤 · 단계 묶음(B05~B09 · D02~D04 · E02~E05 · 529-1) 주소만 · 누르면 `ui-step-nav` 를 올려 보냄 →
|
||||
* 진행 단계 틀(`createWorkflowLayout`)이 이웃 단계 단추를 누름(저장 · 막힘은 각 페이지 `onStepClick`).
|
||||
* ========================================================================== */
|
||||
|
||||
import "./ui_template_help.css";
|
||||
import { API_BASE_URL, ROUTES } from "@config/config_frontend";
|
||||
import { API_BASE_URL, PLAN_STEP_ROUTES, ROUTES, STAB_STEP_ROUTES } from "@config/config_frontend";
|
||||
import { createButton, el } from "./ui_template_elements";
|
||||
import { openModal } from "./ui_template_modal";
|
||||
|
||||
@@ -23,18 +23,23 @@ 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;
|
||||
/** [<] [>] 를 붙이는 주소 묶음 — 묶음 안에서만 오감(b09-print · B03 · B04 · M01 · M02 · D01 · E01 뺌) */
|
||||
const STEP_NAV_GROUPS: ReadonlyArray<readonly string[]> = [
|
||||
[
|
||||
ROUTES.B05_PROFILE,
|
||||
ROUTES.B06_SECTION,
|
||||
ROUTES.B07_DESIGN_DETAIL,
|
||||
ROUTES.B08_QUANTITY,
|
||||
ROUTES.B09_ESTIMATION,
|
||||
],
|
||||
PLAN_STEP_ROUTES,
|
||||
STAB_STEP_ROUTES,
|
||||
];
|
||||
|
||||
/** 설명서 폴더 이름 = 주소 머리(#/b05-… → B05 · #/d02-… → D02) */
|
||||
function currentPage(): string {
|
||||
const n = /^#\/b0(\d)/i.exec(location.hash)?.[1];
|
||||
return n ? `B0${n}` : "";
|
||||
const head = /^#\/([bde]0\d)/i.exec(location.hash)?.[1];
|
||||
return head ? head.toUpperCase() : "";
|
||||
}
|
||||
|
||||
function escapeHtml(text: string): string {
|
||||
@@ -186,24 +191,25 @@ function createStepNavButton(step: -1 | 1): HTMLButtonElement {
|
||||
return button;
|
||||
}
|
||||
|
||||
/** 지금 주소의 [<] [>] 차례 — 목록 밖이면 -1 */
|
||||
function stepNavIndex(): number {
|
||||
/** 지금 주소의 묶음 · [<] [>] 차례 — 목록 밖이면 차례 -1 */
|
||||
function stepNavIndex(): { index: number; last: number } {
|
||||
const route = location.hash.replace(/^#\/?/, "").split("?")[0];
|
||||
return (STEP_NAV_ROUTES as readonly string[]).indexOf(route);
|
||||
const group = STEP_NAV_GROUPS.find((routes) => routes.includes(route)) ?? [];
|
||||
return { index: group.indexOf(route), last: group.length - 1 };
|
||||
}
|
||||
|
||||
/** 아래 단추 묶음에 [?] 를 한 번 — `[data-help-row]` 가 있으면 그 줄 · 없으면 묶음 자신의 맨 앞 */
|
||||
export function placeHelpButton(actions: HTMLElement): void {
|
||||
if (actions.querySelector(".ui-help-btn")) return;
|
||||
const row = actions.querySelector<HTMLElement>("[data-help-row]") ?? actions;
|
||||
if (stepNavIndex() < 0) return void row.prepend(createHelpButton());
|
||||
if (stepNavIndex().index < 0) return void row.prepend(createHelpButton());
|
||||
const prev = createStepNavButton(-1);
|
||||
const next = createStepNavButton(1);
|
||||
// 첫 단계(B05) [<] · 마지막 단계(B09) [>] 흐림 — B05 ↔ B06 은 페이지를 다시 안 세우므로 주소마다 다시 맞춤
|
||||
const sync = (): void => {
|
||||
const index = stepNavIndex();
|
||||
const { index, last } = stepNavIndex();
|
||||
prev.disabled = index <= 0;
|
||||
next.disabled = index === STEP_NAV_ROUTES.length - 1;
|
||||
next.disabled = index === last;
|
||||
};
|
||||
const onHash = (): void => {
|
||||
if (prev.isConnected) sync();
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* - ui_template_locale_b1.ts : B 그룹 전반부 (B01~B04)
|
||||
* - ui_template_locale_b2.ts : B 그룹 후반부 (B05~B07)
|
||||
* - ui_template_locale_b5.ts : B 그룹 끝 (B08~B11)
|
||||
* - ui_template_locale_de.ts : D 예정노선 · E 안정성평가 · 대시보드 [+] 고르기
|
||||
*
|
||||
* 이 파일의 export 시그니처는 분할 이전과 동일하므로 소비처 import 수정은 불필요하다.
|
||||
* ========================================================================== */
|
||||
@@ -28,6 +29,7 @@ import { ui_locales_b3 } from "./ui_template_locale_b3";
|
||||
import { ui_locales_b5 } from "./ui_template_locale_b5";
|
||||
import { ui_locales_m1 } from "./ui_template_locale_m1";
|
||||
import { ui_locales_m2 } from "./ui_template_locale_m2";
|
||||
import { ui_locales_de } from "./ui_template_locale_de";
|
||||
|
||||
/** 지원 언어 인덱스: 0 = 한국어, 1 = 영어 */
|
||||
export const LANGUAGES = ["ko", "en"] as const;
|
||||
@@ -65,6 +67,7 @@ export const ui_locales = {
|
||||
...ui_locales_b5,
|
||||
...ui_locales_m1,
|
||||
...ui_locales_m2,
|
||||
...ui_locales_de,
|
||||
} as const;
|
||||
|
||||
export type LocaleKey = keyof typeof ui_locales;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/* =============================================================================
|
||||
* ui_template_locale_de.ts
|
||||
* 다국어 사전 — D 예정노선 · E 안정성평가 그룹(요구 345) · 대시보드 [+] 고르기
|
||||
*
|
||||
* 신규 문구는 해당 섹션 최하단에 추가.
|
||||
* 이 파일은 사전 데이터만 담는다. 합성·언어 전환·t() 헬퍼는 ui_template_locale.ts 참조.
|
||||
* ========================================================================== */
|
||||
|
||||
import type { LocaleEntry } from "./ui_template_locale_common";
|
||||
|
||||
export const ui_locales_de = {
|
||||
/* --- 단계 막대 · 빈 단계 --- */
|
||||
DE_Step_PlanBase: ["기준 지정", "Base Points"],
|
||||
DE_Step_PlanAnalysis: ["노선 분석", "Route Analysis"],
|
||||
DE_Step_PlanConfirm: ["확정 · 내보내기", "Confirm · Export"],
|
||||
DE_Step_StabGround: ["지반 조건", "Ground"],
|
||||
DE_Step_StabSection: ["2D 해석", "2D Analysis"],
|
||||
DE_Step_Stab3D: ["3D 해석", "3D Analysis"],
|
||||
DE_Step_StabReport: ["보고서", "Report"],
|
||||
DE_Step_Empty: ["준비 중인 단계입니다.", "This step is not ready yet."],
|
||||
} as const satisfies Record<string, LocaleEntry>;
|
||||
@@ -33,8 +33,8 @@ export const LOUPE_HOLD_MS = 400;
|
||||
export const LOUPE_REFRESH_MS = 500;
|
||||
/** 화면 끝과 원 사이 여백(px) — 테두리가 안 잘리게 */
|
||||
export const LOUPE_EDGE = 4;
|
||||
/** 붙일 주소 — B01~B09 · M01 · M02(A 영역 · 로그인 · B10 · B11 은 뺌) */
|
||||
export const LOUPE_ROUTE = /^(b0[1-9]|m0[12])-/;
|
||||
/** 붙일 주소 — B01~B09 · M01 · M02 · D01~D04 · E01~E05(A 영역 · 로그인 · B10 · B11 은 뺌) */
|
||||
export const LOUPE_ROUTE = /^(b0[1-9]|m0[12]|d0[1-4]|e0[1-5])-/;
|
||||
|
||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||||
/** CAD 영역 — cad_host 가 끼운 상자와 iframe */
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
* 드롭다운 초점 빼기 — 마우스로 고른 뒤 초점이 남으면 휠 · ↑↓ 가 값을 또 바꿈(요구 280-6).
|
||||
* ========================================================================== */
|
||||
|
||||
/** 막을 주소 — B · M 영역(`b01-…` · `m02-…`) · A 영역은 그대로 */
|
||||
export const NATIVE_MENU_ROUTE = /^[bm]\d/;
|
||||
/** 막을 주소 — B · M · D · E 영역(`b01-…` · `m02-…` · `d02-…`) · A 영역은 그대로 */
|
||||
export const NATIVE_MENU_ROUTE = /^[bmde]\d/;
|
||||
|
||||
/** `win` 의 기본 메뉴를 막음 — `isOn()` 이 거짓이면(예: A 영역 주소) 그대로 둠 */
|
||||
export function blockNativeMenu(win: Window, isOn: () => boolean): void {
|
||||
|
||||
@@ -30,6 +30,8 @@ export interface WorkflowLayoutOptions {
|
||||
/** 막힌(NOT_STARTED) 단계라도 켤 칸 — 수 하나 또는 목록(B05 · B06 = 2 · 3 · 4 · 496-1) */
|
||||
currentStage?: number | readonly number[];
|
||||
routes?: readonly string[];
|
||||
/** 단계 아이콘 — 없으면 B 일곱 단계 아이콘(D · E 그룹은 제 목록 · 529-1) */
|
||||
icons?: readonly string[];
|
||||
onStepClick?: (stepIndex: number, route: string) => void;
|
||||
/** 좌측 패널이 열리고 닫힐 때(처음 앉힘 포함) — 닫힌 동안 바뀐 안쪽을 열 때 맞춤(499-1). */
|
||||
onOptionsOpenChange?: (isOpen: boolean) => void;
|
||||
@@ -212,7 +214,7 @@ export function createWorkflowLayout(options: WorkflowLayoutOptions): WorkflowLa
|
||||
currentStage: options.currentStage,
|
||||
routes: options.routes,
|
||||
orientation: "vertical",
|
||||
icons: WORKFLOW_STEP_ICONS,
|
||||
icons: options.icons ?? WORKFLOW_STEP_ICONS,
|
||||
onStepClick: options.onStepClick,
|
||||
homeButton: true,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user