updata:icon替换

This commit is contained in:
xiaozhu
2026-09-02 10:10:41 +08:00
committed by tao.chen
parent 3a5cc12782
commit af2f035d03
17 changed files with 159 additions and 304 deletions
+25 -16
View File
@@ -1,4 +1,11 @@
import Icon from "../../components/common/Icon";
import {
Calendar,
Check,
FileText,
LayoutGrid,
Settings,
type LucideIcon,
} from "lucide-react";
import { useAuth, usePermission } from "../../context/AuthContext";
const TREND_VALUES = [38, 55, 44, 73, 61, 86, 78] as const;
@@ -50,22 +57,24 @@ export function DashboardPage({
</div>
<div className="mt-[18px] grid grid-cols-4 gap-3.5">
{[
{ icon: "script" as const, value: scriptCount, label: "工作副本" },
{ icon: "workspace" as const, value: 2, label: "Workspace" },
{ icon: "settings" as const, value: 4, label: "平台用户" },
{
icon: "check" as const,
value: online ? "正常" : "检查中",
label: "平台状态",
},
].map((item) => (
{(
[
{ Icon: FileText, value: scriptCount, label: "工作副本" },
{ Icon: LayoutGrid, value: 2, label: "Workspace" },
{ Icon: Settings, value: 4, label: "平台用户" },
{
Icon: Check,
value: online ? "正常" : "检查中",
label: "平台状态",
},
] as Array<{ Icon: LucideIcon; value: number | string; label: string }>
).map((item) => (
<article
key={item.label}
className="flex items-center gap-3.5 rounded-[9px] border border-[#e0e8ef] bg-white p-5"
>
<span className="text-brand">
<Icon name={item.icon} />
<item.Icon />
</span>
<span className="flex flex-col">
<b className="text-[21px] text-[#20364c]">{item.value}</b>
@@ -81,7 +90,7 @@ export function DashboardPage({
className="flex cursor-pointer items-center gap-2 rounded-[7px] border border-[#d8e4ef] bg-white px-[18px] py-[13px] text-[#346587]"
onClick={() => onNavigate("scripts")}
>
<Icon name="script" />
<FileText />
</button>
<button
@@ -89,7 +98,7 @@ export function DashboardPage({
className="flex cursor-pointer items-center gap-2 rounded-[7px] border border-[#d8e4ef] bg-white px-[18px] py-[13px] text-[#346587]"
onClick={() => onNavigate("schedules")}
>
<Icon name="schedule" />
<Calendar />
</button>
{hasSystemView && (
@@ -98,7 +107,7 @@ export function DashboardPage({
className="flex cursor-pointer items-center gap-2 rounded-[7px] border border-[#d8e4ef] bg-white px-[18px] py-[13px] text-[#346587]"
onClick={() => onNavigate("system")}
>
<Icon name="settings" />
<Settings />
</button>
)}
@@ -226,7 +235,7 @@ export function DashboardPage({
>
<span className="flex items-center gap-[9px] text-[#344c63]">
<i className="grid size-[25px] place-items-center rounded-md bg-[#eaf4ff] text-[#277fcc]">
<Icon name="check" size={13} />
<Check size={13} />
</i>
{row[0]}
</span>
@@ -1,5 +1,5 @@
import { type Workspace, type WorkspaceMember } from "../../services/api";
import Icon from "../../components/common/Icon";
import { Plus, X } from "lucide-react";
export function ProjectMembersDrawer({
open,
@@ -60,7 +60,7 @@ export function ProjectMembersDrawer({
<p style={{ margin: "4px 0 0", fontSize: 13, color: "#888" }}>{selectedProject.workspace_name}</p>
</div>
<button className="icon-button" type="button" onClick={() => onClose()}>
<Icon name="close" />
<X />
</button>
</div>
@@ -80,7 +80,7 @@ export function ProjectMembersDrawer({
onClick={() => onAddMembers()}
style={{ fontSize: 13, padding: "6px 12px" }}
>
<Icon name="plus" size={14} />
<Plus size={14} />
</button>
</div>
@@ -1,5 +1,5 @@
import { type FormEvent } from "react";
import Icon from "../../components/common/Icon";
import { Folder } from "lucide-react";
import {
AppFormDialog,
dialogPrimaryButtonClass,
@@ -43,7 +43,7 @@ export function CreateFolderModal({
>
<form className={modalFormClass} onSubmit={onSubmit}>
<div className={destinationChipClass}>
<Icon name="folder" size={16} />
<Folder size={16} />
{parentPath || "个人根目录"}
</div>
<label className={formFieldClass}>
@@ -76,7 +76,7 @@ export function CreateFolderModal({
>
{busy
? <span className="button-spinner" />
: <Icon name="folder" size={16} />}
: <Folder size={16} />}
{busy ? "正在创建…" : "创建文件夹"}
</Button>
</div>
@@ -1,5 +1,5 @@
import { type FormEvent } from "react";
import Icon from "../../components/common/Icon";
import { BookOpen, Check, FileCode, Folder, Plus } from "lucide-react";
import type { ScriptType, Visibility } from "../../services/api";
import {
AppFormDialog,
@@ -57,7 +57,7 @@ export function CreateScriptModal({
>
<form className={modalFormClass} onSubmit={onSubmit}>
<div className={destinationChipClass}>
<Icon name="folder" size={16} />
<Folder size={16} />
{form.parentPath || "个人根目录"}
</div>
<label className={formFieldClass}>
@@ -92,7 +92,7 @@ export function CreateScriptModal({
type: "notebook" as const,
title: "Jupyter Notebook",
desc: "交互式数据探索与模型实验",
icon: "notebook" as const,
Icon: BookOpen,
iconTone: "bg-[#fff0ed] text-[#dd5a4c]",
size: 22,
},
@@ -100,13 +100,14 @@ export function CreateScriptModal({
type: "python" as const,
title: "Python 脚本",
desc: "批处理、训练和模型调用任务",
icon: "python" as const,
Icon: FileCode,
iconTone: "bg-[#e9f3ff] text-[#2a75c5]",
size: 23,
},
] as const
).map((item) => {
const selected = form.scriptType === item.type;
const TypeIcon = item.Icon;
return (
<button
key={item.type}
@@ -124,7 +125,7 @@ export function CreateScriptModal({
<span
className={`grid size-[37px] shrink-0 place-items-center rounded-lg ${item.iconTone}`}
>
<Icon name={item.icon} size={item.size} />
<TypeIcon size={item.size} />
</span>
<span className="flex min-w-0 flex-col">
<strong className="text-[11px] text-[#34475b]">
@@ -136,7 +137,7 @@ export function CreateScriptModal({
</span>
{selected && (
<span className="absolute top-1.5 right-1.5 grid size-[17px] place-items-center rounded-full bg-[#2e88dd] text-white">
<Icon name="check" size={14} />
<Check size={14} />
</span>
)}
</button>
@@ -178,7 +179,7 @@ export function CreateScriptModal({
disabled={creating || !form.name.trim()}
className={dialogPrimaryButtonClass}
>
{creating ? <span className="button-spinner" /> : <Icon name="plus" size={16} />}
{creating ? <span className="button-spinner" /> : <Plus size={16} />}
{creating ? "正在创建…" : "创建脚本"}
</Button>
</div>
@@ -1,5 +1,5 @@
import { type FormEvent } from "react";
import Icon from "../../components/common/Icon";
import { Upload } from "lucide-react";
import type { Visibility } from "../../services/api";
import {
AppFormDialog,
@@ -142,7 +142,7 @@ export function DataResourceUploadModal({
{uploading ? (
<span className="button-spinner" />
) : (
<Icon name="upload" size={16} />
<Upload size={16} />
)}
{uploading ? "上传中…" : "上传"}
</Button>
@@ -1,5 +1,5 @@
import { type FormEvent } from "react";
import Icon from "../../components/common/Icon";
import { ArrowUpFromLine } from "lucide-react";
import type { ScriptItem, Visibility } from "../../services/api";
import { scriptIcon } from "../../features/platform/WorkspaceTree";
import {
@@ -37,6 +37,8 @@ export function PublishModal({
onSubmit,
onClose,
}: PublishModalProps) {
const PublishTargetIcon = publishTarget ? scriptIcon(publishTarget) : null;
return (
<AppFormDialog
open={publishTarget !== null}
@@ -48,7 +50,7 @@ export function PublishModal({
size="panel"
>
<form className={modalFormClass} onSubmit={onSubmit}>
{publishTarget ? (
{publishTarget && PublishTargetIcon ? (
<div className="mb-[17px] flex items-center gap-2.5 rounded-[7px] border border-[#dce6ef] bg-[#f8fbfd] px-3 py-[11px]">
<span
className={`grid size-[25px] shrink-0 place-items-center rounded-[5px] ${
@@ -57,7 +59,7 @@ export function PublishModal({
: "bg-[#eaf3ff] text-[#2e73c6]"
}`}
>
<Icon name={scriptIcon(publishTarget)} size={18} />
<PublishTargetIcon size={18} />
</span>
<span className="flex min-w-0 flex-col gap-0.5">
<strong className="truncate text-xs text-[#34485d]">
@@ -114,7 +116,7 @@ export function PublishModal({
>
{publishing
? <span className="button-spinner" />
: <Icon name="release" size={16} />}
: <ArrowUpFromLine size={16} />}
{publishing ? "正在发布…" : "确认发布"}
</Button>
</div>
@@ -1,7 +1,6 @@
import { useEffect, useRef, useState } from "react";
import Editor from "@monaco-editor/react";
import Icon from "../../components/common/Icon";
import { Info } from "lucide-react";
import type { ScriptItem } from "../../services/api";
@@ -92,7 +91,7 @@ export function PythonEditor({
aria-live="polite"
>
<div className="mb-4 grid size-[54px] place-items-center rounded-full bg-[#fff1f0] text-[#c84f49]">
<Icon name="info" size={28} />
<Info size={28} />
</div>
<strong className="text-base text-[#1d344d]">Python </strong>
<p className="mt-[9px] max-w-[430px] text-xs leading-[1.7] text-[#7a8a9b] [overflow-wrap:anywhere]">
@@ -1,5 +1,5 @@
import { type ChangeEvent, type MouseEvent as ReactMouseEvent, type RefObject, useMemo } from "react";
import Icon from "../../components/common/Icon";
import { FileText, Plus, RefreshCw, Search, Upload } from "lucide-react";
import { WorkspaceTreeGroup } from "~/features/platform/WorkspaceTree";
import { useScriptWorkspaceStore } from "~/features/platform/state/scriptWorkspaceStore";
import type { ScriptItem, WorkspaceDirectory } from "~/services/api";
@@ -175,7 +175,7 @@ export function ScriptExplorer({
disabled={uploading}
onClick={onUpload}
>
<Icon name="upload" size={15} />
<Upload size={15} />
{uploading ? "上传中…" : "上传"}
</button>
<input
@@ -191,14 +191,14 @@ export function ScriptExplorer({
type="button"
onClick={() => onOpenCreateDialog()}
>
<Icon name="plus" size={16} />
<Plus size={16} />
</button>
</div>
</div>
<div className="mx-3 mt-[11px] mb-[7px] flex h-[38px] items-center gap-[7px] rounded-md border border-[#dce5ed] bg-[#fbfcfd] px-[9px] text-[#95a2b1] focus-within:border-[#6aa9e9] focus-within:shadow-[0_0_0_3px_rgb(31_119_207/8%)]">
<Icon name="search" size={17} />
<Search size={17} />
<input
className="min-w-0 flex-1 border-0 bg-transparent text-xs text-[#26384d] outline-none placeholder:text-[#a7b2bf]"
aria-label="搜索脚本"
@@ -213,7 +213,7 @@ export function ScriptExplorer({
onClick={onRefresh}
>
<span className={refreshing ? "inline-flex animate-spin" : "inline-flex"}>
<Icon name="refresh" size={16} />
<RefreshCw size={16} />
</span>
</button>
</div>
@@ -257,7 +257,7 @@ export function ScriptExplorer({
{filteredScripts.length === 0 && directories.length === 0 && (
<div className="flex flex-col items-center px-[18px] py-[34px] text-center text-[#97a4b4]">
<span className="mb-3 grid size-[46px] place-items-center rounded-[13px] bg-[#eff6fd] text-[#6796c5]">
<Icon name="script" size={24} />
<FileText size={24} />
</span>
<strong className="text-xs text-[#637286]">
{keyword ? "没有匹配脚本" : "还没有构建脚本"}
@@ -273,7 +273,7 @@ export function ScriptExplorer({
className="inline-flex cursor-pointer items-center gap-1 rounded-md border border-[#bcd6ee] bg-white px-[11px] py-[7px] text-[11px] text-[#176cc1]"
onClick={() => onOpenCreateDialog()}
>
<Icon name="plus" size={15} />
<Plus size={15} />
</button>
)}
@@ -1,4 +1,15 @@
import Icon from "../../components/common/Icon";
import {
BookOpen,
Check,
ChevronRight,
ExternalLink,
FileCode,
Info,
Lock,
Plus,
RefreshCw,
X,
} from "lucide-react";
import type {
ActiveEditSession,
LatestVersion,
@@ -401,6 +412,8 @@ export function ScriptWorkspace({
}
}, [script.script_id, script.workspace_id, isReadOnlyMode, readOnlyRefreshVersion]);
const ScriptTypeIcon = scriptIcon(script);
return (
<>
<div className="relative flex h-[43px] min-h-[43px] items-stretch overflow-hidden border-b border-[#e5ebf1] bg-[#f7f9fb]">
@@ -410,7 +423,7 @@ export function ScriptWorkspace({
aria-label="向左滚动"
onClick={() => scroll("left")}
>
<Icon name="chevron" size={16} />
<ChevronRight size={16} />
</button>
<div
className="tabbar-scroll flex flex-1 overflow-x-auto overflow-y-hidden scroll-smooth"
@@ -432,10 +445,9 @@ export function ScriptWorkspace({
<span
className={`grid size-[25px] shrink-0 place-items-center rounded-[5px] ${fileIconTone(tab.scriptType)}`}
>
<Icon
name={tab.scriptType === "notebook" ? "notebook" : "python"}
size={16}
/>
{tab.scriptType === "notebook"
? <BookOpen size={16} />
: <FileCode size={16} />}
</span>
<span className="min-w-0 flex-1 truncate">{tab.scriptName}</span>
<button
@@ -444,7 +456,7 @@ export function ScriptWorkspace({
aria-label="关闭标签"
onClick={(event) => onClose(tab.scriptId, event)}
>
<Icon name="close" size={14} />
<X size={14} />
</button>
</div>
);
@@ -454,7 +466,7 @@ export function ScriptWorkspace({
type="button"
onClick={onNewTab}
>
<Icon name="plus" size={17} />
<Plus size={17} />
</button>
</div>
<button
@@ -463,7 +475,7 @@ export function ScriptWorkspace({
aria-label="向右滚动"
onClick={() => scroll("right")}
>
<Icon name="chevron" size={16} />
<ChevronRight size={16} />
</button>
</div>
@@ -472,10 +484,10 @@ export function ScriptWorkspace({
<span
className={`grid size-[25px] shrink-0 place-items-center rounded-[5px] ${fileIconTone(script.script_type)}`}
>
<Icon name={scriptIcon(script)} size={17} />
<ScriptTypeIcon size={17} />
</span>
<span></span>
<Icon name="chevron" size={13} />
<ChevronRight size={13} />
<strong className="max-w-[300px] truncate text-[#45576b]">
{script.script_name}
</strong>
@@ -561,7 +573,7 @@ export function ScriptWorkspace({
这个锁只在本浏览器当前 tab 内有效,不能阻止隐身模式 / 其它浏览器同时编辑。 */}
{isEditing && (
<div className="flex shrink-0 items-center justify-center gap-2 border-b border-[#c9def9] bg-[#e7f1ff] px-4 py-1.5 text-xs font-medium text-[#1f4e8a]">
<Icon name="info" size={14} />
<Info size={14} />
<span>
</span>
@@ -574,7 +586,7 @@ export function ScriptWorkspace({
<div style={{ display: isReadOnlyMode ? 'block' : 'none', height: '100%' }}>
<div className="flex h-full flex-col overflow-hidden bg-[#f8f9fa]">
<div className="mb-1.5 flex shrink-0 items-center justify-center gap-2 border-b border-[#e0e0e0] bg-[#fff3cd] px-4 py-2 text-[13px] font-medium text-[#856404]">
<Icon name="lock" size={16} />
<Lock size={16} />
<span></span>
</div>
<div className="min-h-0 flex-1 overflow-y-auto">
@@ -585,7 +597,7 @@ export function ScriptWorkspace({
</div>
) : readOnlyError ? (
<div className="flex min-h-[200px] flex-col items-center justify-center gap-3 p-5 text-center text-sm text-[#dc3545]">
<Icon name="info" size={28} />
<Info size={28} />
<strong className="text-base"></strong>
<p className="m-0 text-[#666]">{readOnlyError}</p>
</div>
@@ -712,7 +724,7 @@ export function ScriptWorkspace({
}`}
>
{openError
? <Icon name="info" size={28} />
? <Info size={28} />
: <span className="button-spinner button-spinner--blue size-6 border-[3px]" />}
</div>
<strong className="text-base text-[#1d344d]">
@@ -732,7 +744,7 @@ export function ScriptWorkspace({
>
{editBusy
? <span className="button-spinner button-spinner--blue" />
: <Icon name="refresh" size={16} />}
: <RefreshCw size={16} />}
{editBusy ? "正在重试…" : "重试打开"}
</button>
)}
@@ -763,7 +775,7 @@ export function ScriptWorkspace({
>
{editBusy
? <span className="button-spinner button-spinner--blue" />
: <Icon name="external" size={17} />}
: <ExternalLink size={17} />}
{editBusy
? "正在准备编辑器…"
: isEditing
@@ -817,7 +829,7 @@ export function ScriptWorkspace({
<div className="mt-3 flex flex-wrap items-center gap-x-5 gap-y-2 px-1 text-[11px] text-[#7a8b9c]">
<span className="inline-flex items-center gap-[5px] text-[#25875e]">
<Icon name="check" size={15} />
<Check size={15} />
</span>
<span>SHA-256&nbsp; {shortHash(script.content_hash)}</span>
<span>
@@ -4,7 +4,6 @@ import { useAuth } from "../../context/AuthContext";
import { CreateFolderModal } from "./CreateFolderModal";
import { CreateScriptModal } from "./CreateScriptModal";
import { DataResourceUploadModal } from "./DataResourceUploadModal";
import Icon from "../../components/common/Icon";
import { WelcomePanel } from "./WelcomePanel";
import { PublishModal } from "./PublishModal";
import { ScriptExplorer } from "./ScriptExplorer";
@@ -1,4 +1,14 @@
import Icon from "../../components/common/Icon";
import {
BookOpen,
Database,
FileCode,
FileText,
Folder,
Lock,
Unlock,
Upload,
X,
} from "lucide-react";
import type { ScriptItem, ScriptType } from "../../services/api";
type ContextMenuState = {
@@ -45,6 +55,7 @@ export function TreeContextMenu({
if (!contextMenu) return null;
const isDataResource = !!contextMenu.script?.script_id.startsWith("data:");
const LockToggleIcon = contextMenu.script?.is_locked ? Unlock : Lock;
return (
<div
@@ -71,7 +82,7 @@ export function TreeContextMenu({
onClose();
}}
>
<Icon name="database" size={16} />
<Database size={16} />
Jupyter
</button>
{onRemoveResource && (
@@ -85,7 +96,7 @@ export function TreeContextMenu({
onClose();
}}
>
<Icon name="close" size={16} />
<X size={16} />
</button>
)}
@@ -101,7 +112,7 @@ export function TreeContextMenu({
onClose();
}}
>
<Icon name="script" size={16} />
<FileText size={16} />
</button>
<button
@@ -113,10 +124,7 @@ export function TreeContextMenu({
onClose();
}}
>
<Icon
name={contextMenu.script.is_locked ? "unlock" : "lock"}
size={16}
/>
<LockToggleIcon size={16} />
{contextMenu.script.is_locked ? "解锁文件" : "锁定文件"}
</button>
<button
@@ -125,7 +133,7 @@ export function TreeContextMenu({
role="menuitem"
onClick={() => onRemoveScript(contextMenu.script!)}
>
<Icon name="close" size={16} />
<X size={16} />
</button>
</>
@@ -139,7 +147,7 @@ export function TreeContextMenu({
className={menuItemClass}
onClick={() => onOpenCreateDialog(contextMenu.path, "notebook")}
>
<Icon name="notebook" size={16} />
<BookOpen size={16} />
Notebook
</button>
<button
@@ -148,7 +156,7 @@ export function TreeContextMenu({
className={menuItemClass}
onClick={() => onOpenCreateDialog(contextMenu.path, "python")}
>
<Icon name="python" size={16} />
<FileCode size={16} />
Python
</button>
<button
@@ -157,7 +165,7 @@ export function TreeContextMenu({
className={menuItemClass}
onClick={() => onOpenFolderDialog(contextMenu.path)}
>
<Icon name="folder" size={16} />
<Folder size={16} />
</button>
<button
@@ -166,7 +174,7 @@ export function TreeContextMenu({
className={menuItemClass}
onClick={() => onChooseUpload(contextMenu.path)}
>
<Icon name="upload" size={16} />
<Upload size={16} />
</button>
{contextMenu.kind === "directory" && (
@@ -178,7 +186,7 @@ export function TreeContextMenu({
role="menuitem"
onClick={() => onRemoveDirectory(contextMenu.path)}
>
<Icon name="close" size={16} />
<X size={16} />
</button>
</>
@@ -1,4 +1,4 @@
import Icon from "../../components/common/Icon";
import { Check } from "lucide-react";
import type { StableVersion } from "../../services/api";
import { copyToClipboard } from "../../lib/clipboard";
import {
@@ -30,7 +30,7 @@ export function VersionReceiptModal({
bodyClassName="overflow-visible"
>
<div className="mx-auto mb-3.5 grid size-[58px] place-items-center rounded-full bg-gradient-to-br from-[#24b67d] to-[#149566] text-white shadow-[0_9px_24px_rgb(25_157_104/25%)]">
<Icon name="check" size={28} />
<Check size={28} />
</div>
<span className={modalEyebrowClass}>STABLE VERSION</span>
<h2 className="mb-2 mt-[5px] text-xl text-[#24374a]">
@@ -1,6 +1,14 @@
import { type MouseEvent as ReactMouseEvent, useEffect, useMemo } from "react";
import Icon from "../../components/common/Icon";
import {
BookOpen,
ChevronRight,
Database,
FileCode,
Folder,
Lock,
type LucideIcon,
} from "lucide-react";
import type {
ScriptItem,
WorkspaceDirectory,
@@ -52,8 +60,8 @@ function formatTime(value: string) {
}).format(new Date(value));
}
export function scriptIcon(item: ScriptItem) {
return item.script_type === "notebook" ? "notebook" : "python";
export function scriptIcon(item: Pick<ScriptItem, "script_type">): LucideIcon {
return item.script_type === "notebook" ? BookOpen : FileCode;
}
function ownedScriptPath(item: ScriptItem) {
@@ -158,10 +166,10 @@ export function WorkspaceTreeGroup({
open ? "rotate-90" : ""
}`}
>
<Icon name="chevron" size={14} />
<ChevronRight size={14} />
</span>
<span className="inline-flex text-[#eab434] [&_svg]:fill-[#f7c84a] [&_svg]:stroke-[#e0a828]">
<Icon name="folder" size={17} />
<Folder size={17} />
</span>
<span>{title}</span>
</button>
@@ -242,6 +250,7 @@ function WorkspaceTreeItems({
{childScripts.map((item) => {
const isActive = selectedId === item.script_id;
const isData = item.script_id.startsWith("data:");
const ItemIcon = isData ? Database : scriptIcon(item);
const iconTone = isData
? "text-[#5a8f6a] bg-[#eef8f1]"
: item.script_type === "notebook"
@@ -273,7 +282,7 @@ function WorkspaceTreeItems({
: undefined}
>
<span className={`grid size-[25px] shrink-0 place-items-center rounded-[5px] ${iconTone}`}>
<Icon name={isData ? "database" : scriptIcon(item)} size={17} />
<ItemIcon size={17} />
</span>
<span className="flex min-w-0 flex-1 flex-col">
<strong
@@ -288,7 +297,7 @@ function WorkspaceTreeItems({
</span>
{item.is_locked && (
<span className="mr-1 inline-flex items-center justify-center text-[#c79a3a]" title="已锁定">
<Icon name="lock" size={12} />
<Lock size={12} />
</span>
)}
{item.visibility !== "private" && (
@@ -343,10 +352,10 @@ function DirectoryBranch({
open ? "rotate-90" : ""
}`}
>
<Icon name="chevron" size={13} />
<ChevronRight size={13} />
</span>
<span className="inline-flex shrink-0 text-[#e2aa27] [&_svg]:fill-[#f7c84a]">
<Icon name="folder" size={17} />
<Folder size={17} />
</span>
<strong
className="truncate text-[11px] font-[650]"