feat(FileTree): 为文件树节点添加类型化图标和颜色
- 使用 `#icon` 插槽为树节点添加自定义图标组件 - 重构图标和颜色逻辑,使用 `FILE_TYPE_CONFIG` 对象集中管理文件类型配置 - 为文件夹添加展开/收起状态的不同图标,并使用黄色区分 - 调整树节点标题的字体大小和行高以改善视觉一致性
This commit is contained in:
parent
495a8a0bb4
commit
7b200dcb68
|
|
@ -42,6 +42,12 @@
|
|||
:load-data="onLoadData"
|
||||
@select="onSelect"
|
||||
>
|
||||
<template #icon="{ dataRef, expanded }">
|
||||
<component
|
||||
:is="getFileIcon(dataRef.name, dataRef.type, expanded)"
|
||||
:style="{ color: getFileIconColor(dataRef.name, dataRef.type), fontSize: '18px', marginRight: '6px' }"
|
||||
/>
|
||||
</template>
|
||||
<template #title="{ dataRef }">
|
||||
<a-dropdown :trigger="['contextmenu']">
|
||||
<span class="tree-node-title" :title="dataRef.name">{{ dataRef.name }}</span>
|
||||
|
|
@ -90,7 +96,20 @@
|
|||
|
||||
<script setup>
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { EyeInvisibleOutlined, EyeOutlined, ReloadOutlined, SearchOutlined } from '@ant-design/icons-vue';
|
||||
import {
|
||||
EyeInvisibleOutlined,
|
||||
EyeOutlined,
|
||||
ReloadOutlined,
|
||||
SearchOutlined,
|
||||
FileOutlined,
|
||||
FileMarkdownOutlined,
|
||||
FileImageOutlined,
|
||||
FilePdfOutlined,
|
||||
CodeOutlined,
|
||||
FileTextOutlined,
|
||||
FolderFilled,
|
||||
FolderOpenFilled
|
||||
} from '@ant-design/icons-vue';
|
||||
import { useFileTree } from '../composables/useFileTree';
|
||||
import { useTabs } from '../composables/useTabs';
|
||||
import { useConfig } from '../composables/useConfig';
|
||||
|
|
@ -189,71 +208,51 @@ const onSelect = (keys, { node }) => {
|
|||
|
||||
const isMdFile = (name) => name && name.toLowerCase().endsWith('.md');
|
||||
|
||||
const getFileIcon = (fileName) => {
|
||||
if (!fileName) return FileOutlined;
|
||||
const ext = fileName.split('.').pop().toLowerCase();
|
||||
switch (ext) {
|
||||
case 'md':
|
||||
case 'markdown':
|
||||
return FileMarkdownOutlined;
|
||||
case 'png':
|
||||
case 'jpg':
|
||||
case 'jpeg':
|
||||
case 'gif':
|
||||
case 'webp':
|
||||
case 'svg':
|
||||
case 'ico':
|
||||
return FileImageOutlined;
|
||||
case 'pdf':
|
||||
return FilePdfOutlined;
|
||||
case 'js':
|
||||
case 'json':
|
||||
case 'ts':
|
||||
case 'css':
|
||||
case 'html':
|
||||
case 'vue':
|
||||
case 'xml':
|
||||
case 'yaml':
|
||||
case 'yml':
|
||||
return CodeOutlined;
|
||||
case 'txt':
|
||||
case 'log':
|
||||
return FileTextOutlined;
|
||||
default:
|
||||
return FileOutlined;
|
||||
}
|
||||
const FILE_TYPE_CONFIG = {
|
||||
md: { icon: FileMarkdownOutlined, color: '#1890ff' },
|
||||
markdown: { icon: FileMarkdownOutlined, color: '#1890ff' },
|
||||
png: { icon: FileImageOutlined, color: '#722ed1' },
|
||||
jpg: { icon: FileImageOutlined, color: '#722ed1' },
|
||||
jpeg: { icon: FileImageOutlined, color: '#722ed1' },
|
||||
gif: { icon: FileImageOutlined, color: '#722ed1' },
|
||||
webp: { icon: FileImageOutlined, color: '#722ed1' },
|
||||
svg: { icon: FileImageOutlined, color: '#722ed1' },
|
||||
ico: { icon: FileImageOutlined, color: '#722ed1' },
|
||||
pdf: { icon: FilePdfOutlined, color: '#f5222d' },
|
||||
js: { icon: CodeOutlined, color: '#52c41a' },
|
||||
json: { icon: CodeOutlined, color: '#52c41a' },
|
||||
ts: { icon: CodeOutlined, color: '#52c41a' },
|
||||
css: { icon: CodeOutlined, color: '#52c41a' },
|
||||
html: { icon: CodeOutlined, color: '#52c41a' },
|
||||
vue: { icon: CodeOutlined, color: '#52c41a' },
|
||||
xml: { icon: CodeOutlined, color: '#52c41a' },
|
||||
yaml: { icon: CodeOutlined, color: '#52c41a' },
|
||||
yml: { icon: CodeOutlined, color: '#52c41a' },
|
||||
txt: { icon: FileTextOutlined, color: 'inherit' },
|
||||
log: { icon: FileTextOutlined, color: 'inherit' },
|
||||
};
|
||||
|
||||
const getFileIconColor = (fileName) => {
|
||||
if (!fileName) return 'inherit';
|
||||
const ext = fileName.split('.').pop().toLowerCase();
|
||||
switch (ext) {
|
||||
case 'md':
|
||||
case 'markdown':
|
||||
return '#1890ff';
|
||||
case 'png':
|
||||
case 'jpg':
|
||||
case 'jpeg':
|
||||
case 'gif':
|
||||
case 'webp':
|
||||
case 'svg':
|
||||
case 'ico':
|
||||
return '#722ed1';
|
||||
case 'pdf':
|
||||
return '#f5222d';
|
||||
case 'js':
|
||||
case 'json':
|
||||
case 'ts':
|
||||
case 'css':
|
||||
case 'html':
|
||||
case 'vue':
|
||||
case 'xml':
|
||||
case 'yaml':
|
||||
case 'yml':
|
||||
return '#52c41a';
|
||||
default:
|
||||
return 'inherit';
|
||||
const getFileExtension = (fileName) => {
|
||||
if (!fileName) return '';
|
||||
const lastDotIndex = fileName.lastIndexOf('.');
|
||||
if (lastDotIndex === -1 || lastDotIndex === 0) return '';
|
||||
return fileName.substring(lastDotIndex + 1).toLowerCase();
|
||||
};
|
||||
|
||||
const getFileIcon = (fileName, type, expanded) => {
|
||||
if (type === 'directory') {
|
||||
return expanded ? FolderOpenFilled : FolderFilled;
|
||||
}
|
||||
const ext = getFileExtension(fileName);
|
||||
return FILE_TYPE_CONFIG[ext]?.icon || FileOutlined;
|
||||
};
|
||||
|
||||
const getFileIconColor = (fileName, type) => {
|
||||
if (type === 'directory') {
|
||||
return '#ffc60a'; // 文件夹黄色
|
||||
}
|
||||
const ext = getFileExtension(fileName);
|
||||
return FILE_TYPE_CONFIG[ext]?.color || 'inherit';
|
||||
};
|
||||
|
||||
const isPinned = (path) => config.pinnedFiles.includes(path);
|
||||
|
|
@ -431,13 +430,15 @@ const handleModalOk = async () => {
|
|||
flex: 1; /* 让文字占满剩余空间 */
|
||||
min-width: 0; /* 关键:允许在 flex 容器中收缩,从而触发省略号 */
|
||||
margin-left: 4px; /* spacing between icon and text */
|
||||
font-size: 16px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
:deep(.ant-tree-node-content-wrapper) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
min-height: 28px; /* improve touch target / spacing */
|
||||
min-height: 32px; /* improve touch target / spacing */
|
||||
padding: 0 4px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
|
|
|||
Loading…
Reference in New Issue