Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .Jules/palette.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 2024-05-24 - [Add smooth transitions for a tags but respect user motion preferences]
**Learning:** Adding CSS transitions (`transition: all`) can create unintended animations and performance issues. Also, animations can cause problems for users with vestibular motion disorders.
**Action:** When adding CSS transitions, explicitly specify properties (e.g., `background-color`, `outline-color`) instead of `transition: all`. Always include a `@media (prefers-reduced-motion: reduce)` override to set `transition: none` for accessibility.
**Action:** When adding CSS transitions, explicitly specify properties (e.g., `background-color`, `outline-color`) instead of `transition: all`. Always include a `@media (prefers-reduced-motion: reduce)` override to set `transition: none` for accessibility.
## 2026-07-09 - [닀크 λͺ¨λ“œ 지원 및 μ ‘κ·Όμ„± ν–₯상, CSP μ€€μˆ˜λ₯Ό μœ„ν•œ 인라인 μŠ€νƒ€μΌ 제거]
**Learning:** `Content-Security-Policy`κ°€ `style-src 'unsafe-inline'`λ₯Ό ν—ˆμš©ν•˜λ”λΌλ„, μœ μ§€λ³΄μˆ˜μ„±κ³Ό λ³΄μ•ˆμ„ 높이기 μœ„ν•΄ 인라인 μŠ€νƒ€μΌ λŒ€μ‹  CSS 클래슀λ₯Ό ν™œμš©ν•˜λŠ” 것이 λ‚«λ‹€. 특히, 정적 HTML 생성 κ³Όμ •μ—μ„œ ν•˜λ“œμ½”λ”©λœ 영문 μ ‘κ·Όμ„± 속성(`aria-label="Directory listing"`)이 ν•œκ΅­μ–΄ ν™˜κ²½μ—μ„œ 슀크린 리더 μ‚¬μš©μžμ—κ²Œ 어색할 수 μžˆμœΌλ―€λ‘œ 이λ₯Ό 언어에 맞게 λ²ˆμ—­ν•˜λŠ” 것이 μ€‘μš”ν•˜λ‹€. λ˜ν•œ 정적 파일 트리 λ Œλ”λ§μ— 닀크 λͺ¨λ“œ(`@media (prefers-color-scheme: dark)`)λ₯Ό μ§€μ›ν•˜λ©΄ λˆˆλΆ€μ‹¬μ„ 쀄이고 μ „λ°˜μ μΈ UX λ§Œμ‘±λ„λ₯Ό 크게 ν–₯μƒμ‹œν‚¬ 수 μžˆλ‹€.
**Action:** μ•žμœΌλ‘œ HTML ꡬ쑰λ₯Ό λ™μ μœΌλ‘œ 생성할 λ•Œ, 인라인 μŠ€νƒ€μΌμ„ λ°°μ œν•˜κ³  CSS 클래슀 기반의 λ””μžμΈμ„ μ±„νƒν•˜μ—¬ CSPμ™€μ˜ 좩돌 κ°€λŠ₯성을 쀄인닀. μΆ”κ°€λ‘œ `aria-label` 같은 μ ‘κ·Όμ„± 속성은 ν…œν”Œλ¦Ώ 언어에 μ•Œλ§žκ²Œ λ²ˆμ—­λ˜μ—ˆλŠ”μ§€ ν™•μΈν•˜λ©°, μŠ€νƒ€μΌ μ‹œνŠΈλ₯Ό μ‚½μž…ν•  λ•Œ 닀크 λͺ¨λ“œ λ―Έλ””μ–΄ 쿼리λ₯Ό 기본으둜 μΆ”κ°€ν•˜λŠ” 것을 μžŠμ§€ μ•ŠλŠ”λ‹€.
37 changes: 33 additions & 4 deletions src/main/kotlin/html4tree/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ fun process_dir(curr_dir: File){

val css = """
<style>
body {
background-color: #ffffff;
color: #24292e;
}
ul {
list-style-type: none;
padding-left: 0;
Expand All @@ -193,11 +197,36 @@ fun process_dir(curr_dir: File){
outline: 2px solid #0366d6;
outline-offset: -2px;
}
.item-link {
display: block;
width: 100%;
}
.empty-state {
padding: 0.5rem;
color: #555555;
font-style: italic;
}
@media (prefers-reduced-motion: reduce) {
a {
transition: none;
}
}
@media (prefers-color-scheme: dark) {
body {
background-color: #0d1117;
color: #c9d1d9;
}
a {
color: #58a6ff;
}
a:hover, a:focus-visible {
background-color: #161b22;
outline-color: #58a6ff;
}
.empty-state {
color: #8b949e;
}
}
</style>
"""

Expand All @@ -214,9 +243,9 @@ fun process_dir(curr_dir: File){
<body>
<main>
<h1>${curr_dir.getName().escapeHtml()}</h1>
<nav aria-label="Directory listing">
<nav aria-label="디렉토리 λͺ©λ‘">
<ul>
<li><a style="display:block; width:100%" href="./.." aria-label="μƒμœ„ λ””λ ‰ν† λ¦¬λ‘œ 이동"><span aria-hidden="true">&#x21B0;</span> ..</a></li>
<li><a class="item-link" href="./.." aria-label="μƒμœ„ λ””λ ‰ν† λ¦¬λ‘œ 이동"><span aria-hidden="true">&#x21B0;</span> ..</a></li>
"""

val index_middle = fun():String{
Expand All @@ -231,13 +260,13 @@ fun process_dir(curr_dir: File){
val encodedHref = if (isLinkedDirectory) { "./${fileName.urlEncodePath()}/" } else { "./${fileName.urlEncodePath()}" }
val ariaLabel = "${fileName} ${if (isLinkedDirectory) { "디렉토리" } else { "파일" }}".escapeHtml()
val icon = if (isLinkedDirectory) { "&#128193;" } else { "&rtrif;" }
l.append(""" <li><a style="display:block; width:100%" href="${encodedHref}" aria-label="${ariaLabel}"><span aria-hidden="true">${icon}</span> ${fileName.escapeHtml()}</a></li>""")
l.append(""" <li><a class="item-link" href="${encodedHref}" aria-label="${ariaLabel}"><span aria-hidden="true">${icon}</span> ${fileName.escapeHtml()}</a></li>""")
l.append('\n')
}
}

if(l.isEmpty()){
l.append(""" <li><div style="padding: 0.5rem; color: #666; font-style: italic;">이 λ””λ ‰ν† λ¦¬λŠ” λΉ„μ–΄ μžˆμŠ΅λ‹ˆλ‹€.</div></li>""")
l.append(""" <li><div class="empty-state">이 λ””λ ‰ν† λ¦¬λŠ” λΉ„μ–΄ μžˆμŠ΅λ‹ˆλ‹€.</div></li>""")
l.append('\n')
}

Expand Down
4 changes: 3 additions & 1 deletion src/test/kotlin/html4tree/MainTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ class MainTest {
assertTrue(indexFile.exists())
val htmlContent = indexFile.readText()
assertTrue(htmlContent.contains("<html lang=\"ko\">"))
assertTrue(htmlContent.contains("<nav aria-label=\"Directory listing\">"))
assertTrue(htmlContent.contains("<nav aria-label=\"디렉토리 λͺ©λ‘\">"))
assertTrue(htmlContent.contains("<main>"))
assertTrue(htmlContent.contains("</main>"))
assertTrue(htmlContent.contains("aria-label=\"μƒμœ„ λ””λ ‰ν† λ¦¬λ‘œ 이동\""))
Expand All @@ -159,6 +159,8 @@ class MainTest {
assertTrue(htmlContent.contains("subdir/"))
assertTrue(htmlContent.contains("&#128193;"))
assertFalse(htmlContent.contains("test.ignore"))
assertTrue(htmlContent.contains("class=\"item-link\""))
assertTrue(htmlContent.contains("prefers-color-scheme: dark"))
assertTrue(htmlContent.contains("Content-Security-Policy"))
assertTrue(htmlContent.contains("default-src 'none'; style-src 'unsafe-inline';"))
}
Expand Down
Loading