From b2186e4aacbc22a00d21f66cbcf82cb7cf1eea58 Mon Sep 17 00:00:00 2001 From: bam Date: Tue, 25 Aug 2026 12:48:42 +0900 Subject: [PATCH 1/2] =?UTF-8?q?style:=20=EA=B5=90=EC=95=88=20=ED=91=9C?= =?UTF-8?q?=EC=9D=98=20=EC=8B=9C=EA=B0=81=EC=A0=81=20=EA=B5=AC=EB=B6=84=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- styles/app.css | 27 ++++++++++++++++++++------- tests/accessibility.test.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/styles/app.css b/styles/app.css index 9551927..8fa5c3c 100644 --- a/styles/app.css +++ b/styles/app.css @@ -900,33 +900,46 @@ a.language-nav-link:hover { max-width: 100%; margin: 20px 0 26px; overflow-x: auto; - border: 1px solid var(--color-border); + border: 1px solid var(--color-border-strong); border-radius: var(--radius-md); + background: rgba(15, 22, 41, 0.55); +} + +.table-scroll:focus-visible { + border-color: var(--color-primary-strong); } .lesson-body table { width: 100%; min-width: 520px; - border-collapse: collapse; - background: rgba(15, 22, 41, 0.55); + border-collapse: separate; + border-spacing: 0; font-size: 13px; } .lesson-body th, .lesson-body td { - padding: 11px 14px; + padding: 13px 16px; + border-right: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border); text-align: left; vertical-align: top; } .lesson-body th { - background: var(--color-surface); + border-bottom-color: var(--color-border-strong); + background: var(--color-secondary); color: var(--color-text); - font-size: 11px; + font-size: 12px; + font-weight: 800; + letter-spacing: 0.02em; +} + +.lesson-body tr > :last-child { + border-right: 0; } -.lesson-body tr:last-child td { +.lesson-body tbody tr:last-child td { border-bottom: 0; } diff --git a/tests/accessibility.test.js b/tests/accessibility.test.js index f73456f..98ece8a 100644 --- a/tests/accessibility.test.js +++ b/tests/accessibility.test.js @@ -8,6 +8,7 @@ import { renderCodeQuestView, } from "../src/ui/code-quest-view.js"; import { renderCodingTestNavigationLink } from "../src/ui/coding-test-view.js"; +import { renderMarkdown } from "../src/ui/markdown.js"; import { renderMyPageView } from "../src/ui/my-page-view.js"; function relativeLuminance(hex) { @@ -47,6 +48,35 @@ test("긴 교안 제목과 인라인 코드가 320px 문서 폭을 늘리지 않 assert.match(inlineCodeRule[1], /background:\s*var\(--color-surface-raised\)/); }); +test("교안 표는 명확한 셀 경계와 포커스 가능한 내부 가로 스크롤을 유지한다", async () => { + const css = await readFile(new URL("../styles/app.css", import.meta.url), "utf8"); + const tokens = await readFile(new URL("../styles/tokens.css", import.meta.url), "utf8"); + const renderedTable = renderMarkdown("| A | B | C | D |\n| --- | --- | --- | --- |\n| 1 | 2 | 3 | 4 |"); + const wrapperRule = css.match(/\.table-scroll\s*\{([^}]*)\}/)?.[1] ?? ""; + const tableRule = css.match(/\.lesson-body table\s*\{([^}]*)\}/)?.[1] ?? ""; + const cellRule = css.match(/\.lesson-body th,\s*\.lesson-body td\s*\{([^}]*)\}/)?.[1] ?? ""; + const headerRule = css.match(/\.lesson-body th\s*\{([^}]*)\}/)?.[1] ?? ""; + const headerBackground = tokens.match(/--color-secondary:\s*(#[\da-f]{6})\s*;/i)?.[1]; + const headerText = tokens.match(/--color-text:\s*(#[\da-f]{6})\s*;/i)?.[1]; + + assert.match(renderedTable, /
/); + assert.equal(renderedTable.match(/
/g)?.length, 4); + assert.equal(renderedTable.match(//g)?.length, 4); + assert.match(wrapperRule, /max-width:\s*100%/); + assert.match(wrapperRule, /overflow-x:\s*auto/); + assert.match(wrapperRule, /border:\s*1px solid var\(--color-border-strong\)/); + assert.match(css, /\.table-scroll:focus-visible\s*\{[^}]*border-color:\s*var\(--color-primary-strong\)/s); + assert.match(tableRule, /min-width:\s*520px/); + assert.match(tableRule, /border-collapse:\s*separate/); + assert.match(cellRule, /border-right:\s*1px solid var\(--color-border\)/); + assert.match(cellRule, /border-bottom:\s*1px solid var\(--color-border\)/); + assert.match(headerRule, /background:\s*var\(--color-secondary\)/); + assert.match(headerRule, /font-weight:\s*800/); + assert.ok(headerBackground); + assert.ok(headerText); + assert.ok(contrastRatio(headerText, headerBackground) >= 4.5); +}); + test("인라인 코드는 참고 UI의 byte 톤을 쓰고 오류 제목은 물결 밑줄로 구분한다", async () => { const css = await readFile(new URL("../styles/app.css", import.meta.url), "utf8"); const tokens = await readFile(new URL("../styles/tokens.css", import.meta.url), "utf8"); From f8990765212b9aebf981b9b4e218bec1a957f4d7 Mon Sep 17 00:00:00 2001 From: bam Date: Tue, 25 Aug 2026 12:57:50 +0900 Subject: [PATCH 2/2] =?UTF-8?q?test:=20=EA=B5=90=EC=95=88=20=ED=91=9C=20?= =?UTF-8?q?=EB=81=9D=20=EA=B2=BD=EA=B3=84=20=ED=9A=8C=EA=B7=80=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/accessibility.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/accessibility.test.js b/tests/accessibility.test.js index 98ece8a..12a18f0 100644 --- a/tests/accessibility.test.js +++ b/tests/accessibility.test.js @@ -68,10 +68,13 @@ test("교안 표는 명확한 셀 경계와 포커스 가능한 내부 가로 assert.match(css, /\.table-scroll:focus-visible\s*\{[^}]*border-color:\s*var\(--color-primary-strong\)/s); assert.match(tableRule, /min-width:\s*520px/); assert.match(tableRule, /border-collapse:\s*separate/); + assert.match(tableRule, /border-spacing:\s*0/); assert.match(cellRule, /border-right:\s*1px solid var\(--color-border\)/); assert.match(cellRule, /border-bottom:\s*1px solid var\(--color-border\)/); assert.match(headerRule, /background:\s*var\(--color-secondary\)/); assert.match(headerRule, /font-weight:\s*800/); + assert.match(css, /\.lesson-body tr > :last-child\s*\{[^}]*border-right:\s*0/s); + assert.match(css, /\.lesson-body tbody tr:last-child td\s*\{[^}]*border-bottom:\s*0/s); assert.ok(headerBackground); assert.ok(headerText); assert.ok(contrastRatio(headerText, headerBackground) >= 4.5);