From aaa6a14b9d881c998dc76e06221755962d6cf395 Mon Sep 17 00:00:00 2001
From: seonghobae <8172694+seonghobae@users.noreply.github.com>
Date: Thu, 1 Oct 2026 18:49:43 +0000
Subject: [PATCH 1/2] =?UTF-8?q?=EC=99=B8=EB=B6=80=20=EB=A7=81=ED=81=AC=20?=
=?UTF-8?q?=EC=A0=91=EA=B7=BC=EC=84=B1=20=EB=B0=8F=20=EB=A0=88=EC=9D=B4?=
=?UTF-8?q?=EC=95=84=EC=9B=83=20=EA=B0=9C=EC=84=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- `target="_blank"` 외부 링크에 스크린 리더용 경고 텍스트(`.sr-only`) 추가
- 시각적 사용자를 위한 `aria-hidden="true"` 아이콘 추가
- 긴 URL이 레이아웃을 깨지 않도록 `.ext-link` 클래스를 통해 `word-break: break-all` 적용
- `.jules/palette.md`에 관련된 UX/접근성 학습 기록 추가
---
.jules/palette.md | 4 ++++
scanner/dashboard/index.html | 3 ++-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/.jules/palette.md b/.jules/palette.md
index ea004e2d2..13a56607e 100644
--- a/.jules/palette.md
+++ b/.jules/palette.md
@@ -81,3 +81,7 @@
## 2026-08-12 - Skip to Content Accessibility
**Learning:** Screen reader and keyboard-only users experience significant friction when forced to navigate through repetitive header controls on every page load.
**Action:** Keep a visible-on-focus skip link as the first interactive element, target a programmatically focusable main container, and give the focused link a high-contrast outline.
+
+## 2026-10-01 - External Links Accessibility and Layout
+**Learning:** For `target="_blank"` links, simply adding `rel="noopener"` is not enough. Screen reader users need explicit auditory warnings, visual users need a visual cue (icon), and long URL text in links alongside inline icons can break layouts if it doesn't wrap correctly.
+**Action:** When adding `target="_blank"` to an external link, always include both visually hidden `.sr-only` text (e.g., "(opens in a new tab)") and a visible `aria-hidden="true"` icon. To prevent layout breakage from long text (like URLs), apply `word-break: break-all` strictly to those specific links using a utility class (e.g., `.ext-link`), rather than globally to all `` tags.
diff --git a/scanner/dashboard/index.html b/scanner/dashboard/index.html
index 132bc31b2..7e197eea3 100644
--- a/scanner/dashboard/index.html
+++ b/scanner/dashboard/index.html
@@ -82,6 +82,7 @@
body.drag-active::after{content:"Drop findings.json here";position:fixed;inset:0;z-index:99;background:rgba(37,110,244,.08);border:4px dashed var(--primary);display:flex;align-items:center;justify-content:center;font-size:24px;font-weight:700;color:var(--primary);pointer-events:none;backdrop-filter:blur(2px)}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
a{color:var(--primary)}
+ .ext-link{word-break:break-all}
.skip-link{position:absolute;top:-48px;left:0;background:var(--primary);color:#fff;padding:8px 16px;z-index:100;font-weight:700;border-radius:0 0 8px 0;transition:top .2s}\n .skip-link:focus{top:0;outline:3px solid #fff;outline-offset:2px;box-shadow:0 0 0 5px var(--primary)}\n
@@ -281,7 +282,7 @@ Dashboard
function openDetail(f){
lastFocus = document.activeElement;
const s = String(f.severity||'INFO').toUpperCase();
- const refs = (f.references||[]).map(r=>`${esc(r)}`).join('
');
+ const refs = (f.references||[]).map(r=>`${esc(r)}(opens in a new tab)`).join('
');
const owasp = (f.owasp||[]).join(', ');
const cwe = (f.cwe||[]).join(', ');
const d = document.getElementById('detail');
From bd723e42d5b5495fc19b76fca6cf84ff95b325cc Mon Sep 17 00:00:00 2001
From: Seongho Bae
Date: Fri, 2 Oct 2026 03:56:10 +0900
Subject: [PATCH 2/2] chore: retire duplicate external-link UI delta
Restore the protected develop tree. Canonical Draft PR #1361 preserves the complete user-visible requirement with the safer overflow-wrap boundary and an executable regression; this branch has no independent valid delta.
---
.jules/palette.md | 4 ----
scanner/dashboard/index.html | 3 +--
2 files changed, 1 insertion(+), 6 deletions(-)
diff --git a/.jules/palette.md b/.jules/palette.md
index 13a56607e..ea004e2d2 100644
--- a/.jules/palette.md
+++ b/.jules/palette.md
@@ -81,7 +81,3 @@
## 2026-08-12 - Skip to Content Accessibility
**Learning:** Screen reader and keyboard-only users experience significant friction when forced to navigate through repetitive header controls on every page load.
**Action:** Keep a visible-on-focus skip link as the first interactive element, target a programmatically focusable main container, and give the focused link a high-contrast outline.
-
-## 2026-10-01 - External Links Accessibility and Layout
-**Learning:** For `target="_blank"` links, simply adding `rel="noopener"` is not enough. Screen reader users need explicit auditory warnings, visual users need a visual cue (icon), and long URL text in links alongside inline icons can break layouts if it doesn't wrap correctly.
-**Action:** When adding `target="_blank"` to an external link, always include both visually hidden `.sr-only` text (e.g., "(opens in a new tab)") and a visible `aria-hidden="true"` icon. To prevent layout breakage from long text (like URLs), apply `word-break: break-all` strictly to those specific links using a utility class (e.g., `.ext-link`), rather than globally to all `` tags.
diff --git a/scanner/dashboard/index.html b/scanner/dashboard/index.html
index 7e197eea3..132bc31b2 100644
--- a/scanner/dashboard/index.html
+++ b/scanner/dashboard/index.html
@@ -82,7 +82,6 @@
body.drag-active::after{content:"Drop findings.json here";position:fixed;inset:0;z-index:99;background:rgba(37,110,244,.08);border:4px dashed var(--primary);display:flex;align-items:center;justify-content:center;font-size:24px;font-weight:700;color:var(--primary);pointer-events:none;backdrop-filter:blur(2px)}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
a{color:var(--primary)}
- .ext-link{word-break:break-all}
.skip-link{position:absolute;top:-48px;left:0;background:var(--primary);color:#fff;padding:8px 16px;z-index:100;font-weight:700;border-radius:0 0 8px 0;transition:top .2s}\n .skip-link:focus{top:0;outline:3px solid #fff;outline-offset:2px;box-shadow:0 0 0 5px var(--primary)}\n
@@ -282,7 +281,7 @@ Dashboard
function openDetail(f){
lastFocus = document.activeElement;
const s = String(f.severity||'INFO').toUpperCase();
- const refs = (f.references||[]).map(r=>`${esc(r)}(opens in a new tab)`).join('
');
+ const refs = (f.references||[]).map(r=>`${esc(r)}`).join('
');
const owasp = (f.owasp||[]).join(', ');
const cwe = (f.cwe||[]).join(', ');
const d = document.getElementById('detail');