黑暗模式 优化

This commit is contained in:
‘Liammcl’
2024-12-28 17:47:33 +08:00
parent b97cdd4685
commit 0942ed68ab
11 changed files with 239 additions and 124 deletions

View File

@@ -1,4 +0,0 @@
VITE_SUPABASE_URL=your_supabase_url
VITE_SUPABASE_ANON_KEY=your_supabase_anon_key

12
pnpm-lock.yaml generated
View File

@@ -53,6 +53,9 @@ importers:
react-dom: react-dom:
specifier: ^18.2.0 specifier: ^18.2.0
version: 18.3.1(react@18.3.1) version: 18.3.1(react@18.3.1)
react-icons:
specifier: ^5.4.0
version: 5.4.0(react@18.3.1)
react-infinite-scroll-component: react-infinite-scroll-component:
specifier: ^6.1.0 specifier: ^6.1.0
version: 6.1.0(react@18.3.1) version: 6.1.0(react@18.3.1)
@@ -2121,6 +2124,11 @@ packages:
peerDependencies: peerDependencies:
react: ^18.3.1 react: ^18.3.1
react-icons@5.4.0:
resolution: {integrity: sha512-7eltJxgVt7X64oHh6wSWNwwbKTCtMfK35hcjvJS0yxEAhPM8oUKdS3+kqaW1vicIltw+kR2unHaa12S9pPALoQ==}
peerDependencies:
react: '*'
react-infinite-scroll-component@6.1.0: react-infinite-scroll-component@6.1.0:
resolution: {integrity: sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==} resolution: {integrity: sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==}
peerDependencies: peerDependencies:
@@ -5008,6 +5016,10 @@ snapshots:
react: 18.3.1 react: 18.3.1
scheduler: 0.23.2 scheduler: 0.23.2
react-icons@5.4.0(react@18.3.1):
dependencies:
react: 18.3.1
react-infinite-scroll-component@6.1.0(react@18.3.1): react-infinite-scroll-component@6.1.0(react@18.3.1):
dependencies: dependencies:
react: 18.3.1 react: 18.3.1

View File

@@ -18,6 +18,7 @@ const Header = ({ collapsed, setCollapsed }) => {
console.error("Logout error:", error); console.error("Logout error:", error);
} }
}; };
console.log(user);
const userMenuItems = [ const userMenuItems = [
{ {
@@ -79,7 +80,7 @@ const Header = ({ collapsed, setCollapsed }) => {
)} )}
<p className="max-w-20 truncate"> <p className="max-w-20 truncate">
{!user?.user_metadata?.name || user?.email?.split("@")[0]} {user?.user_metadata?.name || user?.email?.split("@")[0]}
</p> </p>
</div> </div>
</Dropdown> </Dropdown>

View File

@@ -12,13 +12,13 @@ const MainLayout = () => {
const { isDarkMode } = useTheme(); const { isDarkMode } = useTheme();
return ( return (
<Layout className="min-h-screen"> <Layout className="h-screen overflow-hidden">
<Sidebar collapsed={collapsed} /> <Sidebar collapsed={collapsed} />
<Layout className="flex flex-col h-screen"> <Layout className="flex flex-col ">
<Header collapsed={collapsed} setCollapsed={setCollapsed} /> <Header collapsed={collapsed} setCollapsed={setCollapsed} />
<Content <Content
className={` className={`
m-2 p-4 rounded-lg overflow-auto m-2 p-4 rounded-lg overflow-auto h-full
${isDarkMode ? 'bg-[#141414]' : 'bg-white'} ${isDarkMode ? 'bg-[#141414]' : 'bg-white'}
flex-1 flex-1
`} `}

View File

@@ -227,7 +227,7 @@ const ServicePage = () => {
// 子表格列定义 // 子表格列定义
const expandedRowRender = (record) => { const expandedRowRender = (record) => {
return ( return (
<div className="bg-gray-50 p-4 rounded-lg"> <div className="bg-gray-50 dark:bg-gray-600 p-4 rounded-lg">
{record.attributes.sections.map((section) => ( {record.attributes.sections.map((section) => (
<div key={section.key} className="mb-6 rounded-lg shadow-sm p-4"> <div key={section.key} className="mb-6 rounded-lg shadow-sm p-4">
<div className="flex items-center justify-between mb-3 border-b pb-2"> <div className="flex items-center justify-between mb-3 border-b pb-2">

View File

@@ -130,7 +130,7 @@ const Classify = ({activeType,typeList}) => {
/> />
</Form.Item> </Form.Item>
) : ( ) : (
<span className="text-gray-700">{text}</span> <span >{text}</span>
); );
}, },
}, },
@@ -152,7 +152,7 @@ const Classify = ({activeType,typeList}) => {
/> />
</Form.Item> </Form.Item>
) : ( ) : (
<span className="text-gray-700 px-2 py-1 bg-gray-100 rounded-full text-sm"> <span className="text-gray-700 px-2 py-1 bg-gray-100 dark:bg-gray-700 dark:text-gray-100 rounded-full text-sm">
{typeList.find(t => t.value === text)?.label || text} {typeList.find(t => t.value === text)?.label || text}
</span> </span>
); );
@@ -225,8 +225,8 @@ const Classify = ({activeType,typeList}) => {
]; ];
return ( return (
<div className="p-6 bg-gray-50"> <div className="p-6 ">
<div className="bg-white rounded-lg shadow-sm mb-6 p-4"> <div className=" rounded-lg shadow-sm mb-6 p-4">
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4"> <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button <Button
@@ -259,7 +259,7 @@ const Classify = ({activeType,typeList}) => {
value: 'common', value: 'common',
} }
]} ]}
className="bg-gray-50 p-1" className="bg-gray-50 dark:bg-gray-600 p-1"
/> />
</div> </div>
</div> </div>

View File

@@ -56,7 +56,7 @@ const ResourceManagement = () => {
<Card> <Card>
<Classify typeList={filterOption} activeType={activeType} setActiveType={setActiveType} /> <Classify typeList={filterOption} activeType={activeType} setActiveType={setActiveType} />
<Unit typeList={filterOption} activeType={activeType} /> <Unit typeList={filterOption} activeType={activeType} />
<Sections typeList={filterOption} activeType={activeType} /> <Sections activeType={activeType} />
</Card> </Card>
</div> </div>
) )

View File

@@ -8,7 +8,7 @@ import {
message, message,
Popconfirm, Popconfirm,
Select, Select,
Segmented, Divider,
InputNumber, InputNumber,
Card, Card,
Typography Typography
@@ -19,30 +19,22 @@ import { v4 as uuidv4 } from 'uuid';
const { Text } = Typography; const { Text } = Typography;
const SectionsManagement = ({ activeType = 'quotation', typeList }) => { const SectionsManagement = ({ activeType = 'quotation' }) => {
const [data, setData] = useState([]); const [data, setData] = useState([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [editingKey, setEditingKey] = useState(''); const [editingKey, setEditingKey] = useState('');
const [form] = Form.useForm(); const [form] = Form.useForm();
const [filterType, setFilterType] = useState('all'); const [loadingUnits,setLoadingUnits]=useState(false)
const [units,setUnit]=useState([])
const fetchSections = async (type = activeType, filterTypeValue = filterType) => { const [formValues, setFormValues] = useState({});
const fetchSections = async () => {
setLoading(true); setLoading(true);
try { try {
let filterCondition;
switch (filterTypeValue) {
case 'current':
filterCondition = { eq: type };
break;
default:
filterCondition = { eq: type };
}
const { data: sections } = await supabaseService.select('resources', { const { data: sections } = await supabaseService.select('resources', {
filter: { filter: {
'type': { eq: 'sections' }, 'type': { eq: 'sections' },
'attributes->>template_type': filterCondition 'attributes->>template_type': {eq:activeType}
}, },
order: { order: {
column: 'created_at', column: 'created_at',
@@ -58,9 +50,30 @@ const SectionsManagement = ({ activeType = 'quotation', typeList }) => {
setLoading(false); setLoading(false);
} }
}; };
const fetchUnits = async () => {
setLoadingUnits(true);
try {
const { data: units } = await supabaseService.select("resources", {
filter: {
type: { eq: "units" },
"attributes->>template_type": { in: `(${activeType},common)` },
},
order: {
column: "created_at",
ascending: false,
},
});
setUnit(units || []);
} catch (error) {
message.error("获取单位列表失败");
console.error(error);
} finally {
setLoadingUnits(false);
}
};
useEffect(() => { useEffect(() => {
fetchSections(activeType, filterType); fetchSections();
}, [activeType]); }, [activeType]);
const handleAdd = () => { const handleAdd = () => {
@@ -139,7 +152,32 @@ const SectionsManagement = ({ activeType = 'quotation', typeList }) => {
console.error(error); console.error(error);
} }
}; };
const handleAddUnit = async (unitName) => {
try {
const { error } = await supabase.from("resources").insert([
{
type: "units",
attributes: {
name: unitName,
template_type: activeType,
},
schema_version: 1,
},
]);
if (error) throw error;
message.success("新增单位成功");
fetchUnits();
return true;
} catch (error) {
message.error("新增单位失败");
console.error(error);
return false;
}
};
const handleValuesChange = (changedValues, allValues) => {
setFormValues(allValues);
};
const columns = [ const columns = [
{ {
title: '模块名称', title: '模块名称',
@@ -155,11 +193,10 @@ const SectionsManagement = ({ activeType = 'quotation', typeList }) => {
> >
<Input <Input
placeholder="请输入模块名称" placeholder="请输入模块名称"
className="rounded-md"
/> />
</Form.Item> </Form.Item>
) : ( ) : (
<span className="text-gray-700 font-medium">{text}</span> <span className=" font-medium">{text}</span>
); );
}, },
}, },
@@ -168,61 +205,114 @@ const SectionsManagement = ({ activeType = 'quotation', typeList }) => {
dataIndex: ['attributes', 'items'], dataIndex: ['attributes', 'items'],
render: (items, record) => { render: (items, record) => {
const isEditing = record.id === editingKey; const isEditing = record.id === editingKey;
if (isEditing) { if (isEditing) {
return ( return (
<Form.List name="items"> <Form.List name="items">
{(fields, { add, remove }) => ( {(fields, { add, remove }) => (
<div className="space-y-2"> <div className="space-y-2">
{fields.map((field, index) => ( {fields.map((field, index) => {
<Card key={field.key} size="small" className="bg-gray-50"> const items = formValues.items || [];
<div className="grid grid-cols-6 gap-2"> const currentItem = items[field.name] || {};
<Form.Item const subtotal = (currentItem.quantity || 0) * (currentItem.price || 0);
{...field}
name={[field.name, 'name']} return (
className="col-span-2 mb-0" <Card key={field.key} size="small" className="bg-gray-50 dark:bg-gray-600 ">
> <div className="grid grid-cols-6 gap-2">
<Input placeholder="项目名称" /> <Form.Item
</Form.Item> {...field}
<Form.Item name={[field.name, 'name']}
{...field} className="col-span-2 mb-0"
name={[field.name, 'unit']} >
className="mb-0" <Input placeholder="项目名称" />
> </Form.Item>
<Input placeholder="单位" /> <Form.Item
</Form.Item> {...field}
<Form.Item name={[field.name, 'unit']}
{...field} className="mb-0"
name={[field.name, 'quantity']} >
className="mb-0" <Select
> placeholder="选择单位"
<InputNumber loading={loadingUnits}
placeholder="数量" showSearch
min={0} allowClear
className="w-full" style={{ minWidth: "120px" }}
options={units.map((unit) => ({
label: unit.attributes.name,
value: unit.attributes.name,
}))}
onDropdownVisibleChange={(open) => {
if (open) fetchUnits();
}}
dropdownRender={(menu) => (
<>
{menu}
<Divider style={{ margin: "12px 0" }} />
<div style={{ padding: "4px" }}>
<Input.Search
placeholder="输入新单位名称"
enterButton={<PlusOutlined />}
onSearch={async (value) => {
if (!value.trim()) return;
if (
await handleAddUnit(value.trim())
) {
const currentItems =
form.getFieldValue([
"sections",
field.name,
"items",
]);
currentItems[itemField.name].unit =
value.trim();
form.setFieldValue(
["sections", field.name, "items"],
currentItems
);
}
}}
/>
</div>
</>
)}
/>
</Form.Item>
<Form.Item
{...field}
name={[field.name, 'quantity']}
className="mb-0"
>
<InputNumber
placeholder="数量"
min={0}
className="w-full"
/>
</Form.Item>
<Form.Item
{...field}
name={[field.name, 'price']}
className="mb-0"
>
<InputNumber
placeholder="单价 (NT$)"
min={0}
className="w-full"
prefix="NT$"
/>
</Form.Item>
<Button
type="text"
danger
icon={<DeleteOutlined />}
onClick={() => remove(field.name)}
className="flex items-center justify-center"
/> />
</Form.Item> </div>
<Form.Item <div className="flex items-center">
{...field} <Text type="secondary">小计: NT${subtotal.toLocaleString()}</Text>
name={[field.name, 'price']} </div>
className="mb-0" </Card>
> );
<InputNumber })}
placeholder="单价"
min={0}
className="w-full"
/>
</Form.Item>
<Button
type="text"
danger
icon={<DeleteOutlined />}
onClick={() => remove(field.name)}
className="flex items-center justify-center"
/>
</div>
</Card>
))}
<Button <Button
type="dashed" type="dashed"
onClick={() => add({ onClick={() => add({
@@ -241,17 +331,24 @@ const SectionsManagement = ({ activeType = 'quotation', typeList }) => {
</Form.List> </Form.List>
); );
} }
// 计算总金额
const total = (items || []).reduce((sum, item) => {
return sum + (item.quantity * item.price || 0);
}, 0);
return ( return (
<div className="space-y-1"> <div>
{(items || []).map((item, index) => ( {(items || []).map((item, index) => (
<div key={index} className="flex justify-between text-sm"> <div key={index} className="flex justify-start text-sm">
<span className="text-gray-600">{item.name}</span> <span >{item.name}</span>
<span className="text-gray-500"> <span className=" ml-2">
{item.quantity} {item.unit} × ¥{item.price} {item.quantity} {item.unit} × NT${item.price.toLocaleString()}
</span> </span>
</div> </div>
))} ))}
<Divider className="my-2" />
<Text strong>总金额: NT${total.toLocaleString()}</Text>
</div> </div>
); );
}, },
@@ -325,8 +422,8 @@ const SectionsManagement = ({ activeType = 'quotation', typeList }) => {
]; ];
return ( return (
<div className="p-6 bg-gray-50"> <div className="p-6 ">
<div className="bg-white rounded-lg shadow-sm mb-6 p-4"> <div className=" rounded-lg shadow-sm mb-6 p-4">
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4"> <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button <Button
@@ -341,8 +438,11 @@ const SectionsManagement = ({ activeType = 'quotation', typeList }) => {
</div> </div>
</div> </div>
<div className="bg-white rounded-lg shadow-sm"> <div className=" rounded-lg shadow-sm">
<Form form={form}> <Form
form={form}
onValuesChange={handleValuesChange}
>
<Table <Table
scroll={{ x: 1200 }} scroll={{ x: 1200 }}
columns={columns} columns={columns}

View File

@@ -127,7 +127,7 @@ const UnitManagement = ({ activeType, typeList }) => {
/> />
</Form.Item> </Form.Item>
) : ( ) : (
<span className="text-gray-700">{text}</span> <span>{text}</span>
); );
}, },
}, },
@@ -149,7 +149,7 @@ const UnitManagement = ({ activeType, typeList }) => {
/> />
</Form.Item> </Form.Item>
) : ( ) : (
<span className="text-gray-700 px-2 py-1 bg-gray-100 rounded-full text-sm"> <span className="text-gray-700 px-2 py-1 bg-gray-100 dark:bg-gray-700 dark:text-gray-100 rounded-full text-sm">
{typeList.find(t => t.value === text)?.label || text} {typeList.find(t => t.value === text)?.label || text}
</span> </span>
); );
@@ -222,7 +222,7 @@ const UnitManagement = ({ activeType, typeList }) => {
]; ];
return ( return (
<div className="p-6 bg-gray-50"> <div className="p-6 ">
<div className="rounded-lg shadow-sm mb-6 p-4"> <div className="rounded-lg shadow-sm mb-6 p-4">
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4"> <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -256,7 +256,7 @@ const UnitManagement = ({ activeType, typeList }) => {
value: 'common', value: 'common',
} }
]} ]}
className="bg-gray-50 p-1" className="bg-gray-50 dark:bg-gray-600 p-1"
/> />
</div> </div>
</div> </div>

View File

@@ -6,7 +6,7 @@ const NotFound = () => {
const navigate = useNavigate(); const navigate = useNavigate();
return ( return (
<div className="h-screen flex items-center justify-center bg-gray-50"> <div className="h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-600 ">
<Result <Result
status="404" status="404"
title="404" title="404"

View File

@@ -73,6 +73,7 @@ const StorageManager = () => {
const [newFileName, setNewFileName] = useState(""); const [newFileName, setNewFileName] = useState("");
const [currentPath, setCurrentPath] = useState(""); // 添加当前路径状态 const [currentPath, setCurrentPath] = useState(""); // 添加当前路径状态
const [pathHistory, setPathHistory] = useState([]); // 添加路径历史记录 const [pathHistory, setPathHistory] = useState([]); // 添加路径历史记录
const [isUploading, setIsUploading] = useState(false); // 添加上传loading状态
// 文件图标映射 // 文件图标映射
const getFileIcon = (file) => { const getFileIcon = (file) => {
@@ -144,7 +145,6 @@ const StorageManager = () => {
// 预览文件 // 预览文件
const previewFile = async (file) => { const previewFile = async (file) => {
try { try {
// Handle PDF and other binary files
if (file.metadata?.mimetype === 'application/pdf' || if (file.metadata?.mimetype === 'application/pdf' ||
file.metadata?.mimetype.includes('msword') || file.metadata?.mimetype.includes('msword') ||
file.metadata?.mimetype.includes('spreadsheet')) { file.metadata?.mimetype.includes('spreadsheet')) {
@@ -173,6 +173,7 @@ const StorageManager = () => {
multiple: true, multiple: true,
showUploadList: false, showUploadList: false,
customRequest: async ({ file, onSuccess, onError }) => { customRequest: async ({ file, onSuccess, onError }) => {
setIsUploading(true); // 开始上传时设置状态
try { try {
const originalName = file.name; const originalName = file.name;
const fileName = handleFileName(originalName); const fileName = handleFileName(originalName);
@@ -199,6 +200,8 @@ const StorageManager = () => {
} catch (error) { } catch (error) {
message.error(`${file.name} 上传失败: ${error.message}`); message.error(`${file.name} 上传失败: ${error.message}`);
onError(error); onError(error);
} finally {
setIsUploading(false); // 上传完成后重置状态
} }
}, },
beforeUpload: (file) => { beforeUpload: (file) => {
@@ -460,22 +463,22 @@ const StorageManager = () => {
// 修改文件列表渲染 // 修改文件列表渲染
const renderFileList = () => ( const renderFileList = () => (
<div <div
className="flex-1 overflow-y-auto rounded-lg shadow-sm" className="flex-1 overflow-y-auto rounded-lg shadow-sm "
id="scrollableDiv" id="scrollableDiv"
> >
{/* 面包屑导航 */} {/* 面包屑导航样式优化 */}
{currentPath && ( {currentPath && (
<div className="p-4 border-b border-gray-100"> <div className="p-4 border-b border-gray-100 dark:border-gray-700">
<div className="flex items-center space-x-2 text-sm"> <div className="flex items-center space-x-2 text-sm">
<Button <Button
type="link" type="link"
onClick={handleBack} onClick={handleBack}
className="px-0" className="px-0 text-blue-500 dark:text-blue-400"
> >
返回上级 返回上级
</Button> </Button>
<span className="text-gray-500">/</span> <span className="text-gray-500 dark:text-gray-400">/</span>
<span className="text-gray-900">{currentPath}</span> <span className="text-gray-900 dark:text-gray-100">{currentPath}</span>
</div> </div>
</div> </div>
)} )}
@@ -504,8 +507,8 @@ const StorageManager = () => {
<List.Item <List.Item
className={` className={`
relative group cursor-pointer transition-colors duration-200 relative group cursor-pointer transition-colors duration-200
hover:bg-gray-50 hover:bg-gray-50 dark:hover:bg-gray-700
${selectedFile?.name === file.name ? "bg-blue-50" : ""} ${selectedFile?.name === file.name ? "bg-blue-50 dark:bg-gray-700" : ""}
`} `}
onClick={() => file.metadata?.isFolder ? handleFolderClick(file.name) : previewFile(file)} onClick={() => file.metadata?.isFolder ? handleFolderClick(file.name) : previewFile(file)}
> >
@@ -563,7 +566,7 @@ const StorageManager = () => {
</div> </div>
} }
description={ description={
<div className="text-xs text-gray-500 space-x-4"> <div className="text-xs text-gray-500 dark:text-gray-400 space-x-4">
<span>{file.metadata?.isFolder ? '文件夹' : `类型: ${file.metadata?.mimetype}`}</span> <span>{file.metadata?.isFolder ? '文件夹' : `类型: ${file.metadata?.mimetype}`}</span>
{!file.metadata?.isFolder && ( {!file.metadata?.isFolder && (
<> <>
@@ -581,7 +584,6 @@ const StorageManager = () => {
</div> </div>
); );
// 渲染文件类型标签
const renderTypeTags = () => ( const renderTypeTags = () => (
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{Object.entries({ 全部: null, ...FILE_TYPES, 其他: null }).map(([type]) => ( {Object.entries({ 全部: null, ...FILE_TYPES, 其他: null }).map(([type]) => (
@@ -596,24 +598,29 @@ const StorageManager = () => {
))} ))}
</div> </div>
); );
return ( return (
<div className="flex h-screen bg-gray-50"> <div className="flex h-full ">
<div className="w-1/3 p-4 flex flex-col space-y-4"> <div className="w-1/3 p-2 flex flex-col space-y-4 h-full overflow-auto ">
<div className="rounded-lg shadow-sm overflow-hidden"> <div className="rounded-lg shadow-sm p-4 ">
<Dragger <Dragger
{...uploadProps} {...uploadProps}
className="px-6 py-8 hover:bg-gray-50 transition-colors group" className={`px-6 py-8 group
${isUploading ? 'opacity-50 cursor-not-allowed' : ''}`}
disabled={isUploading}
> >
<div className="space-y-3 text-center"> <div className="space-y-3 text-center">
<div className="inline-flex items-center justify-center w-16 h-16 rounded-full bg-blue-50 group-hover:bg-blue-100 transition-colors"> <div className="inline-flex items-center justify-center w-16 h-16 rounded-full group-hover:bg-blue-100 dark:group-hover:bg-blue-800 transition-colors">
<InboxOutlined className="text-3xl text-blue-500" /> {isUploading ? (
<LoadingSpinner />
) : (
<InboxOutlined className="text-3xl text-blue-500 dark:text-blue-400" />
)}
</div> </div>
<div> <div>
<p className="text-base font-medium text-gray-900"> <p className="text-base font-medium text-gray-900 dark:text-gray-100">
点击或拖拽文件上传 {isUploading ? '正在上传...' : '点击或拖拽文件上传'}
</p> </p>
<p className="mt-1 text-sm text-gray-500"> <p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
支持单个或批量上传文件大小不超过50MB 支持单个或批量上传文件大小不超过50MB
</p> </p>
</div> </div>
@@ -621,7 +628,6 @@ const StorageManager = () => {
</Dragger> </Dragger>
</div> </div>
{/* 搜索和筛选区域 */}
<div className="space-y-3"> <div className="space-y-3">
<Search <Search
placeholder="搜索文件名..." placeholder="搜索文件名..."
@@ -630,7 +636,7 @@ const StorageManager = () => {
className="w-full" className="w-full"
size="large" size="large"
/> />
<div className="bg-white p-3 rounded-lg shadow-sm"> <div className=" p-3 rounded-lg shadow-sm">
{renderTypeTags()} {renderTypeTags()}
</div> </div>
</div> </div>
@@ -646,20 +652,20 @@ const StorageManager = () => {
</div> </div>
{/* 右侧预览区域 */} {/* 右侧预览区域 */}
<div className="flex-1 p-4 bg-white border-l border-gray-200"> <div className="flex-1 p-4 border-l border-gray-200">
{selectedFile ? ( {selectedFile ? (
<> <>
<div className="mb-4 pb-4 border-b border-gray-200"> <div className="mb-4 pb-4 border-b border-gray-200">
<Space size="middle" align="center"> <Space size="middle" align="center">
<Space> <Space>
<span className="text-lg font-medium text-gray-900"> <span className="text-lg font-medium ">
{selectedFile.name} {selectedFile.name}
</span> </span>
<Button <Button
type="text" type="text"
icon={<EditOutlined />} icon={<EditOutlined />}
onClick={startRename} onClick={startRename}
className="text-gray-500 hover:text-blue-500" className="text-gray-500 dark:text-gray-100 hover:text-blue-500"
/> />
</Space> </Space>
{isHtml(selectedFile) && ( {isHtml(selectedFile) && (