agent-ecosystem/src/renderer/components/team/editor/fileIcons.ts
iliya cb8017b0db feat: enhance file icon handling and keyboard shortcuts
- Introduced a new FileIcon component to render file-type icons with support for Devicon CDN and fallback to lucide-react icons.
- Added a glow effect for file icons in dark mode to improve visibility.
- Updated various components to utilize the new FileIcon component for consistent icon rendering.
- Refined keyboard shortcut handling to use event.code for layout-independent key detection, improving cross-platform compatibility.
- Enhanced the EditorTabBar with a context menu for tab management, including options to close tabs and manage open files more efficiently.
2026-03-01 14:24:24 +02:00

222 lines
9.6 KiB
TypeScript

/**
* File icon mapping — maps file extensions/names to icon info.
*
* For programming languages and dev tools, uses Devicon CDN SVGs (colorful logos).
* For generic file types (images, fonts, configs), falls back to lucide-react icons.
*/
import {
Braces,
Code,
Database,
File,
FileJson,
FileText,
FileType,
Image,
Lock,
Settings,
Terminal,
} from 'lucide-react';
import type { LucideIcon } from 'lucide-react';
// =============================================================================
// Types
// =============================================================================
export interface FileIconInfo {
icon: LucideIcon;
color: string;
/** Devicon slug — when set, FileIcon component renders the real logo from CDN */
deviconSlug?: string;
}
// =============================================================================
// Devicon CDN
// =============================================================================
const DEVICON_BASE = 'https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons';
/**
* Build Devicon CDN URL for a given slug.
* Uses `-original` variant (colorful) with `-wordmark` fallback.
*/
export function getDeviconUrl(slug: string): string {
return `${DEVICON_BASE}/${slug}/${slug}-original.svg`;
}
// =============================================================================
// Extension → Icon mapping
// =============================================================================
const EXTENSION_MAP: Record<string, FileIconInfo> = {
// TypeScript / JavaScript
ts: { icon: Code, color: '#3178c6', deviconSlug: 'typescript' },
tsx: { icon: Code, color: '#3178c6', deviconSlug: 'react' },
js: { icon: Code, color: '#f7df1e', deviconSlug: 'javascript' },
jsx: { icon: Code, color: '#61dafb', deviconSlug: 'react' },
mjs: { icon: Code, color: '#f7df1e', deviconSlug: 'javascript' },
cjs: { icon: Code, color: '#f7df1e', deviconSlug: 'javascript' },
// Web
html: { icon: Code, color: '#e34c26', deviconSlug: 'html5' },
htm: { icon: Code, color: '#e34c26', deviconSlug: 'html5' },
css: { icon: Code, color: '#1572b6', deviconSlug: 'css3' },
scss: { icon: Code, color: '#c6538c', deviconSlug: 'sass' },
less: { icon: Code, color: '#1d365d', deviconSlug: 'less' },
vue: { icon: Code, color: '#42b883', deviconSlug: 'vuejs' },
svelte: { icon: Code, color: '#ff3e00', deviconSlug: 'svelte' },
// Data / Config (no devicon — lucide fallbacks)
json: { icon: FileJson, color: '#cbcb41', deviconSlug: 'json' },
jsonl: { icon: FileJson, color: '#cbcb41' },
yaml: { icon: Settings, color: '#cb171e', deviconSlug: 'yaml' },
yml: { icon: Settings, color: '#cb171e', deviconSlug: 'yaml' },
toml: { icon: Settings, color: '#9c4121' },
xml: { icon: Code, color: '#e37933', deviconSlug: 'xml' },
csv: { icon: Database, color: '#4caf50' },
// Markdown / Text
md: { icon: FileText, color: '#519aba', deviconSlug: 'markdown' },
mdx: { icon: FileText, color: '#519aba', deviconSlug: 'markdown' },
txt: { icon: FileText, color: '#89949f' },
rst: { icon: FileText, color: '#89949f' },
// Python
py: { icon: Code, color: '#3572a5', deviconSlug: 'python' },
pyx: { icon: Code, color: '#3572a5', deviconSlug: 'python' },
pyi: { icon: Code, color: '#3572a5', deviconSlug: 'python' },
// Rust
rs: { icon: Code, color: '#dea584', deviconSlug: 'rust' },
// Go
go: { icon: Code, color: '#00add8', deviconSlug: 'go' },
// Ruby
rb: { icon: Code, color: '#cc342d', deviconSlug: 'ruby' },
gemspec: { icon: Code, color: '#cc342d', deviconSlug: 'ruby' },
// Java / Kotlin
java: { icon: Code, color: '#b07219', deviconSlug: 'java' },
kt: { icon: Code, color: '#a97bff', deviconSlug: 'kotlin' },
kts: { icon: Code, color: '#a97bff', deviconSlug: 'kotlin' },
// C / C++ / C#
c: { icon: Code, color: '#555555', deviconSlug: 'c' },
h: { icon: Code, color: '#555555', deviconSlug: 'c' },
cpp: { icon: Code, color: '#f34b7d', deviconSlug: 'cplusplus' },
hpp: { icon: Code, color: '#f34b7d', deviconSlug: 'cplusplus' },
cc: { icon: Code, color: '#f34b7d', deviconSlug: 'cplusplus' },
cs: { icon: Code, color: '#178600', deviconSlug: 'csharp' },
// Shell
sh: { icon: Terminal, color: '#89e051', deviconSlug: 'bash' },
bash: { icon: Terminal, color: '#89e051', deviconSlug: 'bash' },
zsh: { icon: Terminal, color: '#89e051', deviconSlug: 'bash' },
fish: { icon: Terminal, color: '#89e051' },
// SQL
sql: { icon: Database, color: '#e38c00', deviconSlug: 'azuresqldatabase' },
// Images (no devicon — lucide Image icon)
png: { icon: Image, color: '#a074c4' },
jpg: { icon: Image, color: '#a074c4' },
jpeg: { icon: Image, color: '#a074c4' },
gif: { icon: Image, color: '#a074c4' },
svg: { icon: Image, color: '#ffb13b' },
ico: { icon: Image, color: '#a074c4' },
webp: { icon: Image, color: '#a074c4' },
// Fonts (no devicon — lucide FileType icon)
woff: { icon: FileType, color: '#89949f' },
woff2: { icon: FileType, color: '#89949f' },
ttf: { icon: FileType, color: '#89949f' },
otf: { icon: FileType, color: '#89949f' },
// Config files (no devicon — lucide icons)
env: { icon: Lock, color: '#e5a00d' },
ini: { icon: Settings, color: '#89949f' },
conf: { icon: Settings, color: '#89949f' },
cfg: { icon: Settings, color: '#89949f' },
// Other languages
graphql: { icon: Braces, color: '#e535ab', deviconSlug: 'graphql' },
gql: { icon: Braces, color: '#e535ab', deviconSlug: 'graphql' },
proto: { icon: Code, color: '#89949f', deviconSlug: 'protobuf' },
dart: { icon: Code, color: '#00b4ab', deviconSlug: 'dart' },
swift: { icon: Code, color: '#f05138', deviconSlug: 'swift' },
php: { icon: Code, color: '#4f5d95', deviconSlug: 'php' },
r: { icon: Code, color: '#276dc3', deviconSlug: 'r' },
lua: { icon: Code, color: '#000080', deviconSlug: 'lua' },
pl: { icon: Code, color: '#39457e', deviconSlug: 'perl' },
scala: { icon: Code, color: '#dc322f', deviconSlug: 'scala' },
groovy: { icon: Code, color: '#4298b8', deviconSlug: 'groovy' },
ex: { icon: Code, color: '#6e4a7e', deviconSlug: 'elixir' },
exs: { icon: Code, color: '#6e4a7e', deviconSlug: 'elixir' },
erl: { icon: Code, color: '#b83998', deviconSlug: 'erlang' },
hs: { icon: Code, color: '#5e5086', deviconSlug: 'haskell' },
clj: { icon: Code, color: '#db5855', deviconSlug: 'clojure' },
fs: { icon: Code, color: '#b845fc', deviconSlug: 'fsharp' },
zig: { icon: Code, color: '#f7a41d', deviconSlug: 'zig' },
nim: { icon: Code, color: '#ffc200', deviconSlug: 'nimble' },
tf: { icon: Code, color: '#7b42bc', deviconSlug: 'terraform' },
hcl: { icon: Code, color: '#7b42bc', deviconSlug: 'terraform' },
};
// Special full filename mapping
const FILENAME_MAP: Record<string, FileIconInfo> = {
Dockerfile: { icon: Code, color: '#2496ed', deviconSlug: 'docker' },
'docker-compose.yml': { icon: Code, color: '#2496ed', deviconSlug: 'docker' },
'docker-compose.yaml': { icon: Code, color: '#2496ed', deviconSlug: 'docker' },
Makefile: { icon: Terminal, color: '#427819' },
Rakefile: { icon: Terminal, color: '#cc342d', deviconSlug: 'ruby' },
Gemfile: { icon: Code, color: '#cc342d', deviconSlug: 'ruby' },
'.gitignore': { icon: Settings, color: '#f05032', deviconSlug: 'git' },
'.gitattributes': { icon: Settings, color: '#f05032', deviconSlug: 'git' },
'.eslintrc': { icon: Settings, color: '#4b32c3', deviconSlug: 'eslint' },
'.prettierrc': { icon: Settings, color: '#56b3b4' },
'tsconfig.json': { icon: Settings, color: '#3178c6', deviconSlug: 'typescript' },
'package.json': { icon: FileJson, color: '#cb3837', deviconSlug: 'nodejs' },
'pnpm-lock.yaml': { icon: Lock, color: '#f69220' },
'package-lock.json': { icon: Lock, color: '#cb3837', deviconSlug: 'npm' },
'yarn.lock': { icon: Lock, color: '#2c8ebb', deviconSlug: 'yarn' },
LICENSE: { icon: FileText, color: '#d9b611' },
'CLAUDE.md': { icon: FileText, color: '#d97706' },
'Cargo.toml': { icon: Settings, color: '#dea584', deviconSlug: 'rust' },
'go.mod': { icon: Settings, color: '#00add8', deviconSlug: 'go' },
'go.sum': { icon: Lock, color: '#00add8', deviconSlug: 'go' },
'.dockerignore': { icon: Settings, color: '#2496ed', deviconSlug: 'docker' },
'vite.config.ts': { icon: Settings, color: '#646cff', deviconSlug: 'vitejs' },
'vite.config.js': { icon: Settings, color: '#646cff', deviconSlug: 'vitejs' },
'webpack.config.js': { icon: Settings, color: '#8dd6f9', deviconSlug: 'webpack' },
'webpack.config.ts': { icon: Settings, color: '#8dd6f9', deviconSlug: 'webpack' },
'.babelrc': { icon: Settings, color: '#f5da55', deviconSlug: 'babel' },
'babel.config.js': { icon: Settings, color: '#f5da55', deviconSlug: 'babel' },
'tailwind.config.js': { icon: Settings, color: '#06b6d4', deviconSlug: 'tailwindcss' },
'tailwind.config.ts': { icon: Settings, color: '#06b6d4', deviconSlug: 'tailwindcss' },
'next.config.js': { icon: Settings, color: '#000000', deviconSlug: 'nextjs' },
'next.config.mjs': { icon: Settings, color: '#000000', deviconSlug: 'nextjs' },
'nuxt.config.ts': { icon: Settings, color: '#00dc82', deviconSlug: 'nuxtjs' },
};
const DEFAULT_ICON: FileIconInfo = { icon: File, color: '#89949f' };
// =============================================================================
// Public API
// =============================================================================
/**
* Get icon info for a file by name.
*/
export function getFileIcon(fileName: string): FileIconInfo {
// Check full filename first
if (FILENAME_MAP[fileName]) return FILENAME_MAP[fileName];
// Check extension
const ext = fileName.includes('.') ? fileName.split('.').pop()?.toLowerCase() : undefined;
if (ext && EXTENSION_MAP[ext]) return EXTENSION_MAP[ext];
return DEFAULT_ICON;
}