feat(709-2): M01 표 · M02 목록 줄 수 = 화면 높이 · 쪽 단추 표 아래 · 한 장 표 화면 안 스크롤

- 쪽 있는 표(요소 · 표 목록 · 로직 목록 · 재료 고르기 모달 · M02 서고 · 새 항목 목록): 줄 수를 표 칸 위치 ~ 화면 아래로 셈(watchFit) · 창 크기 · 글꼴 늦게 실림에도 다시 셈 · 쪽 크기 바뀌어도 첫 줄 유지
- 쪽 단추 = 표 바로 아래 · 줄이 모자라면 표와 함께 위로 붙음
- 쪽 없는 한 장 표(소요량 · 계수): 높이를 화면 아래로 묶고 안에서 스크롤(watchHeight · 표 아래 주 높이 뺌)
- UI_Style.css 의 max-height calc(100dvh - 300px) 제거 · m01-master__pager 규칙 제거(부품 ui-pager 로)
- 낡은 점검 51-10(쪽 단추가 거름 줄 안에 있다고 봄) = 표 바로 아래 ui-pager 로 고침
This commit is contained in:
2026-11-01 15:19:35 +09:00
parent 2e43011069
commit 1a931e2ea1
12 changed files with 265 additions and 107 deletions
@@ -16,6 +16,7 @@ import {
import { t as L } from "@ui/ui_template_locale";
import { openModal } from "@ui/ui_template_modal";
import { buildPager } from "../M01_MasterData/M01_MasterData_UI_Cells";
import { pageKeepFirst, watchFit } from "@ui/ui_template_pager";
import { buildHeadFilters } from "../M01_MasterData/M01_MasterData_UI_Head";
import "../M01_MasterData/M01_MasterData_UI_Style.css";
import {
@@ -103,6 +104,7 @@ export function mountLibraryList(
let rows: Row[] = [];
let picked: string | null = null;
let page = 1;
let size = SIZE; // 붙은 뒤 화면 높이로 다시 셈
const searchField = createInputField({ type: "search", placeholder: tc("Search") });
const body = el("tbody");
let pager = buildPager(0, SIZE, 1, () => {});
@@ -116,8 +118,8 @@ export function mountLibraryList(
const draw = (): void => {
const q = searchField.input.value.trim().toLowerCase();
const shown = rows.filter((r) => !q || libraryLabel(r).toLowerCase().includes(q));
page = Math.min(page, Math.max(1, Math.ceil(shown.length / SIZE)));
const next = buildPager(shown.length, SIZE, page, (p) => {
page = Math.min(page, Math.max(1, Math.ceil(shown.length / size)));
const next = buildPager(shown.length, size, page, (p) => {
page = p;
draw();
});
@@ -125,7 +127,7 @@ export function mountLibraryList(
pager = next;
body.replaceChildren(
...(shown.length
? shown.slice((page - 1) * SIZE, page * SIZE).map((row) => {
? shown.slice((page - 1) * size, page * size).map((row) => {
const radio = el("input", {
attrs: { type: "radio", name: `m02-lib-${opt.kind}`, "aria-label": row.이름 },
}) as HTMLInputElement;
@@ -252,25 +254,34 @@ export function mountLibraryList(
"Lib_Base",
"Lib_Date",
] as const;
host.replaceChildren(
buildHeadFilters([searchField.root, pager]),
el("div", {
className: "ui-table-wrap m01-master__grid-wrap",
attrs: { "data-lib-list": opt.kind },
children: [
el("table", {
className: "ui-table m01-master__grid",
children: [
el("thead", {
children: [
el("tr", { children: heads.map((h) => el("th", { text: h ? tc(h) : "" })) }),
],
}),
body,
],
}),
],
}),
const gridBox = el("div", {
className: "ui-table-wrap m01-master__grid-wrap",
attrs: { "data-lib-list": opt.kind },
children: [
el("table", {
className: "ui-table m01-master__grid",
children: [
el("thead", {
children: [
el("tr", { children: heads.map((h) => el("th", { text: h ? tc(h) : "" })) }),
],
}),
body,
],
}),
],
});
host.replaceChildren(buildHeadFilters([searchField.root]), gridBox, pager);
watchFit(
host,
() => gridBox,
(rows) => {
if (rows === size) return;
page = pageKeepFirst(page, size, rows);
size = rows;
draw();
},
{ once: true },
);
if (opt.canEdit)
tools.replaceChildren(