feat(구조물표): 323-5 고름 한 칸 — 관 세션 id(옮겨도 그대로 · 저장 안 함) · 고름 강조 한 규칙(pickLights · 카드 형상 · 3D 같은 함수) · 그린 것마다 신원표(data-structure-id + data-part) · 같은 자리 거리 = PIPE_MATCH_M 하나 · 322-0 이 깬 옛 시험 도움 파일 · 줄 수 고침
- `design_pipe_ids.ts` — 장부(세션 pipe-ids) · pipe-s{차례} · 자리 → id(찾는 거리 안 가장 가까운 것) · followMovedPipe 가 id 를 새 자리로(고름 id 그대로 · 순환 import 없게 design_selection 에서 옮김) · 설계 페이지가 프로젝트를 정함(usePipeIds) · 자리 이름 만들기 열 곳 · 되읽기 둘 걷음 · 측점 계획 주인 = 세션 id(withPipeIds)
- `design_pick_match.ts` — pickLights(① id ② 같은 자리 ③ 고른 부분) · paintPicked(카드 통째 형상 · 부분 · 관 계열 · 포장층은 제 손잡이) · tagShape — 관 세트 벽 · 집수정 · 관 · 세월교 측벽 · 몸체 · BOX 끝 · C군 벽 · 물넘이 콘크리트에 신원표 · 형상 판정면은 통째 형상 · 콘크리트만
- 3D — 부재 맞춤 = pickLights(옛 0.01 걷음) · C군 벽 솔리드 = 구조물 id(덮는 측점 어디서 골라도 한 번 스윕한 벽이 켜짐)
- 322-0 이 깬 것 고침 — 노면공 흐름 도움 파일(165 · 231-1) 정의 판 확인 흉내 · design_view_profile 700줄(322-0 이 704)
- 시험: test_323_5_pick(세션 id · 옮김 · 강조 규칙 · 칠하기) · 옛 시험 도움 파일 흉내 · 기대 글 고침
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
This commit is contained in:
@@ -133,6 +133,8 @@ export const STATE_REGISTRY = {
|
||||
scope: "project",
|
||||
legacy: (p) => `aislo:structure-pick:${p}`,
|
||||
},
|
||||
/** 관 세션 id 장부(323-5 · `design_pipe_ids`) — `{next, ids: [{id, at}]}` · 저장 안 함. */
|
||||
"pipe-ids": { bucket: "draft", scope: "project" },
|
||||
/** 설계 가게(`design/design_store`)의 고른 측점 · 구조물 — `{chainageM, structureId}`. */
|
||||
selection: { bucket: "draft", scope: "project" },
|
||||
/** 구조물 패널 종류별 캐시 — 고른 구조물 하나 × 종류마다 옛 값(54-32). [저장]·[확정] 뒤 비움. */
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
import { currentRoute, navigateTo, type MountedPage } from "../router";
|
||||
import type { DesignView } from "./design_dock";
|
||||
import type { DesignPageShared } from "./design_shared";
|
||||
import { usePipeIds } from "./design_pipe_ids";
|
||||
import "./design_page.css";
|
||||
|
||||
export type { DesignPageShared } from "./design_shared";
|
||||
@@ -105,6 +106,7 @@ export function renderDesignPage(root: HTMLElement): MountedPage {
|
||||
page.className = "design-page";
|
||||
root.replaceChildren(page);
|
||||
const projectId = localStorage.getItem(CURRENT_PROJECT_ID_KEY) ?? "";
|
||||
usePipeIds(projectId || null); // 관 세션 id 장부 = 이 프로젝트(323-5 · 카드 · 알약 · 종단 · 3D 같은 id)
|
||||
|
||||
// 한 벌 틀 — 좌측 자리 · 가운데(위 칸 + 아래 종단도). 진행 단계 틀은 단계 상태가 오면 감싼다.
|
||||
const left = document.createElement("div");
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/* =============================================================================
|
||||
* A00_Common/design/design_pick_match.ts
|
||||
* 고름 강조 한 규칙(323-5) — 그린 것(카드 형상 · 3D 부재 · 알약 · 측점선)마다 신원표 `{구조물 id · 부분 · 자리}`
|
||||
* 를 달고, 고름 한 칸(`structure-pick`)과 이 함수 하나로 켜짐을 가름.
|
||||
*
|
||||
* ① 고름 · 그림 둘 다 구조물 id 가 있으면 id 가 같아야(관 = 세션 id `design_pipe_ids` · 옮겨도 그대로)
|
||||
* ② 아니면 같은 자리(`PIPE_MATCH_M` — 같은 자리 거리는 이 한 값)
|
||||
* ③ 고른 부분(부재키)이 있으면 그 부분만 · 부분을 안 골랐으면 그 구조물 그림 모두
|
||||
* DOM 은 `data-structure-id` · `data-part`(`tagShape`) — 부분 그림(관 · 벽 · 날개벽 · 물넘이 콘크리트)은
|
||||
* 조정창 손잡이가 같은 고름으로 칠함(`paintPicked` 는 부분 없는 형상만 · 307 「측점 길은 부분 안 켬」).
|
||||
* ========================================================================== */
|
||||
|
||||
import { isNear, type DesignSelection } from "./design_selection";
|
||||
|
||||
export interface PickTag {
|
||||
structureId?: string | null;
|
||||
part?: string | null;
|
||||
chainageM?: number | null;
|
||||
}
|
||||
|
||||
export type PickSelection =
|
||||
(Partial<DesignSelection> & { partKey?: string | null }) | null | undefined;
|
||||
|
||||
/** 이 그림이 고름에 켜지나 — 위 ① ② ③. */
|
||||
export function pickLights(selection: PickSelection, tag: PickTag): boolean {
|
||||
if (!selection) return false;
|
||||
let here: boolean;
|
||||
if (selection.structureId && tag.structureId) here = selection.structureId === tag.structureId;
|
||||
else if (selection.chainageM == null || tag.chainageM == null) return false;
|
||||
else here = isNear(tag.chainageM, selection.chainageM);
|
||||
if (!here) return false;
|
||||
return !selection.partKey || tag.part === selection.partKey;
|
||||
}
|
||||
|
||||
/** 그린 형상에 신원표를 닮(부분 없으면 통째 형상). */
|
||||
export function tagShape(el: Element, structureId: string | null, part?: string | null): void {
|
||||
if (structureId) el.setAttribute("data-structure-id", structureId);
|
||||
if (part) el.setAttribute("data-part", part);
|
||||
}
|
||||
|
||||
/** 카드 안 통째 형상 칠하기 — 고른 구조물 id 와 같은 형상만. 부분 그림(`data-part`) · 관 계열(`pipe-`) ·
|
||||
* 노면공 포장층은 제 손잡이(조정창 · 포장층 고름)가 칠함 — 측점 길(알약 · 목록 · 측점선)은 부분을 안 켬(307). */
|
||||
export function paintPicked(root: ParentNode, selection: PickSelection): void {
|
||||
for (const shape of root.querySelectorAll<SVGElement>("[data-structure-id]")) {
|
||||
const id = shape.getAttribute("data-structure-id") ?? "";
|
||||
if (id.startsWith("pipe-") || shape.getAttribute("data-part") !== null) continue;
|
||||
if (shape.getAttribute("data-pave-type") !== null) continue;
|
||||
shape.classList.toggle(
|
||||
"is-active",
|
||||
!!selection?.structureId && pickLights(selection, { structureId: id }),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
* 고름 한 칸(`structure-pick`)이 유일 원천이다. 값이 바뀌면(구독) 그 값으로 종단도를 다시 세우고,
|
||||
* 관 · 구조물 목록이 바뀐 뒤에도 같은 값으로 다시 얹는다(`paint`) — 화면끼리 손으로 부르던 길이
|
||||
* 하나 빠지거나 다른 길이 강조를 끄더라도 종단도는 값을 따라간다. 관 알약 id(`pipe-`+측점)는
|
||||
* 그릴 때마다 지금 관 목록에서 다시 찾으므로 관이 옮겨져도 끊기지 않는다.
|
||||
* 그릴 때마다 지금 관 목록에서 다시 찾고 관 id 는 세션 id(323-5)라 관이 옮겨져도 끊기지 않는다.
|
||||
* ========================================================================== */
|
||||
|
||||
import {
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
type DesignSelection,
|
||||
} from "./design_selection";
|
||||
import { bindEscapeRelease, ESCAPE_FROM } from "./design_pick_escape";
|
||||
import { pipeIdAt } from "./design_pipe_ids";
|
||||
import { graphTargetAt } from "../../B05_Profile/B05_Profile_UI_Selection";
|
||||
import { irregularStationId } from "../../B05_Profile/B05_Profile_UI_IrregularStations";
|
||||
|
||||
@@ -68,9 +69,7 @@ export function profilePickOf(
|
||||
);
|
||||
if (own) return { stationId: irregularStationId(own.id) };
|
||||
const target = graphTargetAt(null, at, source.pipes(), source.sections());
|
||||
return "pipeChainageM" in target
|
||||
? { structureId: `pipe-${target.pipeChainageM.toFixed(2)}` }
|
||||
: target;
|
||||
return "pipeChainageM" in target ? { structureId: pipeIdAt(target.pipeChainageM) } : target;
|
||||
}
|
||||
|
||||
export function paintProfilePick(target: ProfilePickTarget, pick: ProfilePick): void {
|
||||
@@ -91,7 +90,9 @@ export function paintMapPick(
|
||||
export interface ViewerPickTarget {
|
||||
markers: { selectStation: (stationId: string | null, notify?: boolean) => void };
|
||||
structurePick: {
|
||||
select: (pick: { chainageM: number; kind: string; key?: string } | null) => void;
|
||||
select: (
|
||||
pick: { chainageM: number; kind: string; key?: string; structureId?: string | null } | null,
|
||||
) => void;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -100,7 +101,10 @@ export interface ViewerPickTarget {
|
||||
export function viewerPickOf(
|
||||
selection: (DesignSelection & { partKey?: string }) | null,
|
||||
source: ProfilePickSource,
|
||||
): { stationId: string | null; member: { chainageM: number; kind: string; key?: string } | null } {
|
||||
): {
|
||||
stationId: string | null;
|
||||
member: { chainageM: number; kind: string; key?: string; structureId?: string | null } | null;
|
||||
} {
|
||||
if (!selection || selection.chainageM === null) return { stationId: null, member: null };
|
||||
const at = selection.chainageM;
|
||||
const pick = profilePickOf(selection, source);
|
||||
@@ -108,7 +112,10 @@ export function viewerPickOf(
|
||||
? nearestWithin(source.irregular(), at, (entry) => entry.chainage_m)
|
||||
: undefined;
|
||||
const stationId = "stationId" in pick ? pick.stationId : own ? irregularStationId(own.id) : null;
|
||||
return { stationId, member: { chainageM: at, kind: "", key: selection.partKey } };
|
||||
return {
|
||||
stationId,
|
||||
member: { chainageM: at, kind: "", key: selection.partKey, structureId: selection.structureId },
|
||||
};
|
||||
}
|
||||
|
||||
export function paintViewerPick(
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/* =============================================================================
|
||||
* A00_Common/design/design_pipe_ids.ts
|
||||
* 관 세션 id(323-5) — 관을 처음 볼 때 자리마다 붙이는 id · 옮겨도 그대로 · 저장 안 함(파일 모양 그대로).
|
||||
*
|
||||
* id = `pipe-s` + 차례(`pipe-s3`) — 머리 `pipe-` 로 관임을 가름(옛 자리 이름 `pipe-{누가거리}` 와 같은 머리) ·
|
||||
* 누가거리는 id 에서 읽지 않음(`pipeChainageOf`). 장부 = 세션 `pipe-ids`(고름 `structure-pick` 과 같은 수명 ·
|
||||
* 초안 비우기에 함께 비움). 자리 → id = 찾는 거리(`PIPE_MATCH_M`) 안 가장 가까운 것 · 없으면 새 차례 ·
|
||||
* 옮김 = `movePipeId`(고름 따라가기 `followMovedPipe` 가 부름).
|
||||
* 프로젝트 = 보기가 열 때 정함(`usePipeIds`) — 그리는 함수(카드 · 알약)가 프로젝트를 몰라도 같은 id.
|
||||
* 프로젝트가 없으면(시험 · 도움 파일) 옛 자리 이름.
|
||||
* ========================================================================== */
|
||||
|
||||
import { readState, writeState } from "../b_page_state";
|
||||
import { isNear, nearestWithin, readSelection, selectDesign } from "./design_selection";
|
||||
|
||||
/** 관 찾는 거리 — 정의는 `design_selection` 한 곳(배수 패널이 관 옮김과 함께 가져감). */
|
||||
export { PIPE_MATCH_M } from "./design_selection";
|
||||
|
||||
interface Book {
|
||||
next: number;
|
||||
ids: Array<{ id: string; at: number }>;
|
||||
}
|
||||
|
||||
let active: string | null = null;
|
||||
|
||||
/** 지금 프로젝트 — 종단 · 횡단 보기가 열 때. */
|
||||
export function usePipeIds(projectId: string | null): void {
|
||||
active = projectId;
|
||||
}
|
||||
|
||||
const bookOf = (projectId: string): Book =>
|
||||
readState<Book>("pipe-ids", projectId) ?? { next: 1, ids: [] };
|
||||
|
||||
/** 그 자리 관의 id — 장부에 없으면 새 차례로 적음. */
|
||||
export function pipeIdAt(chainageM: number, projectId: string | null = active): string {
|
||||
if (!projectId) return `pipe-${chainageM.toFixed(2)}`;
|
||||
const book = bookOf(projectId);
|
||||
const hit = nearestWithin(book.ids, chainageM, (entry) => entry.at);
|
||||
if (hit) return hit.id;
|
||||
const id = `pipe-s${book.next}`;
|
||||
writeState(
|
||||
"pipe-ids",
|
||||
{ next: book.next + 1, ids: [...book.ids, { id, at: chainageM }] },
|
||||
projectId,
|
||||
);
|
||||
return id;
|
||||
}
|
||||
|
||||
/** id 의 관 자리 — 장부 · 옛 자리 이름 순 · 관 id 가 아니면 null. */
|
||||
export function pipeChainageOf(id: string, projectId: string | null = active): number | null {
|
||||
if (!id.startsWith("pipe-")) return null;
|
||||
const hit = projectId ? bookOf(projectId).ids.find((entry) => entry.id === id) : undefined;
|
||||
if (hit) return hit.at;
|
||||
const legacy = Number(id.slice("pipe-".length));
|
||||
return Number.isFinite(legacy) ? legacy : null;
|
||||
}
|
||||
|
||||
/** 관을 옮김 — 옛 자리 id 가 새 자리로(새 자리에 남은 옛 기록은 뺌) · 옮긴 관의 id. */
|
||||
export function movePipeId(fromM: number, toM: number, projectId: string | null = active): string {
|
||||
if (!projectId) return `pipe-${toM.toFixed(2)}`;
|
||||
const book = bookOf(projectId);
|
||||
const moving = nearestWithin(book.ids, fromM, (entry) => entry.at);
|
||||
if (!moving) return pipeIdAt(toM, projectId);
|
||||
const stale = nearestWithin(
|
||||
book.ids.filter((entry) => entry !== moving),
|
||||
toM,
|
||||
(entry) => entry.at,
|
||||
);
|
||||
const ids = book.ids
|
||||
.filter((entry) => entry !== stale)
|
||||
.map((entry) => (entry === moving ? { ...entry, at: toM } : entry));
|
||||
writeState("pipe-ids", { next: book.next, ids }, projectId);
|
||||
return moving.id;
|
||||
}
|
||||
|
||||
/** 관 목록에 세션 id 를 얹은 사본 — 측점 계획의 덮는 구조물 id(종단 측점 id · 알약 짝)가 세션 id. */
|
||||
export function withPipeIds<T extends { chainage_m: number }>(
|
||||
pipes: ReadonlyArray<T>,
|
||||
projectId: string | null = active,
|
||||
): Array<T & { id: string }> {
|
||||
return pipes.map((pipe) => ({ ...pipe, id: pipeIdAt(pipe.chainage_m, projectId) }));
|
||||
}
|
||||
|
||||
/** 관을 옮김 — 관 세션 id 가 새 자리로(323-5 · id 그대로) · 그 관을 골라 둔 고름이면 자리만 새로(부재키
|
||||
* 그대로 · 옛 자리 이름 id 면 세션 id 로). 다른 것을 골랐으면 그대로. */
|
||||
export function followMovedPipe(projectId: string | null, fromM: number, toM: number): void {
|
||||
const id = movePipeId(fromM, toM, projectId);
|
||||
const picked = readSelection(projectId);
|
||||
if (!picked || picked.chainageM === null || !isNear(picked.chainageM, fromM)) return;
|
||||
const sid = picked.structureId;
|
||||
if (sid !== null && !sid.startsWith("pipe-")) return;
|
||||
selectDesign(
|
||||
projectId,
|
||||
{ chainageM: toM, structureId: sid === null ? null : id },
|
||||
{ partKey: picked.partKey },
|
||||
);
|
||||
}
|
||||
@@ -188,17 +188,3 @@ export function selectDesign(
|
||||
dispatching = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 관을 옮김 — 그 관을 골라 둔 고름이면 새 자리로(322-3 · 관 id = 자리 이름 `pipe-{누가거리}` 라 id 도
|
||||
* 새 자리로 · 옮겨도 고름 유지 · 부재키 그대로). 다른 것을 골랐으면 그대로. */
|
||||
export function followMovedPipe(projectId: string | null, fromM: number, toM: number): void {
|
||||
const picked = readSelection(projectId);
|
||||
if (!picked || picked.chainageM === null || !isNear(picked.chainageM, fromM)) return;
|
||||
const sid = picked.structureId;
|
||||
if (sid !== null && !sid.startsWith("pipe-")) return;
|
||||
selectDesign(
|
||||
projectId,
|
||||
{ chainageM: toM, structureId: sid === null ? null : `pipe-${toM.toFixed(2)}` },
|
||||
{ partKey: picked.partKey },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* → 한 목록(초안이 있으면 초안 · 없으면 저장분 · 종류마다 따로) · 측점 계획 한 벌(`planStations`) →
|
||||
* 종단 측점 목록(B05 종단 · 3D 막대 · B06 종단 띠가 같은 꼴).
|
||||
*
|
||||
* 구조물 id = 구조물은 structure_id · 관은 자리 이름 `pipe-{누가거리 2자리}`(파일 모양 그대로 · 저장 안 함).
|
||||
* 구조물 id = 구조물은 structure_id · 관은 세션 id(`design_pipe_ids` · 323-5 · 파일 모양 그대로 · 저장 안 함).
|
||||
* ========================================================================== */
|
||||
|
||||
import type { IrregularStation } from "../../B05_Profile/B05_Profile_UI_IrregularStations";
|
||||
@@ -18,9 +18,6 @@ export function structureStatus<P, S>(
|
||||
return { pipes: [...(drafts[0] ?? saved[0])], structures: [...(drafts[1] ?? saved[1])] };
|
||||
}
|
||||
|
||||
/** 관 id(현황 · 알약 · 고름이 같은 값) — 자리 이름. */
|
||||
export const pipeId = (chainageM: number): string => `pipe-${chainageM.toFixed(2)}`;
|
||||
|
||||
/**
|
||||
* 측점 계획 → 종단 측점(측점번호 · 잔여거리 = 간격 기준) — 기준 측점 id = 첫 주인 id(관 = `pipe-…` ·
|
||||
* 구조물 = structure_id) · 시작 · 끝 = `{id}:{역할}`(옮겨도 계획고 편집이 따라감 · 272) · 관 기준 측점 =
|
||||
|
||||
@@ -18,6 +18,7 @@ import { readByKey, stateKey, writeByKey } from "../b_page_state";
|
||||
import { showToast } from "@ui/ui_template_elements";
|
||||
import { mountMissingStationNotice } from "../../B06_Section/B06_Section_UI_Missing_Stations";
|
||||
import { onStaleStructureTypes } from "../../B05_Profile/B05_Profile_Api_Structures";
|
||||
import { pipeIdAt } from "./design_pipe_ids";
|
||||
import {
|
||||
fetchSectionContext,
|
||||
getSections,
|
||||
@@ -399,7 +400,7 @@ export async function mountCrossView(
|
||||
// 카드 고름은 그 카드 측점선으로 알약을 맞춤 — 일반 측점 구조물 · 옆 측점 이음 카드면
|
||||
// 알약이 꺼지므로 연 것으로 다시 세움(관 알약 id = pipe-측점 · 53-1)
|
||||
const pipeAt = structuresPanel.currentChainage();
|
||||
const mark = opened.structureId ?? (pipeAt === null ? null : `pipe-${pipeAt.toFixed(2)}`);
|
||||
const mark = opened.structureId ?? (pipeAt === null ? null : pipeIdAt(pipeAt, projectId));
|
||||
sectionView.selectMark(mark, false); // 측점 고름 = 카드 하나(137-4) · 덮는 것 없으면 알약 · 강조 풂(152-5)
|
||||
structureSelection.syncInletStructure();
|
||||
// 카드만 고른 경우엔 구조물(벽·구체) 선택을 비운다 — 조정창이 저절로 뜨면 안 된다
|
||||
|
||||
@@ -41,7 +41,6 @@ import {
|
||||
type DesignPageShared,
|
||||
} from "./design_shared";
|
||||
import { bindProfileViewLife } from "../../B05_Profile/B05_Profile_UI_Page_Life";
|
||||
import { structureAnchorM } from "../../B05_Profile/B05_Profile_Api_Structures";
|
||||
import { createStructuresBridge } from "../../B05_Profile/B05_Profile_UI_Page_Structures";
|
||||
import { createRouteViewer } from "../../B05_Profile/B05_Profile_UI_Viewer";
|
||||
import {
|
||||
@@ -60,6 +59,7 @@ import { loadSectionDetail } from "../../B06_Section/B06_Section_Section_Store";
|
||||
import {
|
||||
migrateLegacyStations,
|
||||
onStaleStructureTypes,
|
||||
structureAnchorM,
|
||||
} from "../../B05_Profile/B05_Profile_Api_Structures";
|
||||
import { pipeToFacilityItem } from "../../B05_Profile/B05_Profile_UI_Structures_Panel_Types";
|
||||
import {
|
||||
@@ -80,6 +80,7 @@ import "../../B05_Profile/B05_Profile_UI_Style.css";
|
||||
import "../../B05_Profile/B05_Profile_UI_Style_Table.css";
|
||||
import "../../B05_Profile/B05_Profile_UI_Style_Drainage.css";
|
||||
import "../../B05_Profile/B05_Profile_UI_Style_Structures.css";
|
||||
import { pipeIdAt } from "./design_pipe_ids";
|
||||
import {
|
||||
DEFAULT_ROAD_WIDTHS,
|
||||
fetchRoadWidths,
|
||||
@@ -134,10 +135,8 @@ export async function mountProfileView(
|
||||
const structurePick = !!readSelection(activeProjectId)?.structureId;
|
||||
const sections = structurePick ? [] : (currentSectionDetail?.cross_sections ?? []);
|
||||
const target = graphTargetAt(id, chainageM, lastPipes ?? [], sections);
|
||||
if ("pipeChainageM" in target) {
|
||||
profilePanel.setSelectedStructure(`pipe-${target.pipeChainageM.toFixed(2)}`);
|
||||
return;
|
||||
}
|
||||
if ("pipeChainageM" in target)
|
||||
return profilePanel.setSelectedStructure(pipeIdAt(target.pipeChainageM, activeProjectId));
|
||||
profilePanel.setSelectedStation(target.stationId);
|
||||
if (id === null && target.stationId !== null) viewer.markers.selectStation(target.stationId);
|
||||
};
|
||||
@@ -552,11 +551,8 @@ export async function mountProfileView(
|
||||
});
|
||||
|
||||
// 탭이 다시 보일 때 정의 판이 바뀌었으면 종류 · 패널 다시 읽음(322-0)
|
||||
host.onDispose(
|
||||
onStaleStructureTypes(() => {
|
||||
if (host.visible() && !restoring) void bridge.load();
|
||||
}),
|
||||
);
|
||||
const reloadIfShown = (): void => void (host.visible() && !restoring && bridge.load());
|
||||
host.onDispose(onStaleStructureTypes(reloadIfShown));
|
||||
// 한 페이지 두 보기 — 숨김 · 보임 · 떠남(계획서 24-3a · 24-3b).
|
||||
bindProfileViewLife(host, {
|
||||
projectId: activeProjectId,
|
||||
|
||||
Reference in New Issue
Block a user