| import catppuccinIcons from "@iconify-json/catppuccin/icons.json"; |
| import { EXT_TO_LANGUAGE_ID } from "./constants"; |
| import * as fileIconsMod from "./fileIcons"; |
| import * as folderIconsMod from "./folderIcons"; |
|
|
| const catFileNames = fileIconsMod.fileNames as Record<string, string>; |
| const catFileExtensions = fileIconsMod.fileExtensions as Record<string, string>; |
| const catLanguageIds = fileIconsMod.languageIds as Record<string, string>; |
| const catFolderNames = folderIconsMod.folderNames as Record<string, string>; |
|
|
| type IconifySet = { |
| icons: Record<string, { body: string }>; |
| aliases?: Record<string, { parent: string }>; |
| width?: number; |
| height?: number; |
| }; |
|
|
| const cat = catppuccinIcons as unknown as IconifySet; |
| const CAT_W = cat.width ?? 16; |
| const CAT_H = cat.height ?? 16; |
|
|
| const DEFAULT_FILE = "file"; |
| const DEFAULT_FOLDER = "folder"; |
| const DEFAULT_FOLDER_OPEN = "folder-open"; |
|
|
| const dataUrlCache = new Map<string, string>(); |
|
|
| |
| |
| function toIconifySlug(name: string): string { |
| return name.replace(/_/g, "-"); |
| } |
|
|
| function catBody(iconName: string): string | null { |
| const slug = toIconifySlug(iconName); |
| const direct = cat.icons[slug]; |
| if (direct) return direct.body; |
| const alias = cat.aliases?.[slug]; |
| if (alias) { |
| const parent = cat.icons[alias.parent]; |
| if (parent) return parent.body; |
| } |
| return null; |
| } |
|
|
| function buildDataUrl(iconName: string): string | null { |
| const cached = dataUrlCache.get(iconName); |
| if (cached !== undefined) return cached || null; |
| const body = catBody(iconName); |
| if (!body) { |
| dataUrlCache.set(iconName, ""); |
| return null; |
| } |
| const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${CAT_W} ${CAT_H}">${body}</svg>`; |
| const url = `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`; |
| dataUrlCache.set(iconName, url); |
| return url; |
| } |
|
|
| function extOf(name: string): string { |
| const lower = name.toLowerCase(); |
| const dot = lower.indexOf("."); |
| if (dot === -1 || dot === lower.length - 1) return ""; |
| return lower.slice(dot + 1); |
| } |
|
|
| export function fileIconUrl(name: string): string { |
| const lower = name.toLowerCase(); |
|
|
| const byName = catFileNames[lower]; |
| if (byName) { |
| const url = buildDataUrl(byName); |
| if (url) return url; |
| } |
|
|
| let ext = extOf(lower); |
| while (ext) { |
| const iconName = catFileExtensions[ext]; |
| if (iconName) { |
| const url = buildDataUrl(iconName); |
| if (url) return url; |
| } |
| const langId = EXT_TO_LANGUAGE_ID[ext]; |
| if (langId) { |
| const iconByLang = catLanguageIds[langId]; |
| if (iconByLang) { |
| const url = buildDataUrl(iconByLang); |
| if (url) return url; |
| } |
| } |
| const nextDot = ext.indexOf("."); |
| if (nextDot === -1) break; |
| ext = ext.slice(nextDot + 1); |
| } |
|
|
| return buildDataUrl(DEFAULT_FILE) ?? ""; |
| } |
|
|
| export function folderIconUrl(name: string, expanded: boolean): string { |
| const lower = name.toLowerCase(); |
|
|
| const mapped = catFolderNames[lower]; |
| if (mapped) { |
| const slug = toIconifySlug(mapped); |
| const target = expanded ? `${slug}-open` : slug; |
| const url = buildDataUrl(target); |
| if (url) return url; |
| } |
|
|
| return buildDataUrl(expanded ? DEFAULT_FOLDER_OPEN : DEFAULT_FOLDER) ?? ""; |
| } |
|
|