fix(ui_template): 나무 화살표 · 줄 수 글자 대비 · 항목 고르기 툴팁 · 자리표 이름 (PLAN 21-10 흠 5~7)
- 나무 화살표 · 줄 수와 항목 고르기의 흐린 글을 var(--color-text-secondary) 로 — 밝은 테마 대비 3.08 → 6.3 이상 - M01 왼쪽 목록 줄 수도 같은 공용 클래스(ui-tree__count)로 — 밝은 테마 2.64 → 5.41 - 항목 고르기: 잎 툴팁 = 층 이름 + 키 · 「새 분류N」 자리표는 이름 · 나무 이름에서 뺌 · 관리 화면 단추는 개인 항목만(확인) - ghost 단추는 두 테마 모두 6.85 이상이라 색 변경 없음 — 다크 1.06 은 ORCA 탭이 색 전환을 멈춰 생긴 측정값 - 자료 시험에 자리표 · 툴팁 추가 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K7JS47SacjPxZ718QsZKyr
This commit is contained in:
@@ -186,7 +186,7 @@ export function buildSide(
|
||||
? []
|
||||
: [
|
||||
el("span", {
|
||||
className: "m01-side__muted",
|
||||
className: "ui-tree__count",
|
||||
text: node.count.toLocaleString("ko-KR"),
|
||||
}),
|
||||
]),
|
||||
|
||||
@@ -11,6 +11,8 @@ import {
|
||||
itemName,
|
||||
pathIds,
|
||||
rowId,
|
||||
rowTip,
|
||||
shown,
|
||||
toSummary,
|
||||
type PickerRow,
|
||||
type TreeLabels,
|
||||
@@ -72,6 +74,33 @@ assert.equal(itemName(rows[6]), "옹벽 H=2m");
|
||||
assert.equal(itemName({ key: "SS000009", 열: "zz" }), "zz");
|
||||
assert.equal(itemName({ key: "SS000009", 열: "" }), "SS000009");
|
||||
|
||||
// 「새 분류N」 자리표는 이름 · 나무 이름에서 뺌
|
||||
assert.equal(shown("새 분류1"), "");
|
||||
assert.equal(shown("새 분류 12"), "");
|
||||
assert.equal(shown("새 분류"), "");
|
||||
assert.equal(shown("새 분류표"), "새 분류표"); // 자리표가 아닌 진짜 이름은 그대로
|
||||
assert.equal(shown(undefined), "");
|
||||
const fresh = row("SS000300", "n1", "새 분류1", ["새 분류2", "", ""], "personal", {
|
||||
분류3: "새 분류3",
|
||||
});
|
||||
assert.equal(itemName(fresh), "n1"); // 이름이 모두 자리표면 열 id
|
||||
assert.equal(
|
||||
itemName(row("SS000301", "n2", "옹벽", ["새 분류1", "H=2m", ""], "personal")),
|
||||
"옹벽 H=2m",
|
||||
);
|
||||
const placeholderTree = buildTree([fresh], labels);
|
||||
assert.equal(placeholderTree[2].children?.[0].label, "분류 없음"); // 종류
|
||||
assert.equal(placeholderTree[2].children?.[0].children?.[0].label, "분류 없음"); // 분류1
|
||||
assert.deepEqual(pathIds(fresh, labels), [
|
||||
"personal",
|
||||
"personal|분류 없음",
|
||||
"personal|분류 없음|분류 없음",
|
||||
]);
|
||||
|
||||
// 툴팁 = 층 이름 + 키
|
||||
assert.equal(rowTip(rows[7], labels), "개인 · SS000201");
|
||||
assert.equal(rowTip(rows[5], labels), "회사 · SS000101");
|
||||
|
||||
// 나무 — 그룹은 늘 마스터 · 회사 · 개인 차례 · 그룹 → 종류 → 분류1 → 잎
|
||||
const tree = buildTree(rows, labels);
|
||||
assert.deepEqual(
|
||||
@@ -96,7 +125,7 @@ assert.equal(cat?.label, "메쌓기");
|
||||
assert.equal(cat?.count, 2);
|
||||
const leaf = cat?.children?.[0];
|
||||
assert.equal(leaf?.label, "돌기슭막이 메쌓기 1.2m 기초유");
|
||||
assert.equal(leaf?.tip, "SS000001"); // 키는 툴팁
|
||||
assert.equal(leaf?.tip, "마스터 · SS000001"); // 툴팁 = 층 이름 + 키
|
||||
assert.equal(leaf?.count, null);
|
||||
assert.ok(leaf?.row);
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
.ui-item-picker__where,
|
||||
.ui-item-picker__hint {
|
||||
margin: 0;
|
||||
color: var(--color-text-muted);
|
||||
color: var(--color-text-secondary);
|
||||
font-size: var(--text-caption);
|
||||
}
|
||||
|
||||
@@ -87,16 +87,16 @@
|
||||
|
||||
.ui-item-picker__folder-label {
|
||||
flex: 0 0 5.5em;
|
||||
color: var(--color-text-muted);
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.ui-item-picker__key {
|
||||
color: var(--color-text-muted);
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.ui-item-picker__none {
|
||||
color: var(--color-text-muted);
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.ui-item-picker__actions {
|
||||
|
||||
@@ -20,6 +20,8 @@ import {
|
||||
ownerOf,
|
||||
pathIds,
|
||||
rowId,
|
||||
rowTip,
|
||||
shown,
|
||||
toSummary,
|
||||
type FolderKind,
|
||||
type PickNode,
|
||||
@@ -127,7 +129,7 @@ export function openItemPicker(opts: ItemPickerOptions): Promise<ItemPickerResul
|
||||
if (!chosen) {
|
||||
detail.replaceChildren(hint(t("M02_PickerHint")));
|
||||
} else {
|
||||
const where = [labels().layers[layerOf(chosen)], chosen.종류, chosen.분류1]
|
||||
const where = [labels().layers[layerOf(chosen)], shown(chosen.종류), shown(chosen.분류1)]
|
||||
.filter(Boolean)
|
||||
.join(" › ");
|
||||
const small = (text: string): HTMLElement =>
|
||||
@@ -136,7 +138,7 @@ export function openItemPicker(opts: ItemPickerOptions): Promise<ItemPickerResul
|
||||
el("h4", {
|
||||
className: "ui-item-picker__name",
|
||||
text: itemName(chosen),
|
||||
attrs: { title: chosen.key },
|
||||
attrs: { title: rowTip(chosen, labels()) },
|
||||
}),
|
||||
small(where),
|
||||
...(chosen.단위 ? [small(`${t("M02_PickerUnit")} ${chosen.단위}`)] : []),
|
||||
|
||||
@@ -54,9 +54,20 @@ export interface PickNode {
|
||||
row?: PickerRow;
|
||||
}
|
||||
|
||||
/** 보이는 항목 이름 — 종류 · 분류1~3 을 이음(비면 열 id · 키) */
|
||||
/** 「새 분류1」 같은 새로 만들 때의 자리표는 이름이 아님 — 보이는 글에서 뺌 */
|
||||
const PLACEHOLDER = /^새 분류\s*\d*$/;
|
||||
export const shown = (part?: string): string =>
|
||||
part && !PLACEHOLDER.test(part.trim()) ? part : "";
|
||||
|
||||
/** 보이는 항목 이름 — 종류 · 분류1~3 을 이음(자리표는 뺌 · 비면 열 id · 키) */
|
||||
export const itemName = (row: PickerRow): string =>
|
||||
[row.종류, row.분류1, row.분류2, row.분류3].filter(Boolean).join(" ") || row.열 || row.key;
|
||||
[row.종류, row.분류1, row.분류2, row.분류3].map(shown).filter(Boolean).join(" ") ||
|
||||
row.열 ||
|
||||
row.key;
|
||||
|
||||
/** 마우스를 올렸을 때 — 층 이름 + 키 */
|
||||
export const rowTip = (row: PickerRow, labels: TreeLabels): string =>
|
||||
`${labels.layers[layerOf(row)]} · ${row.key}`;
|
||||
|
||||
export const layerOf = (row: PickerRow): PickerLayer => row.layer ?? "system";
|
||||
export const ownerOf = (row: PickerRow): string | null =>
|
||||
@@ -108,8 +119,8 @@ export function buildTree(rows: PickerRow[], labels: TreeLabels): PickNode[] {
|
||||
const mine = rows.filter((row) => layerOf(row) === layer);
|
||||
const kinds = new Map<string, Map<string, PickerRow[]>>();
|
||||
for (const row of mine) {
|
||||
const kind = row.종류 || labels.unclassified;
|
||||
const cat = row.분류1 || labels.unclassified;
|
||||
const kind = shown(row.종류) || labels.unclassified;
|
||||
const cat = shown(row.분류1) || labels.unclassified;
|
||||
const cats = kinds.get(kind) ?? new Map<string, PickerRow[]>();
|
||||
cats.set(cat, [...(cats.get(cat) ?? []), row]);
|
||||
kinds.set(kind, cats);
|
||||
@@ -122,7 +133,7 @@ export function buildTree(rows: PickerRow[], labels: TreeLabels): PickNode[] {
|
||||
children: leaves.map((row) => ({
|
||||
id: rowId(row),
|
||||
label: itemName(row),
|
||||
tip: row.key,
|
||||
tip: rowTip(row, labels),
|
||||
count: null,
|
||||
row,
|
||||
})),
|
||||
@@ -141,8 +152,8 @@ export function buildTree(rows: PickerRow[], labels: TreeLabels): PickNode[] {
|
||||
/** 잎까지 가는 길의 나무 줄 id — 처음부터 펼칠 자리 */
|
||||
export function pathIds(row: PickerRow, labels: TreeLabels): string[] {
|
||||
const layer = layerOf(row);
|
||||
const kind = row.종류 || labels.unclassified;
|
||||
const cat = row.분류1 || labels.unclassified;
|
||||
const kind = shown(row.종류) || labels.unclassified;
|
||||
const cat = shown(row.분류1) || labels.unclassified;
|
||||
return [layer, `${layer}|${kind}`, `${layer}|${kind}|${cat}`];
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
.ui-tree__caret {
|
||||
display: inline-block;
|
||||
width: var(--spacing-12);
|
||||
color: var(--color-text-muted);
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.ui-tree__count {
|
||||
color: var(--color-text-muted);
|
||||
color: var(--color-text-secondary);
|
||||
font-size: var(--text-caption);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user