From 249d88f405ffee0400dc5e4fcdb2b373dc77ac6e Mon Sep 17 00:00:00 2001 From: mawkone Date: Sun, 14 Jun 2026 12:59:07 -0700 Subject: [PATCH] feat(codebase): add file-type specific subtle colored icons to the file tree --- .../components/project/file-icons.tsx | 61 +++++++++++++++++++ .../components/project/gitea-file-tree.tsx | 7 +++ 2 files changed, 68 insertions(+) create mode 100644 vibn-frontend/components/project/file-icons.tsx diff --git a/vibn-frontend/components/project/file-icons.tsx b/vibn-frontend/components/project/file-icons.tsx new file mode 100644 index 00000000..5d0068f8 --- /dev/null +++ b/vibn-frontend/components/project/file-icons.tsx @@ -0,0 +1,61 @@ +import { + FileText, + Braces, + CodeXml, + TerminalSquare, + Info, + GitBranch, + Settings, + Image as ImageIcon, + Palette, + FileCode2, + FileJson, + FileBox, + Box, + Hash, + Database +} from "lucide-react"; + +export function getFileIconAndColor(filename: string) { + const name = filename.toLowerCase(); + + if (name.includes('package.json') || name.includes('package-lock.json') || name.endsWith('.json')) { + return { icon: Braces, color: "#eab308" }; // yellow + } + if (name.startsWith('.env')) { + return { icon: TerminalSquare, color: "#10b981" }; // green + } + if (name.endsWith('.html') || name.endsWith('.xml') || name.endsWith('.svg')) { + return { icon: CodeXml, color: "#f97316" }; // orange + } + if (name.endsWith('.md') || name.endsWith('.mdx') || name.endsWith('.txt')) { + return { icon: Info, color: "#3b82f6" }; // blue + } + if (name.endsWith('.ts') || name.endsWith('.tsx')) { + return { icon: FileCode2, color: "#3b82f6" }; // blue + } + if (name.endsWith('.js') || name.endsWith('.jsx') || name.endsWith('.mjs') || name.endsWith('.cjs')) { + return { icon: FileCode2, color: "#eab308" }; // yellow + } + if (name.endsWith('.css') || name.endsWith('.scss') || name.endsWith('.less') || name.includes('tailwind')) { + return { icon: Palette, color: "#ec4899" }; // pink + } + if (name.endsWith('.sh') || name === 'procfile' || name === 'dockerfile') { + return { icon: TerminalSquare, color: "#10b981" }; // green + } + if (name.endsWith('.yml') || name.endsWith('.yaml') || name.includes('config')) { + return { icon: Settings, color: "#8b5cf6" }; // purple + } + if (name.includes('.git') || name.endsWith('ignore')) { + return { icon: GitBranch, color: "#6b7280" }; // gray + } + if (name.match(/\.(jpg|jpeg|png|gif|webp|ico)$/)) { + return { icon: ImageIcon, color: "#14b8a6" }; // teal + } + if (name.endsWith('.sql') || name.endsWith('.sqlite') || name.endsWith('.db')) { + return { icon: Database, color: "#6366f1" }; // indigo + } + + // Default + return { icon: FileText, color: "#9ca3af" }; // gray-400 +} diff --git a/vibn-frontend/components/project/gitea-file-tree.tsx b/vibn-frontend/components/project/gitea-file-tree.tsx index 8f8c9726..9084f64b 100644 --- a/vibn-frontend/components/project/gitea-file-tree.tsx +++ b/vibn-frontend/components/project/gitea-file-tree.tsx @@ -13,6 +13,7 @@ import { useEffect, useState, useCallback } from "react"; import { Loader2, AlertCircle } from "lucide-react"; import { Tree, Folder, File } from "@/components/ui/file-tree"; import { THEME } from "@/components/project/dashboard-ui"; +import { getFileIconAndColor } from "@/components/project/file-icons"; interface TreeItem { name: string; @@ -240,6 +241,9 @@ export function GiteaFileTree({ ); } + + const { icon: FileIconComponent, color } = getFileIconAndColor(item.name); + return ( onSelectFile?.(item.path)} isSelectable={!!onSelectFile} isSelect={selectedPath === item.path} + fileIcon={ + + } > {item.name}