From 4ef3650454c4ad0ab0e2c09d79bee16ababb4f26 Mon Sep 17 00:00:00 2001 From: ypshim Date: Wed, 4 Nov 2026 09:25:00 +0900 Subject: [PATCH] =?UTF-8?q?feat(plan):=20=EB=82=A0=EA=B0=9C=EB=B2=BD=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=20=ED=83=80=EC=9D=BC=EC=97=90=20=ED=98=84?= =?UTF-8?q?=EC=9E=AC=20=ED=98=95=EC=8B=9D=EC=9D=84=20=EB=B0=98=EC=98=81?= =?UTF-8?q?=ED=95=9C=20=EA=B7=B8=EB=A6=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 좌우: 평면 그림. 같게 = 좌측 형식의 날개벽 두 개와 "=", 따로 = 현재 좌우 형식 (같으면 긴 것 · 짧은 것으로 예시) - 편집할 측: 현재 좌우 형식대로 두 날개벽을 그리고, 고른 측을 굵게, 다른 측은 흐린 점선. 글자는 "좌 · ① 쪽"만 남김 - 형식: 측면 그림. 일반형 = 길고 아랫면이 비스듬한 사다리꼴, 단축형 = 짧은 직사각형, 없음 = 벽체 선과 점선 윤곽 - 그림은 48 × 24, 선 색 = 글자 색 (선택 파랑 · 비활성 회색). 테스트 669건 통과, 빌드 통과. 브라우저 시각 확인은 미실시 Co-Authored-By: Claude Opus 5.5 --- src/main.ts | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/main.ts b/src/main.ts index 01ca98b..12cd3ce 100644 --- a/src/main.ts +++ b/src/main.ts @@ -966,6 +966,34 @@ function fillAbutBearingCard( box.append(el('p', `검사 · ${abutBearingChecks(model, members, rule, H).join(' · ')}`, 'muted small abut-checks')); } +/** + * 날개벽 타일 그림 (2026-11-04, 48 × 24, 선 색 = 글자 색). 평면 그림은 위가 흉벽 · 벽체, 아래로 날개벽이 뻗는다. + * 날개벽 모양은 현재 형식을 따른다: 일반형 = 길게, 단축형 = 짧게(뒷굽 끝까지), 없음 = 흐린 점선. + */ +const WING_ICON = { + plan(left: WingForm, right: WingForm, focus?: 'left' | 'right', equal = false): string { + const stroke = (on: boolean) => (on ? 'stroke="currentColor" stroke-width="2.6"' : 'stroke="currentColor" stroke-width="1.6" stroke-dasharray="2 2" opacity="0.45"'); + const wing = (side: 'left' | 'right', form: WingForm) => { + const x = side === 'left' ? 10 : 38; + const dx = side === 'left' ? -1 : 1; + const on = form !== 'none' && (focus === undefined || focus === side); + const len = form === 'general' ? 12 : 5; + const style = form === 'none' ? stroke(false) : stroke(on); + return ``; + }; + const wall = ''; + const eq = equal ? '' : ''; + return wall + wing('left', left) + wing('right', right) + eq; + }, + side(form: WingForm): string { + const solid = 'fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"'; + const faint = 'fill="none" stroke="currentColor" stroke-width="1.3" stroke-dasharray="2 2" opacity="0.45"'; + if (form === 'general') return ``; + if (form === 'short') return ``; + return ``; + }, +}; + /** skew (deg) as 95°02′52″. */ function dms(deg: number): string { const total = Math.round(Math.abs(deg) * 3600); @@ -993,13 +1021,21 @@ function fillAbutWingCard( const sideName = (s: 'left' | 'right') => (s === 'left' ? '좌 · ① 쪽' : `우 · ${circled(lastNo)} 쪽`); box.append( optionTiles('좌우', [ - { label: '좌우 같게', on: linked, isDefault: true, pick: () => apply(setWingsLinked(rec, true)) }, - { label: '따로 정하기', on: !linked, pick: () => apply(setWingsLinked(rec, false)) }, + // 같게: the left form on both sides with "="; 따로: the current forms, or long / short when they happen to match. + { label: '좌우 같게', icon: WING_ICON.plan(forms.left, forms.left, undefined, true), on: linked, isDefault: true, pick: () => apply(setWingsLinked(rec, true)) }, + { + label: '따로 정하기', + icon: forms.left === forms.right ? WING_ICON.plan('general', 'short') : WING_ICON.plan(forms.left, forms.right), + on: !linked, + pick: () => apply(setWingsLinked(rec, false)), + }, ]), optionTiles( '편집할 측', (['left', 'right'] as const).map((s) => ({ - label: `${sideName(s)} · ${NAME[forms[s]]}`, + // The picture shows both wings in their current form, with this side drawn bold. + label: sideName(s), + icon: WING_ICON.plan(forms.left, forms.right, s), on: side === s, pick: () => { state.abutWingSide = s; @@ -1012,6 +1048,7 @@ function fillAbutWingCard( `${side === 'left' ? '좌' : '우'} 날개벽 (${sideName(side).split(' · ')[1]}) 형식`, (['general', 'short', 'none'] as const).map((f) => ({ label: NAME[f], + icon: WING_ICON.side(f), on: forms[side] === f, isDefault: f === 'general', pick: () => apply(setWingForm(rec, side, f)),