diff --git a/.jules/palette.md b/.jules/palette.md index 9a12c9de..c933e2eb 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -48,3 +48,7 @@ ## 2024-08-01 - 네이티브 브라우저 UI의 다크 모드 지원 강제 **학습:** CSS 미디어 쿼리(`@media (prefers-color-scheme: dark)`)를 통해 다크 모드를 지원하더라도, 브라우저의 네이티브 UI 요소(스크롤바, 기본 폼 컨트롤, 기본 백그라운드 등)는 테마 변경을 인식하지 못해 어두운 테마 환경에서 밝은 스크롤바가 표시되는 등 시각적 불일치를 초래합니다. **조치:** 항상 HTML 문서의 `` 영역에 `` 메타 태그를 명시적으로 추가하여 브라우저 수준에서 사용자의 시스템 테마(다크 모드 등)를 완전히 상속받아 일관성 있는 네이티브 UI를 렌더링하도록 보장하십시오. + +## 2024-08-02 - 빈 디렉토리에 대한 시각적 피드백 개선 +**학습:** 목록에 파일이 없는 디렉토리에 닫힌 폴더 아이콘(`📁`)을 사용하면 사용자가 안에 내용이 있을 것이라고 예상하게 됩니다. 열린 빈 폴더 아이콘(`📂`)을 사용하면 디렉토리가 비어 있다는 것을 직관적으로 전달할 수 있습니다. +**조치:** 디렉토리 트리를 렌더링할 때, 해당 디렉토리가 비어 있는지 확인하고 빈 경우에는 열린 폴더 이모지(`📂`)를 사용하여 시각적 피드백을 명확히 제공하십시오. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index b4558624..348881d1 100644 --- a/src/main/kotlin/html4tree/main.kt +++ b/src/main/kotlin/html4tree/main.kt @@ -362,7 +362,19 @@ ${cssContent} if (!isSymbolicLink) { val encodedHref = if (isLinkedDirectory) { "./${fileName.urlEncodePath()}/" } else { "./${fileName.urlEncodePath()}" } val ariaLabel = "${fileName} ${if (isLinkedDirectory) { "디렉토리" } else { "파일" }}".escapeHtml() - val icon = if (isLinkedDirectory) { "📁" } else { "📄" } + var isEmptyDir = false + if (isLinkedDirectory) { + try { + val stream = Files.newDirectoryStream(it.toPath()) + try { + isEmptyDir = !stream.iterator().hasNext() + } finally { + stream.close() + } + } catch (e: Exception) { + } + } + val icon = if (isLinkedDirectory) { if (isEmptyDir) "📂" else "📁" } else { "📄" } l.append("""
  • ${fileName.escapeHtml()}
  • """) l.append('\n') } diff --git a/src/test/kotlin/html4tree/MainTest.kt b/src/test/kotlin/html4tree/MainTest.kt index 13494714..76dfba64 100644 --- a/src/test/kotlin/html4tree/MainTest.kt +++ b/src/test/kotlin/html4tree/MainTest.kt @@ -322,7 +322,7 @@ class MainTest { assertTrue(htmlContent.contains("title=\"subdir 디렉토리\"")) assertTrue(htmlContent.contains("file1.txt")) assertTrue(htmlContent.contains("subdir/")) - assertTrue(htmlContent.contains("📁")) + assertTrue(htmlContent.contains("📂")) assertFalse(htmlContent.contains("test.ignore")) assertTrue(htmlContent.contains("Content-Security-Policy")) val hashMatch = Regex("""style-src '(sha256-[A-Za-z0-9+/=]+)'""").find(htmlContent)?.groupValues?.get(1) @@ -414,6 +414,21 @@ class MainTest { } } + @Test + fun testProcessDirEmptyDirIcon() { + val emptyDir = File(tempDir, "empty_dir") + emptyDir.mkdir() + val notEmptyDir = File(tempDir, "not_empty_dir") + notEmptyDir.mkdir() + File(notEmptyDir, "file.txt").writeText("hello") + + go(tempDir.absolutePath, 0) + + val htmlContent = File(tempDir, "index.html").readText() + assertTrue(htmlContent.contains("📂 empty_dir")) + assertTrue(htmlContent.contains("📁 not_empty_dir")) + } + @Test fun testGoWithMaxLevel() { val subdir = File(tempDir, "subdir")