From b2e2fcff91707937e59f5f1583ec9864dacc041d Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 28 Sep 2026 09:45:50 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix(spreadsheet):=20=EC=97=91=EC=85=80=20?= =?UTF-8?q?=EB=B6=99=EC=97=AC=EB=84=A3=EA=B8=B0=20=EC=84=9C=EC=8B=9D=20?= =?UTF-8?q?=E2=80=94=20=EB=AC=B6=EC=9D=8C=20=EC=84=A0=ED=83=9D=EC=9E=90=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=C2=B7=20=EC=84=A0=20=EA=B5=B5?= =?UTF-8?q?=EA=B8=B0=EB=B3=84=20=EC=A2=85=EB=A5=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ` 안 `.xl65 {...}` 짜임(엑셀이 인라인 대신 클래스로 서식을 실을 때) → 클래스별 선언. */ +/** `` 안 `.xl65 {...}` · `.xl65, .xl70 {...}`(묶음 선택자) 짜임(엑셀이 인라인 대신 + * 클래스로 서식을 실을 때) → 클래스별 선언(같은 클래스가 여러 규칙에 나오면 뒤엣것이 이김). */ function parseClassRules(doc: Document): Record> { const css = Array.from(doc.querySelectorAll("style")) .map((s) => s.textContent ?? "") .join("\n"); const rules: Record> = {}; - for (const m of css.matchAll(/\.([a-zA-Z0-9_-]+)\s*\{([^}]*)\}/g)) { - rules[m[1]] = parseStyleAttr(m[2]); + for (const m of css.matchAll(/([^{}]+)\{([^}]*)\}/g)) { + const decls = parseStyleAttr(m[2]); + for (const selectorPart of m[1].split(",")) { + const cls = /\.([a-zA-Z0-9_-]+)\s*$/.exec(selectorPart.trim()); + if (cls) Object.assign((rules[cls[1]] ??= {}), decls); + } } return rules; } diff --git a/resources/tester/spreadsheet/fixture_excel_style_paste.html b/resources/tester/spreadsheet/fixture_excel_style_paste.html new file mode 100644 index 00000000..139c4167 --- /dev/null +++ b/resources/tester/spreadsheet/fixture_excel_style_paste.html @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
품목수량금액
터파기1201200000
메우기80800000
합계2002000000
+ + + From 4f7470bbbd2254eadbf08ac40efbc0de415ce9f5 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 28 Sep 2026 09:48:20 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat(spreadsheet):=20C=20=EA=B2=A9=EC=9E=90?= =?UTF-8?q?=20=E2=80=94=20=EC=95=B1=20=EB=B0=9D=EC=9D=80=20=C2=B7=20?= =?UTF-8?q?=EC=96=B4=EB=91=90=EC=9A=B4=20=ED=85=8C=EB=A7=88=20=EB=94=B0?= =?UTF-8?q?=EB=9D=BC=EA=B0=80=EA=B2=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .aislo-grid 안 색 변수(--aislo-grid-bg · -fg · -line · -head-bg · -head-fg · -head-border · -selected) 를 전부 앱 전역 토큰(ui_template_theme.css 의 --color-surface-raised · -text-body · -border · -surface · -text-secondary · -accent)에 연결 — 새 값 안 적음, 앱이 data-theme 를 바꾸면 그대로 따라감(다른 스프레드시트 파일(spreadsheet_toolbar.css)과 같은 방식). 칸 · 머리 배경 · 눈금선 · 선택 테두리 · 채우기 손잡이 테두리의 하드코딩 흰색 · 회색 · 파랑을 이 변수로 바꿈. 테두리 기본 색(사용자가 색 안 지정)은 #000000 대신 currentColor 로 — 칸 글자색과 같이 테마를 따라감. 사용자가 지정한 채움색 · 글자색(조건부 서식 포함)은 그대로 둠 (엑셀과 같음 — 이미 빈 문자열 인라인 스타일로 CSS 기본값에 떨어지는 구조라 따로 안 고침). 시험 틀(html)에 ui_template_theme.css 를 넣어 data-theme 전환을 실제로 시험. ORCA 수치(시험 틀 · data-theme 전환) — 밝은: 격자 배경 rgb(255,255,255) · 글자 rgb(51,51,51) · 선택 #3e0079 · 눈금선 #e6e2e3. 어두운: 격자 배경 rgb(37,31,56) · 글자 rgb(228,224,240) · 선택 #b99aff · 눈금선 #322a45 — 모두 전환됨. 사용자 지정 채움(A3 #F2F2F2)·조건부 서식 글자색(H4 #c00000)은 두 테마에서 값 그대로(안 바뀜) 확인. A3 무색 테두리는 currentColor 로 밝은 rgb(51,51,51)/어두운 rgb(228,224,240) 로 글자색과 같이 바뀜 확인. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01VVM3xZ1aUPcUTuW2WZSnwg --- .../spreadsheet/spreadsheet_cellstyle.ts | 2 +- A00_Common/spreadsheet/spreadsheet_grid.css | 25 +++++++++++-------- A00_Common/spreadsheet/spreadsheet_grid.ts | 2 +- .../spreadsheet/spreadsheet_grid_test.html | 3 ++- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/A00_Common/spreadsheet/spreadsheet_cellstyle.ts b/A00_Common/spreadsheet/spreadsheet_cellstyle.ts index 4ba194bb..842bca41 100644 --- a/A00_Common/spreadsheet/spreadsheet_cellstyle.ts +++ b/A00_Common/spreadsheet/spreadsheet_cellstyle.ts @@ -94,7 +94,7 @@ export function resolveBoxBorders( /** 빈 글 = 인라인 테두리를 안 그림(css `aislo-grid--gridlines` 눈금선이 비쳐 보임). `scale` = 확대 · 축소 배율(선 굵기도 같이). */ function borderCss(side: BorderSide | undefined, scale: number): string { if (!side) return ""; - const color = side.색 ?? "#000000"; + const color = side.색 ?? "currentColor"; const w = (px: number): number => Math.max(1, Math.round(px * scale)); switch (side.선) { case "hair": diff --git a/A00_Common/spreadsheet/spreadsheet_grid.css b/A00_Common/spreadsheet/spreadsheet_grid.css index 9998e5b2..9dd2d789 100644 --- a/A00_Common/spreadsheet/spreadsheet_grid.css +++ b/A00_Common/spreadsheet/spreadsheet_grid.css @@ -4,12 +4,16 @@ * ========================================================================== */ .aislo-grid { - --aislo-grid-line: #d9d9d9; - --aislo-grid-head-bg: #f3f3f3; - --aislo-grid-head-fg: #444; - --aislo-grid-head-border: #cfcfcf; + /* 앱 전역 테마 토큰(ui_template_theme.css · :root[data-theme])을 그대로 물려받음 — + * 여기서 값을 다시 안 적음(다크 전환 시 앱 토큰이 바뀌면 같이 바뀜). */ + --aislo-grid-bg: var(--color-surface-raised); + --aislo-grid-fg: var(--color-text-body); + --aislo-grid-line: var(--color-border); + --aislo-grid-head-bg: var(--color-surface); + --aislo-grid-head-fg: var(--color-text-secondary); + --aislo-grid-head-border: var(--color-border); --aislo-grid-freeze-shadow: rgba(0, 0, 0, 0.12); - --aislo-grid-selected: #1a73e8; + --aislo-grid-selected: var(--color-accent); position: relative; overflow: hidden; @@ -18,7 +22,8 @@ font: 10pt "굴림", sans-serif; - background: #fff; + background: var(--aislo-grid-bg); + color: var(--aislo-grid-fg); user-select: none; -webkit-user-select: none; } @@ -94,7 +99,7 @@ .aislo-grid__colhead--hidden-before, .aislo-grid__rowhead--hidden-before { - border-left: 3px double #888; + border-left: 3px double var(--aislo-grid-head-fg); } .aislo-grid__head-label { @@ -122,7 +127,7 @@ box-sizing: border-box; padding: 0; border: 1px solid var(--aislo-grid-head-border); - background: #fff; + background: var(--aislo-grid-head-bg); color: var(--aislo-grid-head-fg); font-size: 0.7em; line-height: 1; @@ -160,7 +165,7 @@ flex-direction: column; overflow: hidden; padding: 0 2px; - background: #fff; + background: var(--aislo-grid-bg); cursor: cell; } @@ -228,7 +233,7 @@ width: 6px; height: 6px; background: var(--aislo-grid-selected); - border: 1px solid #fff; + border: 1px solid var(--aislo-grid-bg); cursor: crosshair; z-index: 3; } diff --git a/A00_Common/spreadsheet/spreadsheet_grid.ts b/A00_Common/spreadsheet/spreadsheet_grid.ts index 23dc5c68..e17fd02d 100644 --- a/A00_Common/spreadsheet/spreadsheet_grid.ts +++ b/A00_Common/spreadsheet/spreadsheet_grid.ts @@ -815,7 +815,7 @@ export function createGrid(ctx: SpreadsheetContext): GridHandle { node.style.top = `${screen.y}px`; node.style.width = `${screen.w}px`; node.style.height = `${screen.h}px`; - node.style.borderColor = "#1a73e8"; + node.style.borderColor = "var(--aislo-grid-selected)"; node.style.borderWidth = i === 0 ? "2px" : "1px"; selLayer!.append(node); } diff --git a/resources/tester/spreadsheet/spreadsheet_grid_test.html b/resources/tester/spreadsheet/spreadsheet_grid_test.html index f393d1d4..4d3a65df 100644 --- a/resources/tester/spreadsheet/spreadsheet_grid_test.html +++ b/resources/tester/spreadsheet/spreadsheet_grid_test.html @@ -1,8 +1,9 @@ - + C 격자 시험 틀 +