Skip to content
Open
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
3 changes: 3 additions & 0 deletions .jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,6 @@
## 2024-08-01 - λ„€μ΄ν‹°λΈŒ λΈŒλΌμš°μ € UI의 닀크 λͺ¨λ“œ 지원 κ°•μ œ
**ν•™μŠ΅:** CSS λ―Έλ””μ–΄ 쿼리(`@media (prefers-color-scheme: dark)`)λ₯Ό 톡해 닀크 λͺ¨λ“œλ₯Ό μ§€μ›ν•˜λ”λΌλ„, λΈŒλΌμš°μ €μ˜ λ„€μ΄ν‹°λΈŒ UI μš”μ†Œ(μŠ€ν¬λ‘€λ°”, κΈ°λ³Έ 폼 컨트둀, κΈ°λ³Έ λ°±κ·ΈλΌμš΄λ“œ λ“±)λŠ” ν…Œλ§ˆ 변경을 μΈμ‹ν•˜μ§€ λͺ»ν•΄ μ–΄λ‘μš΄ ν…Œλ§ˆ ν™˜κ²½μ—μ„œ 밝은 μŠ€ν¬λ‘€λ°”κ°€ ν‘œμ‹œλ˜λŠ” λ“± μ‹œκ°μ  뢈일치λ₯Ό μ΄ˆλž˜ν•©λ‹ˆλ‹€.
**쑰치:** 항상 HTML λ¬Έμ„œμ˜ `<head>` μ˜μ—­μ— `<meta name="color-scheme" content="light dark">` 메타 νƒœκ·Έλ₯Ό λͺ…μ‹œμ μœΌλ‘œ μΆ”κ°€ν•˜μ—¬ λΈŒλΌμš°μ € μˆ˜μ€€μ—μ„œ μ‚¬μš©μžμ˜ μ‹œμŠ€ν…œ ν…Œλ§ˆ(닀크 λͺ¨λ“œ λ“±)λ₯Ό μ™„μ „νžˆ 상속받아 일관성 μžˆλŠ” λ„€μ΄ν‹°λΈŒ UIλ₯Ό λ Œλ”λ§ν•˜λ„λ‘ 보μž₯ν•˜μ‹­μ‹œμ˜€.
## 2026-07-20 - File system root accessibility issue
**Learning:** When an application dynamically generates HTML titles and headers based on file system paths, the root directory can return an empty string for the file name. This results in empty `<title>` and `<h1>` tags, which severely degrades screen reader accessibility.
**Action:** Provide a robust fallback, such as the absolute path, when generating semantic HTML tags from user-provided or system-generated identifiers.
6 changes: 4 additions & 2 deletions src/main/kotlin/html4tree/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,8 @@ fun process_dir(curr_dir: File, excludeSet: Set<String>? = null, dirFiles: Array
${cssContent} </style>
"""

val dirName = if (curr_dir.name.isEmpty()) curr_dir.absolutePath else curr_dir.name

val index_top = """<!doctype html>
<html lang="ko">
<head>
Expand All @@ -327,12 +329,12 @@ ${cssContent} </style>
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src '${styleHash}'; base-uri 'none'; form-action 'none';">
<!-- λ³΄μ•ˆ ν–₯상: 리퍼러λ₯Ό ν†΅ν•œ 디렉토리 경둜 λ…ΈμΆœ λ°©μ§€ -->
<meta name="referrer" content="no-referrer">
<title>${curr_dir.getName().escapeHtml()}</title>
<title>${dirName.escapeHtml()}</title>
${css}
</head>
<body>
<main>
<h1>${curr_dir.getName().escapeHtml()}</h1>
<h1>${dirName.escapeHtml()}</h1>
<nav aria-label="디렉토리 λͺ©λ‘">
<ul role="list">
<li><a class="dir-link" href="./.." aria-label="μƒμœ„ λ””λ ‰ν† λ¦¬λ‘œ 이동" title="μƒμœ„ λ””λ ‰ν† λ¦¬λ‘œ 이동"><span class="icon" aria-hidden="true">&#x21B0;</span> <span>..</span></a></li>
Expand Down
18 changes: 18 additions & 0 deletions src/test/kotlin/html4tree/MainTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,24 @@ class MainTest {
}
}

@Test
fun testProcessDirEmptyDirNameFallback() {
val fakeRoot = object : File(tempDir, "fakeRoot") {
override fun getName() = ""
}
fakeRoot.mkdir()
try {
process_dir(fakeRoot)
val indexFile = File(fakeRoot, "index.html")
assertTrue(indexFile.exists())
val content = indexFile.readText()
assertTrue(content.contains("<title>${fakeRoot.absolutePath.escapeHtml()}</title>"))
assertTrue(content.contains("<h1>${fakeRoot.absolutePath.escapeHtml()}</h1>"))
} finally {
fakeRoot.deleteRecursively()
}
}

@Test
fun testProcessIgnoreFileWithIndexHtml() {
val ignoreFile = File(tempDir, ".html4ignore")
Expand Down
Loading