feat(M02): 컨테이너 안 「불러오는 중」 — 0.3초 넘을 때만 · 실패 = 까닭 + 다시 불러오기 (PLAN 30-6)

- 공용 부품 ui_template_loading(showLoading · loadingError · delayedShow) — 칸 안 작은 회전 표시 + 「불러오는 중...」 · 화면 전체 잠금 아님 · 다른 페이지도 씀
- 붙인 자리 — 좌측 나무(구조물 · 일위대가 · 사람 나무) · 상세 칸(구조물 표 · 도면 · 면적 · 재료) · 조합 목록 · 조합 상세 · 항목 카드
- 공용 글 Common_Load_Failed · Common_Reload
- 시험 test_ui_loading(0.3초 규칙 가짜 시계 · 실패 글 · 붙은 자리)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 20:02:36 +09:00
co-authored by Claude Opus 5.5
parent 71666a8633
commit 25cf716a0d
9 changed files with 233 additions and 6 deletions
@@ -11,6 +11,7 @@
import "./M02_MasterTemplete_TreePanel.css";
import { createInputField, el, showConfirmDialog, showToast } from "@ui/ui_template_elements";
import { loadingError, showLoading } from "@ui/ui_template_loading";
import { t as L } from "@ui/ui_template_locale";
import {
createTreeRow,
@@ -393,6 +394,7 @@ export function createTreePanel(opt: TreePanelOptions): TreePanelHandle {
async function refresh(): Promise<void> {
const mine = ++seq;
const stop = showLoading(body); // 0.3초 넘으면 나무 칸 안에 「불러오는 중」(PLAN 30-6)
try {
const got = await api.fetch(opt.layer, owner);
if (mine !== seq) return;
@@ -400,8 +402,11 @@ export function createTreePanel(opt: TreePanelOptions): TreePanelHandle {
} catch (error) {
if (mine !== seq) return;
view = null;
body.replaceChildren(hint(L("M02_PickerLoadFailed").replace("{value}", why(error))));
stop();
body.replaceChildren(loadingError(why(error), () => void refresh()));
return;
} finally {
stop(); // 늦게 온 옛 요청의 표시도 걷음
}
paint();
}