website
git clone https://git.pyrossh.dev/website
木 Personal website of pyrossh. Built with astrojs, shiki, vite.
src/_helpers/fileIcons.js
| 3c79a68 | 1 | import iconSet from "@iconify-json/vscode-icons/icons.json" with { type: "json" }; |
| 3c79a68 | 2 | |
| 3c79a68 | 3 | // The old Astro version resolved per-extension file/folder icons from the |
| 3c79a68 | 4 | // full vscode-icons manifest (see git history at 7325531^:src/utils/files.ts). |
| 3c79a68 | 5 | // That manifest is itself a large VS Code extension repo installed as a git |
| 3c79a68 | 6 | // dependency — overkill for a static build. This is a curated subset of the |
| 3c79a68 | 7 | // same @iconify-json/vscode-icons icon set (already used to render both), |
| 3c79a68 | 8 | // covering the extensions that actually show up in these repos, with a |
| 3c79a68 | 9 | // generic fallback for anything else. |
| 3c79a68 | 10 | const FILENAME_TO_ICON = { |
| 3c79a68 | 11 | "cargo.toml": "file-type-cargo", |
| 3c79a68 | 12 | "cargo.lock": "file-type-cargo", |
| 3c79a68 | 13 | "license": "file-type-license", |
| 3c79a68 | 14 | "license.md": "file-type-license", |
| 3c79a68 | 15 | ".gitignore": "file-type-git", |
| 3c79a68 | 16 | ".gitattributes": "file-type-git", |
| 3c79a68 | 17 | ".npmignore": "file-type-npm", |
| 3c79a68 | 18 | "package.json": "file-type-npm", |
| 3c79a68 | 19 | "package-lock.json": "file-type-npm", |
| 3c79a68 | 20 | "bun.lock": "file-type-npm", |
| 3c79a68 | 21 | "tsconfig.json": "file-type-typescript", |
| 3c79a68 | 22 | }; |
| 3c79a68 | 23 | |
| 3c79a68 | 24 | const EXT_TO_ICON = { |
| 3c79a68 | 25 | rs: "file-type-rust", |
| 3c79a68 | 26 | toml: "file-type-toml", |
| 3c79a68 | 27 | json: "file-type-json", |
| 3c79a68 | 28 | jsonc: "file-type-json", |
| 3c79a68 | 29 | md: "file-type-markdown", |
| 3c79a68 | 30 | mdx: "file-type-mdx", |
| 3c79a68 | 31 | css: "file-type-css", |
| 3c79a68 | 32 | html: "file-type-html", |
| 3c79a68 | 33 | js: "file-type-js", |
| 3c79a68 | 34 | mjs: "file-type-js", |
| 3c79a68 | 35 | jsx: "file-type-reactjs", |
| 3c79a68 | 36 | ts: "file-type-typescript", |
| 3c79a68 | 37 | tsx: "file-type-reactts", |
| 3c79a68 | 38 | zig: "file-type-zig", |
| 3c79a68 | 39 | svg: "file-type-svg", |
| 3c79a68 | 40 | png: "file-type-image", |
| 3c79a68 | 41 | jpg: "file-type-image", |
| 3c79a68 | 42 | jpeg: "file-type-image", |
| 3c79a68 | 43 | gif: "file-type-image", |
| 3c79a68 | 44 | webp: "file-type-webp", |
| 3c79a68 | 45 | pdf: "file-type-pdf2", |
| 3c79a68 | 46 | txt: "file-type-text", |
| 3c79a68 | 47 | sh: "file-type-shell", |
| 3c79a68 | 48 | py: "file-type-python", |
| 3c79a68 | 49 | kt: "file-type-kotlin", |
| 3c79a68 | 50 | java: "file-type-java", |
| 3c79a68 | 51 | go: "file-type-go", |
| 3c79a68 | 52 | c: "file-type-c", |
| 3c79a68 | 53 | h: "file-type-cheader", |
| 3c79a68 | 54 | yml: "file-type-yaml", |
| 3c79a68 | 55 | yaml: "file-type-yaml", |
| 3c79a68 | 56 | }; |
| 3c79a68 | 57 | |
| 3c79a68 | 58 | const FOLDER_TO_ICON = { |
| 3c79a68 | 59 | src: "folder-type-src", |
| 3c79a68 | 60 | test: "folder-type-test", |
| 3c79a68 | 61 | tests: "folder-type-test", |
| 3c79a68 | 62 | public: "folder-type-public", |
| 3c79a68 | 63 | images: "folder-type-images", |
| 3c79a68 | 64 | docs: "folder-type-docs", |
| 3c79a68 | 65 | dist: "folder-type-dist", |
| 3c79a68 | 66 | ".github": "folder-type-github", |
| 3c79a68 | 67 | node_modules: "folder-type-node", |
| 3c79a68 | 68 | }; |
| 3c79a68 | 69 | |
| 3931c4d | 70 | // Every icon id this module can ever emit, deduped — used to build the |
| 3931c4d | 71 | // sprite once rather than guessing which subset a given page needs. |
| 3931c4d | 72 | const ICON_NAMES = new Set([ |
| 3931c4d | 73 | ...Object.values(FILENAME_TO_ICON), |
| 3931c4d | 74 | ...Object.values(EXT_TO_ICON), |
| 3931c4d | 75 | ...Object.values(FOLDER_TO_ICON), |
| 3931c4d | 76 | "default-file", |
| 3931c4d | 77 | "default-folder", |
| 3931c4d | 78 | ]); |
| 3931c4d | 79 | |
| 3931c4d | 80 | /** |
| 1980b5c | 81 | * A <svg><symbol> sprite holding every file/folder icon this repo browser |
| 1980b5c | 82 | * can use, written once to assets/icons/sprite.svg (see eleventy.config.js) |
| 1980b5c | 83 | * rather than inlined per page. fileIcon()/folderIcon() emit a tiny <use> |
| 1980b5c | 84 | * that points at that shared file, so the ~30 icon bodies are fetched |
| 1980b5c | 85 | * (and cached by the browser) once for the whole site instead of being |
| 1980b5c | 86 | * duplicated in every one of the thousands of generated repo pages. |
| 3931c4d | 87 | */ |
| 3931c4d | 88 | export const iconSpriteDefs = () => { |
| 3931c4d | 89 | const symbols = [...ICON_NAMES] |
| 3931c4d | 90 | .map((name) => { |
| 3931c4d | 91 | const icon = iconSet.icons[name]; |
| 1980b5c | 92 | return `<symbol id="icon-${name}" viewBox="0 0 ${iconSet.width} ${iconSet.height}">${icon.body}</symbol>`; |
| 3931c4d | 93 | }) |
| 3931c4d | 94 | .join(""); |
| 1980b5c | 95 | return `<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true">${symbols}</svg>`; |
| 3c79a68 | 96 | }; |
| 3c79a68 | 97 | |
| 1980b5c | 98 | const useIcon = (name) => `<svg width="16" height="16"><use href="/assets/icons/sprite.svg#icon-${name}"></use></svg>`; |
| 3931c4d | 99 | |
| 3c79a68 | 100 | export const fileIcon = (filename, ext) => { |
| 3931c4d | 101 | const key = FILENAME_TO_ICON[filename.toLowerCase()] ?? EXT_TO_ICON[ext] ?? "default-file"; |
| 3931c4d | 102 | return useIcon(key); |
| 3c79a68 | 103 | }; |
| 3c79a68 | 104 | |
| 3c79a68 | 105 | export const folderIcon = (foldername) => { |
| 3931c4d | 106 | const key = FOLDER_TO_ICON[foldername.toLowerCase()] ?? "default-folder"; |
| 3931c4d | 107 | return useIcon(key); |
| 3c79a68 | 108 | }; |