website

#astro#js#html#css

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
};