From abbf5d5bcd045cdb6baf16128ef54d4df3a7f3fd Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Wed, 7 Oct 2026 15:05:31 -0700 Subject: [PATCH] fix(web): C#, Java, PHP and 11 other languages get file icons (#16974) Co-authored-by: Claude Opus 5.5 (1M context) --- apps/web/src/pierre-icons.test.ts | 24 +++++++++- apps/web/src/pierre-icons.ts | 79 +++++++++++++++++++++++++++++-- 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/apps/web/src/pierre-icons.test.ts b/apps/web/src/pierre-icons.test.ts index 6090d7ed9e72bdaaf3dab960aef312e732be40b1..c90b130b33eae6ddd4740c0abec4b2674cf39916 100644 --- a/apps/web/src/pierre-icons.test.ts +++ b/apps/web/src/pierre-icons.test.ts @@ -38,7 +38,10 @@ describe("Pierre file icons", () => { it("ships every custom icon referenced by the extended resolver", () => { const customIconNames = new Set( - Object.values(T3_PIERRE_ICONS.byFileName).filter((name) => name.startsWith("t3-")), + [ + ...Object.values(T3_PIERRE_ICONS.byFileName), + ...Object.values(T3_PIERRE_ICONS.byFileExtension), + ].filter((name) => name.startsWith("t3-")), ); for (const iconName of customIconNames) { assert.include(T3_PIERRE_ICONS.spriteSheet, `id="${iconName}"`); @@ -64,4 +67,23 @@ describe("Pierre file icons", () => { it("gives a dockerfile fence the Docker icon", () => { assert.isTrue(hasSpecificPierreIconForFileName(syntheticFileNameForLanguageId("dockerfile"))); }); + + it.each([ + "csharp", + "dart", + "diff", + "elixir", + "haskell", + "java", + "kotlin", + "lua", + "php", + "powershell", + "r", + "scala", + "toml", + "xml", + ])("gives a %s fence a language icon", (language) => { + assert.isTrue(hasSpecificPierreIconForFileName(syntheticFileNameForLanguageId(language))); + }); }); diff --git a/apps/web/src/pierre-icons.ts b/apps/web/src/pierre-icons.ts index 46f0099fedee3ea4dcdf48b21eeb8879f0f9517c..ead46e89d6ee0566e7f2350ef027d951aed160e2 100644 --- a/apps/web/src/pierre-icons.ts +++ b/apps/web/src/pierre-icons.ts @@ -28,6 +28,51 @@ const T3_FILE_ICON_SPRITE = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + `; export const T3_PIERRE_ICONS = { @@ -41,9 +86,33 @@ export const T3_PIERRE_ICONS = { "pnpm-lock.yaml": "t3-file-icon-pnpm", "pnpm-workspace.yaml": "t3-file-icon-pnpm", }, - byFileExtension: Object.fromEntries( - VIDEO_FILE_EXTENSIONS.map((extension) => [extension, "t3-file-icon-video"]), - ), + byFileExtension: { + ...Object.fromEntries( + VIDEO_FILE_EXTENSIONS.map((extension) => [extension, "t3-file-icon-video"]), + ), + // Languages the complete set has no icon for. + cs: "t3-file-icon-csharp", + csx: "t3-file-icon-csharp", + dart: "t3-file-icon-dart", + diff: "t3-file-icon-diff", + patch: "t3-file-icon-diff", + ex: "t3-file-icon-elixir", + exs: "t3-file-icon-elixir", + hs: "t3-file-icon-haskell", + lhs: "t3-file-icon-haskell", + java: "t3-file-icon-java", + kt: "t3-file-icon-kotlin", + kts: "t3-file-icon-kotlin", + lua: "t3-file-icon-lua", + php: "t3-file-icon-php", + ps1: "t3-file-icon-powershell", + psm1: "t3-file-icon-powershell", + psd1: "t3-file-icon-powershell", + r: "t3-file-icon-r", + scala: "t3-file-icon-scala", + toml: "t3-file-icon-toml", + xml: "t3-file-icon-xml", + }, } satisfies FileTreeIcons; const completeIconResolver = createFileTreeIconResolver(T3_PIERRE_ICONS); @@ -51,11 +120,15 @@ const completeIconResolver = createFileTreeIconResolver(T3_PIERRE_ICONS); const LANGUAGE_EXTENSION_ALIASES: Record = { bash: "sh", csharp: "cs", + elixir: "ex", + haskell: "hs", javascript: "js", jsx: "jsx", + kotlin: "kt", markdown: "md", mdx: "mdx", plaintext: "txt", + powershell: "ps1", python: "py", ruby: "rb", rust: "rs", -- 2.54.0