|
15 | 15 | exts: new Set(['exe', 'dll', 'so', 'class', 'pyc', 'png', 'jpg', 'jpeg', 'gif', 'svg', 'mp4', 'mp3', 'wav', 'zip', 'tar', 'gz', 'rar']) |
16 | 16 | }; |
17 | 17 |
|
| 18 | + // VS Code Material Icon Theme - Professional file icons |
18 | 19 | const ICONS = { |
19 | | - js: { i: 'javascript', c: '#f1e05a' }, jsx: { i: 'javascript', c: '#f1e05a' }, |
20 | | - ts: { i: 'code', c: '#3178c6' }, tsx: { i: 'code', c: '#3178c6' }, |
21 | | - py: { i: 'code', c: '#3776ab' }, html: { i: 'html', c: '#e34c26' }, |
22 | | - css: { i: 'css', c: '#563d7c' }, json: { i: 'data_object', c: '#cb171e' }, |
23 | | - md: { i: 'article', c: '#fff' } |
| 20 | + // JavaScript |
| 21 | + js: { icon: 'javascript.svg', color: '#f1e05a' }, |
| 22 | + jsx: { icon: 'react.svg', color: '#61dafb' }, |
| 23 | + mjs: { icon: 'javascript.svg', color: '#f1e05a' }, |
| 24 | + |
| 25 | + // TypeScript |
| 26 | + ts: { icon: 'typescript.svg', color: '#3178c6' }, |
| 27 | + tsx: { icon: 'react_ts.svg', color: '#3178c6' }, |
| 28 | + |
| 29 | + // Python |
| 30 | + py: { icon: 'python.svg', color: '#3776ab' }, |
| 31 | + pyc: { icon: 'python-misc.svg', color: '#3776ab' }, |
| 32 | + |
| 33 | + // Web |
| 34 | + html: { icon: 'html.svg', color: '#e34c26' }, |
| 35 | + htm: { icon: 'html.svg', color: '#e34c26' }, |
| 36 | + css: { icon: 'css.svg', color: '#563d7c' }, |
| 37 | + scss: { icon: 'sass.svg', color: '#c6538c' }, |
| 38 | + sass: { icon: 'sass.svg', color: '#c6538c' }, |
| 39 | + less: { icon: 'less.svg', color: '#1d365d' }, |
| 40 | + |
| 41 | + // Data |
| 42 | + json: { icon: 'json.svg', color: '#cbcb41' }, |
| 43 | + xml: { icon: 'xml.svg', color: '#ff6600' }, |
| 44 | + yaml: { icon: 'yaml.svg', color: '#cb171e' }, |
| 45 | + yml: { icon: 'yaml.svg', color: '#cb171e' }, |
| 46 | + toml: { icon: 'toml.svg', color: '#9c4221' }, |
| 47 | + |
| 48 | + // Documentation |
| 49 | + md: { icon: 'markdown.svg', color: '#083fa1' }, |
| 50 | + mdx: { icon: 'mdx.svg', color: '#fcb32c' }, |
| 51 | + txt: { icon: 'document.svg', color: '#a0a0a0' }, |
| 52 | + |
| 53 | + // Config |
| 54 | + gitignore: { icon: 'git.svg', color: '#f34f29' }, |
| 55 | + env: { icon: 'tune.svg', color: '#e7c547' }, |
| 56 | + config: { icon: 'settings.svg', color: '#6d8086' }, |
| 57 | + |
| 58 | + // Java |
| 59 | + java: { icon: 'java.svg', color: '#b07219' }, |
| 60 | + class: { icon: 'javaclass.svg', color: '#b07219' }, |
| 61 | + jar: { icon: 'jar.svg', color: '#b07219' }, |
| 62 | + |
| 63 | + // C/C++ |
| 64 | + c: { icon: 'c.svg', color: '#555555' }, |
| 65 | + cpp: { icon: 'cpp.svg', color: '#f34b7d' }, |
| 66 | + h: { icon: 'h.svg', color: '#555555' }, |
| 67 | + hpp: { icon: 'hpp.svg', color: '#f34b7d' }, |
| 68 | + |
| 69 | + // PHP |
| 70 | + php: { icon: 'php.svg', color: '#4f5d95' }, |
| 71 | + |
| 72 | + // Ruby |
| 73 | + rb: { icon: 'ruby.svg', color: '#701516' }, |
| 74 | + |
| 75 | + // Go |
| 76 | + go: { icon: 'go.svg', color: '#00add8' }, |
| 77 | + |
| 78 | + // Rust |
| 79 | + rs: { icon: 'rust.svg', color: '#dea584' }, |
| 80 | + |
| 81 | + // Shell |
| 82 | + sh: { icon: 'shell.svg', color: '#89e051' }, |
| 83 | + bash: { icon: 'shell.svg', color: '#89e051' }, |
| 84 | + zsh: { icon: 'shell.svg', color: '#89e051' }, |
| 85 | + |
| 86 | + // Docker |
| 87 | + dockerfile: { icon: 'docker.svg', color: '#0db7ed' }, |
| 88 | + |
| 89 | + // Images |
| 90 | + png: { icon: 'image.svg', color: '#a074c4' }, |
| 91 | + jpg: { icon: 'image.svg', color: '#a074c4' }, |
| 92 | + jpeg: { icon: 'image.svg', color: '#a074c4' }, |
| 93 | + gif: { icon: 'image.svg', color: '#a074c4' }, |
| 94 | + svg: { icon: 'svg.svg', color: '#ffb13b' }, |
| 95 | + ico: { icon: 'image.svg', color: '#a074c4' }, |
| 96 | + webp: { icon: 'image.svg', color: '#a074c4' }, |
| 97 | + |
| 98 | + // Vue/Angular/React |
| 99 | + vue: { icon: 'vue.svg', color: '#42b883' }, |
| 100 | + |
| 101 | + // Others |
| 102 | + sql: { icon: 'database.svg', color: '#e38c00' }, |
| 103 | + pdf: { icon: 'pdf.svg', color: '#f40f02' }, |
| 104 | + zip: { icon: 'zip.svg', color: '#f9dc5c' }, |
| 105 | + |
| 106 | + // Default |
| 107 | + default: { icon: 'document.svg', color: '#a0a0a0' } |
24 | 108 | }; |
25 | 109 |
|
| 110 | + // Special folder types |
| 111 | + const FOLDER_ICONS = { |
| 112 | + 'node_modules': { icon: 'folder-node.svg', color: '#8cc84b' }, |
| 113 | + 'src': { icon: 'folder-src.svg', color: '#f0eee6' }, |
| 114 | + 'dist': { icon: 'folder-dist.svg', color: '#f0eee6' }, |
| 115 | + 'build': { icon: 'folder-build.svg', color: '#f0eee6' }, |
| 116 | + 'public': { icon: 'folder-public.svg', color: '#f0eee6' }, |
| 117 | + 'assets': { icon: 'folder-images.svg', color: '#f0eee6' }, |
| 118 | + 'images': { icon: 'folder-images.svg', color: '#f0eee6' }, |
| 119 | + 'img': { icon: 'folder-images.svg', color: '#f0eee6' }, |
| 120 | + 'components': { icon: 'folder-component.svg', color: '#f0eee6' }, |
| 121 | + 'pages': { icon: 'folder-views.svg', color: '#f0eee6' }, |
| 122 | + 'views': { icon: 'folder-views.svg', color: '#f0eee6' }, |
| 123 | + 'tests': { icon: 'folder-test.svg', color: '#f0eee6' }, |
| 124 | + 'test': { icon: 'folder-test.svg', color: '#f0eee6' }, |
| 125 | + '__tests__': { icon: 'folder-test.svg', color: '#f0eee6' }, |
| 126 | + 'utils': { icon: 'folder-helper.svg', color: '#f0eee6' }, |
| 127 | + 'helpers': { icon: 'folder-helper.svg', color: '#f0eee6' }, |
| 128 | + 'lib': { icon: 'folder-lib.svg', color: '#f0eee6' }, |
| 129 | + 'config': { icon: 'folder-config.svg', color: '#f0eee6' }, |
| 130 | + '.git': { icon: 'folder-git.svg', color: '#f34f29' }, |
| 131 | + '.vscode': { icon: 'folder-vscode.svg', color: '#007acc' }, |
| 132 | + 'default': { icon: 'folder.svg', color: '#dcb67a' } |
| 133 | + }; |
| 134 | + |
| 135 | + const ICON_BASE_URL = 'https://raw.githack.com/PKief/vscode-material-icon-theme/main/icons/'; |
| 136 | + |
26 | 137 | const MAX_RENDER = 1000; // Max items to render at once |
27 | 138 | const BATCH = 50; // Files to process per batch |
28 | 139 |
|
|
80 | 191 |
|
81 | 192 | const ign = p => { const pts = p.split('/'); if (pts.some(x => IGNORED.folders.has(x))) return true; const e = pts[pts.length - 1].split('.').pop().toLowerCase(); return IGNORED.exts.has(e); }; |
82 | 193 |
|
83 | | - const ico = (n, f) => { if (f) return { i: 'folder', c: '#e3dacc', cls: 'folder-icon' }; const e = n.split('.').pop().toLowerCase(); const ic = ICONS[e] || { i: 'description', c: '#888' }; return { ...ic, cls: `${e}-icon` }; }; |
| 194 | + // Get icon for file or folder |
| 195 | + const ico = (name, isFolder) => { |
| 196 | + if (isFolder) { |
| 197 | + // Check for special folder names |
| 198 | + const folderName = name.toLowerCase(); |
| 199 | + const folderIcon = FOLDER_ICONS[folderName] || FOLDER_ICONS['default']; |
| 200 | + return { |
| 201 | + type: 'svg', |
| 202 | + url: ICON_BASE_URL + folderIcon.icon, |
| 203 | + color: folderIcon.color, |
| 204 | + cls: 'folder-icon' |
| 205 | + }; |
| 206 | + } |
| 207 | + |
| 208 | + // File icon |
| 209 | + const fileName = name.toLowerCase(); |
| 210 | + |
| 211 | + // Check for special filenames (like .gitignore, dockerfile, etc.) |
| 212 | + if (fileName === '.gitignore' || fileName === '.gitattributes') { |
| 213 | + return { |
| 214 | + type: 'svg', |
| 215 | + url: ICON_BASE_URL + 'git.svg', |
| 216 | + color: '#f34f29', |
| 217 | + cls: 'git-icon' |
| 218 | + }; |
| 219 | + } |
| 220 | + |
| 221 | + if (fileName === 'dockerfile' || fileName.startsWith('dockerfile.')) { |
| 222 | + return { |
| 223 | + type: 'svg', |
| 224 | + url: ICON_BASE_URL + 'docker.svg', |
| 225 | + color: '#0db7ed', |
| 226 | + cls: 'docker-icon' |
| 227 | + }; |
| 228 | + } |
| 229 | + |
| 230 | + if (fileName.startsWith('.env')) { |
| 231 | + return { |
| 232 | + type: 'svg', |
| 233 | + url: ICON_BASE_URL + 'tune.svg', |
| 234 | + color: '#e7c547', |
| 235 | + cls: 'env-icon' |
| 236 | + }; |
| 237 | + } |
| 238 | + |
| 239 | + if (fileName === 'package.json') { |
| 240 | + return { |
| 241 | + type: 'svg', |
| 242 | + url: ICON_BASE_URL + 'nodejs.svg', |
| 243 | + color: '#8cc84b', |
| 244 | + cls: 'nodejs-icon' |
| 245 | + }; |
| 246 | + } |
| 247 | + |
| 248 | + if (fileName === 'readme.md' || fileName === 'readme') { |
| 249 | + return { |
| 250 | + type: 'svg', |
| 251 | + url: ICON_BASE_URL + 'readme.svg', |
| 252 | + color: '#4caf50', |
| 253 | + cls: 'readme-icon' |
| 254 | + }; |
| 255 | + } |
| 256 | + |
| 257 | + // Get by extension |
| 258 | + const ext = name.split('.').pop().toLowerCase(); |
| 259 | + const iconData = ICONS[ext] || ICONS['default']; |
| 260 | + |
| 261 | + return { |
| 262 | + type: 'svg', |
| 263 | + url: ICON_BASE_URL + iconData.icon, |
| 264 | + color: iconData.color, |
| 265 | + cls: `${ext}-icon` |
| 266 | + }; |
| 267 | + }; |
84 | 268 |
|
85 | 269 | const esc = s => s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); |
86 | 270 |
|
|
237 | 421 | <span class="material-symbols-outlined">chevron_right</span> |
238 | 422 | </button> |
239 | 423 | <div class="file-icon ${ic.cls}"> |
240 | | - <span class="material-symbols-outlined" style="color:${ic.c}">${ic.i}</span> |
| 424 | + <img src="${ic.url}" alt="${nd.n}" class="vscode-icon" onerror="this.style.display='none'" /> |
241 | 425 | </div> |
242 | 426 | <label class="file-label"> |
243 | 427 | <input type="checkbox" class="file-checkbox" data-path="${nd.full}" ${nd.ig ? 'disabled' : 'checked'}> |
|
0 commit comments