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",