From 3206fd57b673c871be50afceeac8acdcbf755d71 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 2 Sep 2026 13:58:22 +0000 Subject: [PATCH 1/9] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC=20=EC=A0=91=EA=B7=BC=EC=84=B1=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .Jules/palette.md | 26 +++----------------------- CHANGELOG.md | 1 + i18n.js | 20 ++++++++++++++++---- index.html | 32 ++++++++++++++++---------------- 4 files changed, 36 insertions(+), 43 deletions(-) diff --git a/.Jules/palette.md b/.Jules/palette.md index 8a7cf4c..0d50105 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -1,23 +1,3 @@ -## 2024-06-19 - Added ARIA roles to generic div containers -**Learning:** Found a recurring pattern in the app where generic `div` elements were being used with `aria-label` but lacked a specific role (e.g., `.language-switch`, `.hero-actions`). This makes screen readers announce them poorly since they don't know what kind of component the label applies to. -**Action:** When adding `aria-label` to group interactive elements in generic containers (`div` or `span`), always remember to add `role="group"` (or another appropriate role) to give screen readers proper context. - -## 2024-06-21 - Added skip-to-content link -**Learning:** Found a missing skip-to-content link, which is a key accessibility feature to help keyboard and screen reader users bypass navigation. Additionally learned that giving `
` `tabindex="-1"` and removing its outline when `:focus-visible` ensures proper focus handling after clicking the skip link without disruptive visual outlines. -**Action:** Always include a skip-to-content link near the start of the `body` and manage target focus appropriately. - -## 2026-06-25 - Fix Header Overlap -**Learning:** When using a sticky header, clicking anchor links can cause the target element to scroll under the header, hindering the user experience. -**Action:** Use `scroll-padding-top` on the `html` element with the height of the sticky header to ensure anchor links scroll to a position just below the header. - -## 2024-06-25 - Improve Color Contrast -**Learning:** Found that using `--gold` for text on white or light backgrounds (like `--paper`) fails WCAG AA contrast standards, making the text difficult to read for some users. -**Action:** Avoid using `--gold` on light backgrounds. Instead, use alternatives with better contrast like `--teal`. Retain `--gold` for dark backgrounds (like `--ink`) where it provides excellent contrast. - -## 2024-07-10 - prefers-reduced-motion 지원 추가 -**Learning:** 시스템 레벨에서 애니메이션 줄이기(prefers-reduced-motion)를 설정한 사용자를 위해 과도한 애니메이션과 부드러운 스크롤을 비활성화하는 것이 필요합니다. 이때 `0s` 대신 `0.01ms`를 사용하여 `transitionend`와 같은 브라우저 이벤트가 정상적으로 발생하도록 해야 자바스크립트 콜백이 멈추는(hanging) 문제를 방지할 수 있습니다. -**Action:** 항상 `styles.css` 하단에 `prefers-reduced-motion: reduce` 미디어 쿼리를 추가하여 모든 요소의 `animation-duration`과 `transition-duration`을 `0.01ms`로 설정하고 `scroll-behavior: auto`를 적용합니다. - -## 2024-07-15 - Expand clickable area of project cards -**Learning:** Using an anchor tag to wrap an entire card (block-level element) can result in verbose and confusing screen reader output. However, restricting the clickable area to just the title makes the UI harder to interact with (violating Fitts's Law). -**Action:** Apply `position: relative` to the card container and use a `::after` pseudo-element with `position: absolute; inset: 0;` on the title's anchor tag. This expands the clickable area to the whole card while keeping semantic and accessible HTML structure. +## 2026-09-02 - [External Link Accessibility] +**Learning:** Hardcoding `title` attributes on links in a localized site breaks dynamic language switching. The site uses a custom `i18n.js` script that manages text via data attributes. +**Action:** Always extend the custom i18n system (e.g., adding `data-i18n-title`) instead of relying on static HTML attributes when adding user-visible accessibility metadata. diff --git a/CHANGELOG.md b/CHANGELOG.md index e097a55..8c28a79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # CHANGELOG ## [Unreleased] +- **UX/접근성 개선**: 모든 외부 링크(`target="_blank"`)에 새 창 열림 안내를 제공하는 `title` 속성을 추가하고 다국어 지원(`data-i18n-title`)을 연동하여 접근성을 향상시켰습니다. (2026-09-02) - **보안 개선**: `i18n.js`에서 잘못된 언어 요청 시 `console.warn` 메시지에 사용자 입력값이 직접 포함되지 않도록 수정하여 로그 인젝션(Log Injection) 취약점을 제거했습니다. - **성능 개선**: `.skip-link` 애니메이션을 `top`에서 `transform: translateY()`로 변경하여 전환 중 레이아웃 재계산을 줄일 수 있도록 했습니다. 실제 효과는 브라우저별 측정 대상입니다. - **렌더링 힌트 정합성**: 첫 화면의 eager 이미지와 단일 LCP 후보에서 강제 `decoding="async"`를 제거해 HTML 표준의 기본 `auto` 판단에 맡기고, 지연 로드 이미지에는 비동기 디코딩 힌트를 유지했습니다. 정적 테스트가 eager, lazy, LCP 후보 집합의 존재와 조합을 검증하며, 실제 LCP 효과는 배포 후 실측 대상으로 유지합니다. diff --git a/i18n.js b/i18n.js index 00b81d3..cb81c2a 100644 --- a/i18n.js +++ b/i18n.js @@ -144,8 +144,8 @@ const messages = { "work.fourTitle": "작업 흐름", "work.fourBody": "반복 탐색은 줄이고 근거 확인과 사람의 판단은 남기는 흐름.", "footer.founded": "Founded by", - "footer.line": "Context into judgment. Judgment into action." - }, + "footer.line": "Context into judgment. Judgment into action.", + "common.newWindow": "새 창에서 열림" }, en: { metaTitle: "Contextual Wisdom Lab", metaDescription: "A research lab building AI decision support systems that connect scattered enterprise material into judgment inside concrete contexts.", @@ -291,8 +291,8 @@ const messages = { "work.fourTitle": "Agentic workflows", "work.fourBody": "Workflows that reduce repeated search while preserving evidence checks and human judgment.", "footer.founded": "Founded by", - "footer.line": "Context into judgment. Judgment into action." - } + "footer.line": "Context into judgment. Judgment into action.", + "common.newWindow": "Opens in a new window"} }; function preferredLanguage() { @@ -312,6 +312,7 @@ function preferredLanguage() { // ⚡ Bolt: Cache DOM queries and current state to prevent redundant lookups and layout thrashing let i18nNodes = null; +let i18nTitleNodes = null; let langButtons = null; let metaDesc = null; let ogDesc = null; @@ -375,6 +376,17 @@ function setLanguage(lang) { node.textContent = newText; } }); + + if (!i18nTitleNodes) { + i18nTitleNodes = document.querySelectorAll("[data-i18n-title]"); + } + + i18nTitleNodes.forEach((node) => { + const newText = dict[node.dataset.i18nTitle]; + if (newText && node.getAttribute("title") !== newText) { + node.setAttribute("title", newText); + } + }); } langButtons.forEach((button) => { diff --git a/index.html b/index.html index a2dbbd7..86d29d6 100644 --- a/index.html +++ b/index.html @@ -42,7 +42,7 @@ 프로젝트 Fork 작업 - GitHub + GitHub
@@ -59,7 +59,7 @@

맥락지혜 연구실

구슬이 서 말이어도 꿰어야 보배이듯, 문서, 메일, 로그, 회의록을 맥락 안에서 엮어 사람이 무엇을 결정하고 무엇을 실행할지 보이게 하는 AI 의사결정 지원 시스템을 연구하고 만듭니다.

@@ -254,19 +254,19 @@

참고문헌

  1. Ackoff, R. L. (1989). From data to wisdom. Journal of Applied Systems Analysis, 16(1), 3-9. - https://faculty.ung.edu/kmelton/documents/datawisdom.pdf + https://faculty.ung.edu/kmelton/documents/datawisdom.pdf
  2. Baskarada, S., & Koronios, A. (2013). Data, information, knowledge, wisdom (DIKW): A semiotic theoretical and empirical exploration of the hierarchy and its quality dimension. Australasian Journal of Information Systems, 18(1). - https://doi.org/10.3127/ajis.v18i1.748 + https://doi.org/10.3127/ajis.v18i1.748
  3. Frické, M. (2009). The knowledge pyramid: A critique of the DIKW hierarchy. Journal of Information Science, 35(2), 131-142. - https://doi.org/10.1177/0165551508094050 + https://doi.org/10.1177/0165551508094050
  4. Brienza, J. P., Kung, F. Y. H., Santos, H. C., Bobocel, D. R., & Grossmann, I. (2018). Wisdom, bias, and balance: Toward a process-sensitive measurement of wisdom-related cognition. Journal of Personality and Social Psychology, 115(6), 1093-1126. - https://doi.org/10.1037/pspp0000171 + https://doi.org/10.1037/pspp0000171
@@ -327,39 +327,39 @@

공개 프로젝트

-

Naruon

+

Naruon

메일, 첨부, 일정, 작업을 맥락으로 묶어 판단과 실행으로 연결하는 AI 이메일 워크스페이스입니다.

-

pg-erd-cloud

+

pg-erd-cloud

PostgreSQL 스키마를 리버스 엔지니어링하고 ERD와 DDL 공유 흐름으로 관리하는 클라우드 MVP입니다.

-

BandScope

+

BandScope

곡을 섹션, 역할, 템포, 연습 우선순위로 분석하는 로컬 우선 리허설 앱입니다.

-

codec-carver

+

codec-carver

긴 녹음을 메타데이터를 보존한 FLAC/Opus 조각으로 변환하는 Python CLI입니다.

-

newsdom-api

+

newsdom-api

스캔된 일본어 신문 PDF를 기사, 제목, 본문, 이미지 구조의 DOM형 JSON으로 파싱하는 API입니다.

-

scopeweave

+

scopeweave

트리 편집, 진행률 계산, CSV/JSON, 주간 Gantt를 지원하는 정적 HTML/CSS/JS WBS 플래너입니다.

-

VibeSec

+

VibeSec

바이브코딩 앱을 위한 보안 가드레일입니다. AI 개발 도구 규칙, 정적 점검, 리뷰와 수정 프롬프트를 다룹니다.

-

fast-mlsirm

+

fast-mlsirm

MLSIRM/MLS2PLM 모형의 시뮬레이션, 적합, 복원 진단을 빠르게 수행하는 Python/Rust 패키지입니다.

@@ -431,7 +431,7 @@

연구에서 제품으로

>

Founded by - Seongho Bae. + Seongho Bae. Context into judgment. Judgment into action.

From 5e5fbd1c5c6068026588dd228c883bfc9457b925 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 3 Sep 2026 01:37:06 +0000 Subject: [PATCH 2/9] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC=20=EC=A0=91=EA=B7=BC=EC=84=B1=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .Jules/palette.md | 26 +++++++++++++++++++++++++- i18n.js | 6 ++++-- test_i18n.html | 9 +++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/.Jules/palette.md b/.Jules/palette.md index 0d50105..209e617 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -1,3 +1,27 @@ -## 2026-09-02 - [External Link Accessibility] +## 2024-06-19 - Added ARIA roles to generic div containers +**Learning:** Found a recurring pattern in the app where generic `div` elements were being used with `aria-label` but lacked a specific role (e.g., `.language-switch`, `.hero-actions`). This makes screen readers announce them poorly since they don't know what kind of component the label applies to. +**Action:** When adding `aria-label` to group interactive elements in generic containers (`div` or `span`), always remember to add `role="group"` (or another appropriate role) to give screen readers proper context. + +## 2024-06-21 - Added skip-to-content link +**Learning:** Found a missing skip-to-content link, which is a key accessibility feature to help keyboard and screen reader users bypass navigation. Additionally learned that giving `
` `tabindex="-1"` and removing its outline when `:focus-visible` ensures proper focus handling after clicking the skip link without disruptive visual outlines. +**Action:** Always include a skip-to-content link near the start of the `body` and manage target focus appropriately. + +## 2026-06-25 - Fix Header Overlap +**Learning:** When using a sticky header, clicking anchor links can cause the target element to scroll under the header, hindering the user experience. +**Action:** Use `scroll-padding-top` on the `html` element with the height of the sticky header to ensure anchor links scroll to a position just below the header. + +## 2024-06-25 - Improve Color Contrast +**Learning:** Found that using `--gold` for text on white or light backgrounds (like `--paper`) fails WCAG AA contrast standards, making the text difficult to read for some users. +**Action:** Avoid using `--gold` on light backgrounds. Instead, use alternatives with better contrast like `--teal`. Retain `--gold` for dark backgrounds (like `--ink`) where it provides excellent contrast. + +## 2024-07-10 - prefers-reduced-motion 지원 추가 +**Learning:** 시스템 레벨에서 애니메이션 줄이기(prefers-reduced-motion)를 설정한 사용자를 위해 과도한 애니메이션과 부드러운 스크롤을 비활성화하는 것이 필요합니다. 이때 `0s` 대신 `0.01ms`를 사용하여 `transitionend`와 같은 브라우저 이벤트가 정상적으로 발생하도록 해야 자바스크립트 콜백이 멈추는(hanging) 문제를 방지할 수 있습니다. +**Action:** 항상 `styles.css` 하단에 `prefers-reduced-motion: reduce` 미디어 쿼리를 추가하여 모든 요소의 `animation-duration`과 `transition-duration`을 `0.01ms`로 설정하고 `scroll-behavior: auto`를 적용합니다. + +## 2024-07-15 - Expand clickable area of project cards +**Learning:** Using an anchor tag to wrap an entire card (block-level element) can result in verbose and confusing screen reader output. However, restricting the clickable area to just the title makes the UI harder to interact with (violating Fitts's Law). +**Action:** Apply `position: relative` to the card container and use a `::after` pseudo-element with `position: absolute; inset: 0;` on the title's anchor tag. This expands the clickable area to the whole card while keeping semantic and accessible HTML structure. + +## 2026-09-03 - [External Link Accessibility] **Learning:** Hardcoding `title` attributes on links in a localized site breaks dynamic language switching. The site uses a custom `i18n.js` script that manages text via data attributes. **Action:** Always extend the custom i18n system (e.g., adding `data-i18n-title`) instead of relying on static HTML attributes when adding user-visible accessibility metadata. diff --git a/i18n.js b/i18n.js index cb81c2a..a6cf851 100644 --- a/i18n.js +++ b/i18n.js @@ -145,7 +145,8 @@ const messages = { "work.fourBody": "반복 탐색은 줄이고 근거 확인과 사람의 판단은 남기는 흐름.", "footer.founded": "Founded by", "footer.line": "Context into judgment. Judgment into action.", - "common.newWindow": "새 창에서 열림" }, + "common.newWindow": "새 창에서 열림" + }, en: { metaTitle: "Contextual Wisdom Lab", metaDescription: "A research lab building AI decision support systems that connect scattered enterprise material into judgment inside concrete contexts.", @@ -292,7 +293,8 @@ const messages = { "work.fourBody": "Workflows that reduce repeated search while preserving evidence checks and human judgment.", "footer.founded": "Founded by", "footer.line": "Context into judgment. Judgment into action.", - "common.newWindow": "Opens in a new window"} + "common.newWindow": "Opens in a new window" + } }; function preferredLanguage() { diff --git a/test_i18n.html b/test_i18n.html index 2aae97d..ced1567 100644 --- a/test_i18n.html +++ b/test_i18n.html @@ -8,6 +8,8 @@
맥락지혜 연구실
+ GitHub + @@ -46,10 +48,17 @@ const titleNode = document.querySelector('[data-i18n="hero.title"]'); assertEqual(titleNode.textContent, "Contextual Wisdom Lab", "Title text should change to English"); + + // Test title update + const linkNode = document.querySelector('[data-i18n-title="common.newWindow"]'); + assertEqual(linkNode.getAttribute("title"), "Opens in a new window", "Title attribute should change to English"); + // Test 3: Switch back to KO updates nodes correctly setLanguage("ko"); assertEqual(currentLang, "ko", "Language should be 'ko' after setting back"); + assertEqual(titleNode.textContent, "맥락지혜 연구실", "Title text back to Korean"); + assertEqual(linkNode.getAttribute("title"), "새 창에서 열림", "Title attribute back to Korean"); // Test 4: Sentinel Security - Input Validation for untrusted inputs setLanguage("__proto__"); From 6c364b8c750f5111161d81779e5f907f98ff7d9f Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 3 Sep 2026 14:15:34 +0000 Subject: [PATCH 3/9] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC=20=EC=A0=91=EA=B7=BC=EC=84=B1=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From dfe5a2cf0ba52b0d0f6f92d989f9ecfc4c362083 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 4 Sep 2026 05:00:50 +0000 Subject: [PATCH 4/9] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC=20=EC=A0=91=EA=B7=BC=EC=84=B1=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From d72897628bee1da73c0ed1cdd63ffa8500b75e9e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 14:13:04 +0900 Subject: [PATCH 5/9] test(a11y): require non-title new-window warning --- test_i18n.html | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/test_i18n.html b/test_i18n.html index ced1567..e5c0524 100644 --- a/test_i18n.html +++ b/test_i18n.html @@ -37,7 +37,7 @@ } } - requestAnimationFrame(() => { + requestAnimationFrame(async () => { console.log("Running tests..."); assertEqual(currentLang, "ko", "Initial language should be 'ko'"); @@ -48,18 +48,34 @@ const titleNode = document.querySelector('[data-i18n="hero.title"]'); assertEqual(titleNode.textContent, "Contextual Wisdom Lab", "Title text should change to English"); - - // Test title update + // Tooltip localization is supplemental; it is not the accessible warning contract. const linkNode = document.querySelector('[data-i18n-title="common.newWindow"]'); assertEqual(linkNode.getAttribute("title"), "Opens in a new window", "Title attribute should change to English"); // Test 3: Switch back to KO updates nodes correctly setLanguage("ko"); assertEqual(currentLang, "ko", "Language should be 'ko' after setting back"); - assertEqual(titleNode.textContent, "맥락지혜 연구실", "Title text back to Korean"); assertEqual(linkNode.getAttribute("title"), "새 창에서 열림", "Title attribute back to Korean"); + // External links need a localized non-title warning that keyboard/touch/AT users can reach. + const response = await fetch("index.html", { cache: "no-store" }); + const pageText = await response.text(); + const page = new DOMParser().parseFromString(pageText, "text/html"); + const externalLinks = Array.from(page.querySelectorAll('a[target="_blank"]')); + const allLinksDescribeNewWindow = externalLinks.length > 0 && externalLinks.every((link) => { + const ids = (link.getAttribute("aria-describedby") || "").trim().split(/\s+/).filter(Boolean); + return ids.some((id) => { + const description = page.getElementById(id); + return description && description.getAttribute("data-i18n") === "common.newWindow"; + }); + }); + assertEqual( + allLinksDescribeNewWindow, + true, + "Every target=_blank link should reference a localized non-title new-window description" + ); + // Test 4: Sentinel Security - Input Validation for untrusted inputs setLanguage("__proto__"); assertEqual(currentLang, "ko", "Language should safely fallback to 'ko' on invalid input"); From 88ede142e8ab8d9aee9d451379a8127cdcb7c1af Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 14:13:18 +0900 Subject: [PATCH 6/9] docs(a11y): bound external-link warning guidance --- .Jules/palette.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.Jules/palette.md b/.Jules/palette.md index 209e617..6a6ae16 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -11,7 +11,7 @@ **Action:** Use `scroll-padding-top` on the `html` element with the height of the sticky header to ensure anchor links scroll to a position just below the header. ## 2024-06-25 - Improve Color Contrast -**Learning:** Found that using `--gold` for text on white or light backgrounds (like `--paper`) fails WCAG AA contrast standards, making the text difficult to read for some users. +**Learning:** Found that using `--gold` for text on white or light backgrounds (like `--paper`) fails WCAC AA contrast standards, making the text difficult to read for some users. **Action:** Avoid using `--gold` on light backgrounds. Instead, use alternatives with better contrast like `--teal`. Retain `--gold` for dark backgrounds (like `--ink`) where it provides excellent contrast. ## 2024-07-10 - prefers-reduced-motion 지원 추가 @@ -22,6 +22,6 @@ **Learning:** Using an anchor tag to wrap an entire card (block-level element) can result in verbose and confusing screen reader output. However, restricting the clickable area to just the title makes the UI harder to interact with (violating Fitts's Law). **Action:** Apply `position: relative` to the card container and use a `::after` pseudo-element with `position: absolute; inset: 0;` on the title's anchor tag. This expands the clickable area to the whole card while keeping semantic and accessible HTML structure. -## 2026-09-03 - [External Link Accessibility] -**Learning:** Hardcoding `title` attributes on links in a localized site breaks dynamic language switching. The site uses a custom `i18n.js` script that manages text via data attributes. -**Action:** Always extend the custom i18n system (e.g., adding `data-i18n-title`) instead of relying on static HTML attributes when adding user-visible accessibility metadata. +## 2026-09-03 - External link new-window warning +**Learning:** Localizing a `title` tooltip is useful supplemental metadata, but it is not a dependable advance warning for keyboard, touch, or assistive-technology users. W3C's current guidance treats new-window warnings as advisory good practice and notes that `title` is poorly discoverable without pointer hover. +**Action:** When this site keeps `target="_blank"`, provide the localized new-window notice through ordinary accessible link semantics (for example, referenced descriptive text) and treat `title` as supplemental only. Verify both KO/EN switching and browser keyboard/touch/accessibility behavior before claiming completion. From 6339d4febfdf55c0dba0832f7b0b0cd1ce1a268d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 14:13:35 +0900 Subject: [PATCH 7/9] docs(a11y): correct external-link journal wording --- .Jules/palette.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.Jules/palette.md b/.Jules/palette.md index 6a6ae16..d133a28 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -11,7 +11,7 @@ **Action:** Use `scroll-padding-top` on the `html` element with the height of the sticky header to ensure anchor links scroll to a position just below the header. ## 2024-06-25 - Improve Color Contrast -**Learning:** Found that using `--gold` for text on white or light backgrounds (like `--paper`) fails WCAC AA contrast standards, making the text difficult to read for some users. +**Learning:** Found that using `--teal text`? No; using `--gold` for text on white or light backgrounds (like `--paper`) fails WCAG AA contrast standards, making the text difficult to read for some users. **Action:** Avoid using `--gold` on light backgrounds. Instead, use alternatives with better contrast like `--teal`. Retain `--gold` for dark backgrounds (like `--ink`) where it provides excellent contrast. ## 2024-07-10 - prefers-reduced-motion 지원 추가 From 39a055ed6e5b358f5795ec18eb25244185898c25 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 14:13:59 +0900 Subject: [PATCH 8/9] docs(a11y): restore color-contrast journal wording --- .Jules/palette.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.Jules/palette.md b/.Jules/palette.md index d133a28..b488c98 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -11,7 +11,7 @@ **Action:** Use `scroll-padding-top` on the `html` element with the height of the sticky header to ensure anchor links scroll to a position just below the header. ## 2024-06-25 - Improve Color Contrast -**Learning:** Found that using `--teal text`? No; using `--gold` for text on white or light backgrounds (like `--paper`) fails WCAG AA contrast standards, making the text difficult to read for some users. +**Learning:** Found that using `--gold` for text on white or light backgrounds (like `--paper`) fails WCAG AA contrast standards, making the text difficult to read for some users. **Action:** Avoid using `--gold` on light backgrounds. Instead, use alternatives with better contrast like `--teal`. Retain `--gold` for dark backgrounds (like `--ink`) where it provides excellent contrast. ## 2024-07-10 - prefers-reduced-motion 지원 추가 From f4df0a3f04334fd7654b11d19aa22e26b971ba9b Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 4 Sep 2026 05:35:01 +0000 Subject: [PATCH 9/9] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC=20=EC=A0=91=EA=B7=BC=EC=84=B1=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- i18n.js | 10 ---------- index.html | 33 +++++++++++++++++---------------- styles.css | 13 +++++++++++++ test_i18n.html | 10 +++++----- 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c28a79..231d17c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # CHANGELOG ## [Unreleased] -- **UX/접근성 개선**: 모든 외부 링크(`target="_blank"`)에 새 창 열림 안내를 제공하는 `title` 속성을 추가하고 다국어 지원(`data-i18n-title`)을 연동하여 접근성을 향상시켰습니다. (2026-09-02) +- **UX/접근성 개선**: 모든 외부 링크(`target="_blank"`)에 새 창 열림 사전 경고를 안내하는 visually hidden 설명을 `aria-describedby`로 연결하여 접근성을 향상시켰습니다. (2026-09-04) - **보안 개선**: `i18n.js`에서 잘못된 언어 요청 시 `console.warn` 메시지에 사용자 입력값이 직접 포함되지 않도록 수정하여 로그 인젝션(Log Injection) 취약점을 제거했습니다. - **성능 개선**: `.skip-link` 애니메이션을 `top`에서 `transform: translateY()`로 변경하여 전환 중 레이아웃 재계산을 줄일 수 있도록 했습니다. 실제 효과는 브라우저별 측정 대상입니다. - **렌더링 힌트 정합성**: 첫 화면의 eager 이미지와 단일 LCP 후보에서 강제 `decoding="async"`를 제거해 HTML 표준의 기본 `auto` 판단에 맡기고, 지연 로드 이미지에는 비동기 디코딩 힌트를 유지했습니다. 정적 테스트가 eager, lazy, LCP 후보 집합의 존재와 조합을 검증하며, 실제 LCP 효과는 배포 후 실측 대상으로 유지합니다. diff --git a/i18n.js b/i18n.js index a6cf851..c23bdff 100644 --- a/i18n.js +++ b/i18n.js @@ -314,7 +314,6 @@ function preferredLanguage() { // ⚡ Bolt: Cache DOM queries and current state to prevent redundant lookups and layout thrashing let i18nNodes = null; -let i18nTitleNodes = null; let langButtons = null; let metaDesc = null; let ogDesc = null; @@ -379,16 +378,7 @@ function setLanguage(lang) { } }); - if (!i18nTitleNodes) { - i18nTitleNodes = document.querySelectorAll("[data-i18n-title]"); - } - i18nTitleNodes.forEach((node) => { - const newText = dict[node.dataset.i18nTitle]; - if (newText && node.getAttribute("title") !== newText) { - node.setAttribute("title", newText); - } - }); } langButtons.forEach((button) => { diff --git a/index.html b/index.html index 86d29d6..b608c99 100644 --- a/index.html +++ b/index.html @@ -42,7 +42,7 @@ 프로젝트 Fork 작업 - GitHub + GitHub
@@ -59,7 +59,7 @@

맥락지혜 연구실

구슬이 서 말이어도 꿰어야 보배이듯, 문서, 메일, 로그, 회의록을 맥락 안에서 엮어 사람이 무엇을 결정하고 무엇을 실행할지 보이게 하는 AI 의사결정 지원 시스템을 연구하고 만듭니다.

@@ -254,19 +254,19 @@

참고문헌

  1. Ackoff, R. L. (1989). From data to wisdom. Journal of Applied Systems Analysis, 16(1), 3-9. - https://faculty.ung.edu/kmelton/documents/datawisdom.pdf + https://faculty.ung.edu/kmelton/documents/datawisdom.pdf
  2. Baskarada, S., & Koronios, A. (2013). Data, information, knowledge, wisdom (DIKW): A semiotic theoretical and empirical exploration of the hierarchy and its quality dimension. Australasian Journal of Information Systems, 18(1). - https://doi.org/10.3127/ajis.v18i1.748 + https://doi.org/10.3127/ajis.v18i1.748
  3. Frické, M. (2009). The knowledge pyramid: A critique of the DIKW hierarchy. Journal of Information Science, 35(2), 131-142. - https://doi.org/10.1177/0165551508094050 + https://doi.org/10.1177/0165551508094050
  4. Brienza, J. P., Kung, F. Y. H., Santos, H. C., Bobocel, D. R., & Grossmann, I. (2018). Wisdom, bias, and balance: Toward a process-sensitive measurement of wisdom-related cognition. Journal of Personality and Social Psychology, 115(6), 1093-1126. - https://doi.org/10.1037/pspp0000171 + https://doi.org/10.1037/pspp0000171
@@ -327,39 +327,39 @@

공개 프로젝트

-

Naruon

+

Naruon

메일, 첨부, 일정, 작업을 맥락으로 묶어 판단과 실행으로 연결하는 AI 이메일 워크스페이스입니다.

-

pg-erd-cloud

+

pg-erd-cloud

PostgreSQL 스키마를 리버스 엔지니어링하고 ERD와 DDL 공유 흐름으로 관리하는 클라우드 MVP입니다.

-

BandScope

+

BandScope

곡을 섹션, 역할, 템포, 연습 우선순위로 분석하는 로컬 우선 리허설 앱입니다.

-

codec-carver

+

codec-carver

긴 녹음을 메타데이터를 보존한 FLAC/Opus 조각으로 변환하는 Python CLI입니다.

-

newsdom-api

+

newsdom-api

스캔된 일본어 신문 PDF를 기사, 제목, 본문, 이미지 구조의 DOM형 JSON으로 파싱하는 API입니다.

-

scopeweave

+

scopeweave

트리 편집, 진행률 계산, CSV/JSON, 주간 Gantt를 지원하는 정적 HTML/CSS/JS WBS 플래너입니다.

-

VibeSec

+

VibeSec

바이브코딩 앱을 위한 보안 가드레일입니다. AI 개발 도구 규칙, 정적 점검, 리뷰와 수정 프롬프트를 다룹니다.

-

fast-mlsirm

+

fast-mlsirm

MLSIRM/MLS2PLM 모형의 시뮬레이션, 적합, 복원 진단을 빠르게 수행하는 Python/Rust 패키지입니다.

@@ -431,9 +431,10 @@

연구에서 제품으로

>

Founded by - Seongho Bae. + Seongho Bae. Context into judgment. Judgment into action.

+ 새 창에서 열림 diff --git a/styles.css b/styles.css index f7697d8..416189d 100644 --- a/styles.css +++ b/styles.css @@ -845,3 +845,16 @@ main:focus-visible { scroll-behavior: auto !important; } } + +/* ⚡ Bolt: Visually hidden utility for accessible semantics */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} diff --git a/test_i18n.html b/test_i18n.html index e5c0524..dd2b05d 100644 --- a/test_i18n.html +++ b/test_i18n.html @@ -8,7 +8,8 @@
맥락지혜 연구실
- GitHub + GitHub + 새 창에서 열림 @@ -48,15 +49,14 @@ const titleNode = document.querySelector('[data-i18n="hero.title"]'); assertEqual(titleNode.textContent, "Contextual Wisdom Lab", "Title text should change to English"); - // Tooltip localization is supplemental; it is not the accessible warning contract. - const linkNode = document.querySelector('[data-i18n-title="common.newWindow"]'); - assertEqual(linkNode.getAttribute("title"), "Opens in a new window", "Title attribute should change to English"); + const descNode = document.getElementById("new-window-desc"); + assertEqual(descNode.textContent, "Opens in a new window", "Description text should change to English"); // Test 3: Switch back to KO updates nodes correctly setLanguage("ko"); assertEqual(currentLang, "ko", "Language should be 'ko' after setting back"); assertEqual(titleNode.textContent, "맥락지혜 연구실", "Title text back to Korean"); - assertEqual(linkNode.getAttribute("title"), "새 창에서 열림", "Title attribute back to Korean"); + assertEqual(descNode.textContent, "새 창에서 열림", "Description text back to Korean"); // External links need a localized non-title warning that keyboard/touch/AT users can reach. const response = await fetch("index.html", { cache: "no-store" });