Skip to content
Open
4 changes: 4 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@
## 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-08-28 - ์™ธ๋ถ€ ๋งํฌ์— ๋Œ€ํ•œ ๋‹ค๊ตญ์–ด ํˆดํŒ ์ถ”๊ฐ€
**Learning:** ์™ธ๋ถ€ ๋งํฌ(target="_blank")๋Š” ์‹œ๊ฐ์ ์œผ๋กœ ํ™”์‚ดํ‘œ ๋“ฑ์œผ๋กœ ํ‘œ์‹œ๋˜์ง€ ์•Š๊ฑฐ๋‚˜ ์Šคํฌ๋ฆฐ ๋ฆฌ๋” ์‚ฌ์šฉ์ž๊ฐ€ ์ปจํ…์ŠคํŠธ๋ฅผ ์žƒ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. HTML์˜ `title` ์†์„ฑ์„ ํ™œ์šฉํ•˜์—ฌ ์™ธ๋ถ€ ๋งํฌ์ž„์„ ๋ช…์‹œ์ ์œผ๋กœ ์•ˆ๋‚ดํ•˜๋ฉด ์ ‘๊ทผ์„ฑ๊ณผ ์‚ฌ์šฉ์„ฑ์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ๋‹ค๊ตญ์–ด ์‚ฌ์ดํŠธ์˜ ๊ฒฝ์šฐ `title` ์†์„ฑ ๋˜ํ•œ ๋™์ ์œผ๋กœ ๋ฒˆ์—ญ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
**Action:** ์™ธ๋ถ€ ์ฐฝ์—์„œ ์—ด๋ฆฌ๋Š” ๋งํฌ์—๋Š” ํ•ญ์ƒ ๋ช…ํ™•ํ•œ ์•ˆ๋‚ด ํˆดํŒ(`title`)์„ ์ œ๊ณตํ•˜๊ณ , ๋‹ค๊ตญ์–ด ์ง€์› ์Šคํฌ๋ฆฝํŠธ์—์„œ ์†์„ฑ ๋ฒˆ์—ญ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•˜์—ฌ ์ผ๊ด€๋œ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
18 changes: 14 additions & 4 deletions i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const messages = {
metaDescription: "๋งฅ๋ฝ์ง€ํ˜œ ์—ฐ๊ตฌ์‹ค์€ ํฉ์–ด์ง„ ๊ธฐ์—… ์ž๋ฃŒ๋ฅผ ๋งฅ๋ฝ ์•ˆ์—์„œ ํŒ๋‹จ ๊ฐ€๋Šฅํ•œ ๊ตฌ์กฐ๋กœ ๋ฐ”๊พธ๋Š” AI ์˜์‚ฌ๊ฒฐ์ • ์ง€์› ์‹œ์Šคํ…œ์„ ์—ฐ๊ตฌํ•˜๊ณ  ๋งŒ๋“ญ๋‹ˆ๋‹ค.",
logoSrc: "assets/context-wisdom-lab-logo.svg",
logoAlt: "๋งฅ๋ฝ์ง€ํ˜œ ์—ฐ๊ตฌ์‹ค ยท Contextual Wisdom Lab",
"common.newTab": "์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐ŸŸก User-facing change missing CHANGELOG entry

This PR adds a user-facing feature (translated title tooltips on external links) via the new common.newTab key but leaves CHANGELOG.md untouched. The repository convention requires a Korean entry under [Unreleased] for every user-facing change.

Prompt for agents
The repository convention (CLAUDE.md) requires CHANGELOG.md to be updated in Korean under the [Unreleased] section for any user-facing change. This PR introduces user-visible translated tooltips (title attribute) on external links via the new common.newTab i18n key, but CHANGELOG.md was not updated. Add a Korean [Unreleased] entry to CHANGELOG.md describing the addition of multilingual external-link tooltips.
Devin Review

Was this helpful? React with ๐Ÿ‘ or ๐Ÿ‘Ž to provide feedback.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿ“ Info: Tooltip wording: window vs tab

The Korean common.newTab reads '์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ' (new window) while the English reads 'Opens in new tab'. Harmless wording mismatch between locales.

Devin Review

Was this helpful? React with ๐Ÿ‘ or ๐Ÿ‘Ž to provide feedback.

"nav.intro": "์†Œ๊ฐœ",
"nav.problem": "๋ฌธ์ œ์˜์‹",
"nav.model": "์—ฐ๊ตฌ๋ชจํ˜•",
Expand Down Expand Up @@ -151,6 +152,7 @@ const messages = {
metaDescription: "A research lab building AI decision support systems that connect scattered enterprise material into judgment inside concrete contexts.",
logoSrc: "assets/context-wisdom-lab-logo-en.svg",
logoAlt: "Contextual Wisdom Lab",
"common.newTab": "Opens in new tab",
"nav.intro": "Intro",
"nav.problem": "Problem",
"nav.model": "Research Model",
Expand Down Expand Up @@ -365,14 +367,22 @@ function setLanguage(lang) {

if (!isInitialDefault) {
if (!i18nNodes) {
i18nNodes = document.querySelectorAll("[data-i18n]");
i18nNodes = document.querySelectorAll("[data-i18n], [data-i18n-title]");
}

// Only update textContent if it actually changed to avoid layout recalculations
i18nNodes.forEach((node) => {
const newText = dict[node.dataset.i18n];
if (newText && node.textContent !== newText) {
node.textContent = newText;
if (node.hasAttribute("data-i18n")) {
const newText = dict[node.dataset.i18n];
if (newText && node.textContent !== newText) {
node.textContent = newText;
}
}
if (node.hasAttribute("data-i18n-title")) {
const newTitle = dict[node.dataset.i18nTitle];
if (newTitle && node.getAttribute("title") !== newTitle) {
node.setAttribute("title", newTitle);
}
}
});
}
Comment on lines 367 to 388

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿ“ Info: Korean-default skip relies on inlined titles matching the dictionary

The initial-load fast path skips all data-i18n-title nodes when the resolved language is Korean, so inlined title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" values are trusted to match messages.ko['common.newTab']. They currently match; any future drift would silently go uncorrected on first load.

(Refers to this code)

Devin Review

Was this helpful? React with ๐Ÿ‘ or ๐Ÿ‘Ž to provide feedback.

Expand Down
32 changes: 16 additions & 16 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<a href="#projects" data-i18n="nav.projects">ํ”„๋กœ์ ํŠธ</a>
<a href="#forks" data-i18n="nav.forks">Fork</a>
<a href="#work" data-i18n="nav.work">์ž‘์—…</a>
<a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab">GitHub</a>
<a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab">GitHub</a>
</nav>
<div class="language-switch" role="group" aria-label="Language">
<button type="button" data-lang="ko" lang="ko" aria-pressed="true" aria-label="ํ•œ๊ตญ์–ด">KO</button>
Expand All @@ -59,7 +59,7 @@ <h1 data-i18n="hero.title">๋งฅ๋ฝ์ง€ํ˜œ ์—ฐ๊ตฌ์‹ค</h1>
๊ตฌ์Šฌ์ด ์„œ ๋ง์ด์–ด๋„ ๊ฟฐ์–ด์•ผ ๋ณด๋ฐฐ์ด๋“ฏ, ๋ฌธ์„œ, ๋ฉ”์ผ, ๋กœ๊ทธ, ํšŒ์˜๋ก์„ ๋งฅ๋ฝ ์•ˆ์—์„œ ์—ฎ์–ด ์‚ฌ๋žŒ์ด ๋ฌด์—‡์„ ๊ฒฐ์ •ํ•˜๊ณ  ๋ฌด์—‡์„ ์‹คํ–‰ํ• ์ง€ ๋ณด์ด๊ฒŒ ํ•˜๋Š” AI ์˜์‚ฌ๊ฒฐ์ • ์ง€์› ์‹œ์Šคํ…œ์„ ์—ฐ๊ตฌํ•˜๊ณ  ๋งŒ๋“ญ๋‹ˆ๋‹ค.
</p>
<div class="hero-actions" role="group" aria-label="Homepage actions">
<a target="_blank" rel="noopener noreferrer" class="button primary" href="https://github.com/ContextualWisdomLab" data-i18n="hero.primaryCta">GitHub ๋ณด๊ธฐ</a>
<a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" class="button primary" href="https://github.com/ContextualWisdomLab" data-i18n="hero.primaryCta">GitHub ๋ณด๊ธฐ</a>
<a class="button secondary" href="#dikw" data-i18n="hero.secondaryCta">DIKW ๋ณด๊ธฐ</a>
</div>
</div>
Expand Down Expand Up @@ -254,19 +254,19 @@ <h2 data-i18n="references.title">์ฐธ๊ณ ๋ฌธํ—Œ</h2>
<ol class="reference-list">
<li>
<span data-i18n="references.ackoff">Ackoff, R. L. (1989). From data to wisdom. Journal of Applied Systems Analysis, 16(1), 3-9.</span>
<a target="_blank" rel="noopener noreferrer" href="https://faculty.ung.edu/kmelton/documents/datawisdom.pdf">https://faculty.ung.edu/kmelton/documents/datawisdom.pdf</a>
<a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://faculty.ung.edu/kmelton/documents/datawisdom.pdf">https://faculty.ung.edu/kmelton/documents/datawisdom.pdf</a>
</li>
<li>
<span data-i18n="references.baskarada">Baskarada, S., &amp; 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).</span>
<a target="_blank" rel="noopener noreferrer" href="https://doi.org/10.3127/ajis.v18i1.748">https://doi.org/10.3127/ajis.v18i1.748</a>
<a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://doi.org/10.3127/ajis.v18i1.748">https://doi.org/10.3127/ajis.v18i1.748</a>
</li>
<li>
<span data-i18n="references.fricke">Frickรฉ, M. (2009). The knowledge pyramid: A critique of the DIKW hierarchy. Journal of Information Science, 35(2), 131-142.</span>
<a target="_blank" rel="noopener noreferrer" href="https://doi.org/10.1177/0165551508094050">https://doi.org/10.1177/0165551508094050</a>
<a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://doi.org/10.1177/0165551508094050">https://doi.org/10.1177/0165551508094050</a>
</li>
<li>
<span data-i18n="references.brienza">Brienza, J. P., Kung, F. Y. H., Santos, H. C., Bobocel, D. R., &amp; 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.</span>
<a target="_blank" rel="noopener noreferrer" href="https://doi.org/10.1037/pspp0000171">https://doi.org/10.1037/pspp0000171</a>
<a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://doi.org/10.1037/pspp0000171">https://doi.org/10.1037/pspp0000171</a>
</li>
</ol>
</section>
Expand Down Expand Up @@ -327,39 +327,39 @@ <h2 data-i18n="projects.title">๊ณต๊ฐœ ํ”„๋กœ์ ํŠธ</h2>
</div>
<div class="naruon-grid project-grid">
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/naruon" data-i18n="projects.naruonTitle">Naruon</a></h3>
<h3><a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/naruon" data-i18n="projects.naruonTitle">Naruon</a></h3>
<p data-i18n="projects.naruonBody">๋ฉ”์ผ, ์ฒจ๋ถ€, ์ผ์ •, ์ž‘์—…์„ ๋งฅ๋ฝ์œผ๋กœ ๋ฌถ์–ด ํŒ๋‹จ๊ณผ ์‹คํ–‰์œผ๋กœ ์—ฐ๊ฒฐํ•˜๋Š” AI ์ด๋ฉ”์ผ ์›Œํฌ์ŠคํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/pg-erd-cloud" data-i18n="projects.pgErdTitle">pg-erd-cloud</a></h3>
<h3><a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/pg-erd-cloud" data-i18n="projects.pgErdTitle">pg-erd-cloud</a></h3>
<p data-i18n="projects.pgErdBody">PostgreSQL ์Šคํ‚ค๋งˆ๋ฅผ ๋ฆฌ๋ฒ„์Šค ์—”์ง€๋‹ˆ์–ด๋งํ•˜๊ณ  ERD์™€ DDL ๊ณต์œ  ํ๋ฆ„์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ํด๋ผ์šฐ๋“œ MVP์ž…๋‹ˆ๋‹ค.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/bandscope" data-i18n="projects.bandscopeTitle">BandScope</a></h3>
<h3><a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/bandscope" data-i18n="projects.bandscopeTitle">BandScope</a></h3>
<p data-i18n="projects.bandscopeBody">๊ณก์„ ์„น์…˜, ์—ญํ• , ํ…œํฌ, ์—ฐ์Šต ์šฐ์„ ์ˆœ์œ„๋กœ ๋ถ„์„ํ•˜๋Š” ๋กœ์ปฌ ์šฐ์„  ๋ฆฌํ—ˆ์„ค ์•ฑ์ž…๋‹ˆ๋‹ค.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/codec-carver" data-i18n="projects.codecCarverTitle">codec-carver</a></h3>
<h3><a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/codec-carver" data-i18n="projects.codecCarverTitle">codec-carver</a></h3>
<p data-i18n="projects.codecCarverBody">๊ธด ๋…น์Œ์„ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์กดํ•œ FLAC/Opus ์กฐ๊ฐ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” Python CLI์ž…๋‹ˆ๋‹ค.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/newsdom-api" data-i18n="projects.newsdomTitle">newsdom-api</a></h3>
<h3><a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/newsdom-api" data-i18n="projects.newsdomTitle">newsdom-api</a></h3>
<p data-i18n="projects.newsdomBody">์Šค์บ”๋œ ์ผ๋ณธ์–ด ์‹ ๋ฌธ PDF๋ฅผ ๊ธฐ์‚ฌ, ์ œ๋ชฉ, ๋ณธ๋ฌธ, ์ด๋ฏธ์ง€ ๊ตฌ์กฐ์˜ DOMํ˜• JSON์œผ๋กœ ํŒŒ์‹ฑํ•˜๋Š” API์ž…๋‹ˆ๋‹ค.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/scopeweave" data-i18n="projects.scopeweaveTitle">scopeweave</a></h3>
<h3><a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/scopeweave" data-i18n="projects.scopeweaveTitle">scopeweave</a></h3>
<p data-i18n="projects.scopeweaveBody">ํŠธ๋ฆฌ ํŽธ์ง‘, ์ง„ํ–‰๋ฅ  ๊ณ„์‚ฐ, CSV/JSON, ์ฃผ๊ฐ„ Gantt๋ฅผ ์ง€์›ํ•˜๋Š” ์ •์  HTML/CSS/JS WBS ํ”Œ๋ž˜๋„ˆ์ž…๋‹ˆ๋‹ค.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/VibeSec" data-i18n="projects.vibesecTitle">VibeSec</a></h3>
<h3><a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/VibeSec" data-i18n="projects.vibesecTitle">VibeSec</a></h3>
<p data-i18n="projects.vibesecBody">๋ฐ”์ด๋ธŒ์ฝ”๋”ฉ ์•ฑ์„ ์œ„ํ•œ ๋ณด์•ˆ ๊ฐ€๋“œ๋ ˆ์ผ์ž…๋‹ˆ๋‹ค. AI ๊ฐœ๋ฐœ ๋„๊ตฌ ๊ทœ์น™, ์ •์  ์ ๊ฒ€, ๋ฆฌ๋ทฐ์™€ ์ˆ˜์ • ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/fast-mlsirm" data-i18n="projects.fastMlsirmTitle">fast-mlsirm</a></h3>
<h3><a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/fast-mlsirm" data-i18n="projects.fastMlsirmTitle">fast-mlsirm</a></h3>
<p data-i18n="projects.fastMlsirmBody">MLSIRM/MLS2PLM ๋ชจํ˜•์˜ ์‹œ๋ฎฌ๋ ˆ์ด์…˜, ์ ํ•ฉ, ๋ณต์› ์ง„๋‹จ์„ ๋น ๋ฅด๊ฒŒ ์ˆ˜ํ–‰ํ•˜๋Š” Python/Rust ํŒจํ‚ค์ง€์ž…๋‹ˆ๋‹ค.</p>
</article>
<article>
<h3><a target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/waf-ids-ai-soc" data-i18n="projects.wafIdsTitle">waf-ids-ai-soc</a></h3>
<h3><a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://github.com/ContextualWisdomLab/waf-ids-ai-soc" data-i18n="projects.wafIdsTitle">waf-ids-ai-soc</a></h3>
<p data-i18n="projects.wafIdsBody">DNSBL ๊ฒŒ์‹œ ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ˜ Rust ์šฐ์„  WAF/IDS/AI SOC ๊ฒŒ์ดํŠธ์›จ์ด์ž…๋‹ˆ๋‹ค.</p>
</article>
</div>
Expand Down Expand Up @@ -431,7 +431,7 @@ <h2 data-i18n="work.title">์—ฐ๊ตฌ์—์„œ ์ œํ’ˆ์œผ๋กœ</h2>
>
<p>
<span data-i18n="footer.founded">Founded by</span>
<a target="_blank" rel="noopener noreferrer" href="https://github.com/seonghobae">Seongho Bae</a>.
<a title="์ƒˆ ์ฐฝ์—์„œ ์—ด๊ธฐ" data-i18n-title="common.newTab" target="_blank" rel="noopener noreferrer" href="https://github.com/seonghobae">Seongho Bae</a>.
<span data-i18n="footer.line">Context into judgment. Judgment into action.</span>
</p>
</footer>
Expand Down
Loading