fix: Resolve TypeScript build errors and clean up unused imports

Fixed Build Issues:
- Removed unused imports in ProjectList, ModelList, ProjectForm, DataTable, CardGrid
- Fixed variant type mismatches in TableAction and GridAction interfaces
- Replaced InteractiveTextarea with standard textarea in ProjectForm
- Updated EmptyState usage to use correct component props
- Removed unused ModelCardSkeleton component definition

 Code Cleanup:
- Cleaned up unused Search, Filter, MoreHorizontal, Eye, Edit, Trash2 imports
- Removed unused filters state in DataTable
- Removed unused actions parameter in CardGrid
- Simplified ProjectForm description field implementation
- Fixed EmptyProjectList usage in ProjectList

 Build Status:
- All TypeScript errors resolved
- Hot reload working correctly
- Development server running smoothly on port 5174
- No more compilation warnings or errors

The application now builds successfully with all UI/UX enhancements intact.
This commit is contained in:
imeepos 2025-07-15 20:50:54 +08:00
parent 496b26cdeb
commit a6f9e82c65
5 changed files with 71 additions and 48 deletions

View File

@ -1,5 +1,5 @@
import React, { useState, useMemo } from 'react'; import React, { useState, useMemo } from 'react';
import { Grid, List, Search, Filter, SortAsc, SortDesc } from 'lucide-react'; import { Grid, List, SortAsc, SortDesc } from 'lucide-react';
import { SearchInput } from './InteractiveInput'; import { SearchInput } from './InteractiveInput';
import { InteractiveButton } from './InteractiveButton'; import { InteractiveButton } from './InteractiveButton';
@ -13,7 +13,7 @@ export interface GridAction<T> {
label: string; label: string;
icon?: React.ReactNode; icon?: React.ReactNode;
onClick: (item: T) => void; onClick: (item: T) => void;
variant?: 'default' | 'primary' | 'danger'; variant?: 'primary' | 'secondary' | 'danger' | 'success' | 'ghost' | 'outline';
disabled?: (item: T) => boolean; disabled?: (item: T) => boolean;
} }
@ -87,7 +87,6 @@ export function CardGrid<T extends CardGridItem>({
emptyText = '暂无数据', emptyText = '暂无数据',
emptyComponent, emptyComponent,
className = '', className = '',
actions = [],
selectedItems = [], selectedItems = [],
onSelectionChange, onSelectionChange,
bulkActions = [], bulkActions = [],
@ -147,15 +146,6 @@ export function CardGrid<T extends CardGridItem>({
// 网格列数类名 // 网格列数类名
const getGridColsClass = () => { const getGridColsClass = () => {
const colsMap = {
1: 'grid-cols-1',
2: 'grid-cols-2',
3: 'grid-cols-3',
4: 'grid-cols-4',
5: 'grid-cols-5',
6: 'grid-cols-6',
};
const classes = []; const classes = [];
if (gridCols.sm) classes.push(`grid-cols-${gridCols.sm}`); if (gridCols.sm) classes.push(`grid-cols-${gridCols.sm}`);
if (gridCols.md) classes.push(`md:grid-cols-${gridCols.md}`); if (gridCols.md) classes.push(`md:grid-cols-${gridCols.md}`);

View File

@ -1,5 +1,5 @@
import React, { useState, useMemo } from 'react'; import React, { useState, useMemo } from 'react';
import { ChevronUp, ChevronDown, Search, Filter, MoreHorizontal, Eye, Edit, Trash2 } from 'lucide-react'; import { ChevronUp, ChevronDown, Filter } from 'lucide-react';
import { SearchInput } from './InteractiveInput'; import { SearchInput } from './InteractiveInput';
import { InteractiveButton } from './InteractiveButton'; import { InteractiveButton } from './InteractiveButton';
@ -18,7 +18,7 @@ export interface TableAction<T> {
label: string; label: string;
icon?: React.ReactNode; icon?: React.ReactNode;
onClick: (record: T) => void; onClick: (record: T) => void;
variant?: 'default' | 'primary' | 'danger'; variant?: 'primary' | 'secondary' | 'danger' | 'success' | 'ghost' | 'outline';
disabled?: (record: T) => boolean; disabled?: (record: T) => boolean;
} }
@ -71,8 +71,6 @@ export function DataTable<T extends Record<string, any>>({
direction: 'asc' | 'desc'; direction: 'asc' | 'desc';
} | null>(null); } | null>(null);
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [filters, setFilters] = useState<Record<string, any>>({});
// 获取行的唯一键 // 获取行的唯一键
const getRowKey = (record: T, index: number): string => { const getRowKey = (record: T, index: number): string => {
if (typeof rowKey === 'function') { if (typeof rowKey === 'function') {

View File

@ -4,7 +4,6 @@ import { modelService } from '../services/modelService';
import ModelCard from './ModelCard'; import ModelCard from './ModelCard';
import ModelForm from './ModelForm'; import ModelForm from './ModelForm';
import ModelSearch from './ModelSearch'; import ModelSearch from './ModelSearch';
import { ModelCardSkeleton } from './SkeletonLoader';
import { import {
PlusIcon, PlusIcon,
Squares2X2Icon, Squares2X2Icon,
@ -185,21 +184,7 @@ const ModelList: React.FC<ModelListProps> = ({ onModelSelect }) => {
// 骨架屏组件
const ModelCardSkeleton = () => (
<div className="bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden animate-pulse">
<div className="aspect-[3/4] bg-gray-200 loading-shimmer" />
<div className="p-5 space-y-3">
<div className="h-6 bg-gray-200 rounded loading-shimmer" />
<div className="h-4 bg-gray-200 rounded w-3/4 loading-shimmer" />
<div className="h-4 bg-gray-200 rounded w-1/2 loading-shimmer" />
<div className="flex gap-2 pt-2">
<div className="flex-1 h-10 bg-gray-200 rounded-xl loading-shimmer" />
<div className="w-10 h-10 bg-gray-200 rounded-xl loading-shimmer" />
</div>
</div>
</div>
);
if (loading) { if (loading) {
return ( return (
@ -222,7 +207,27 @@ const ModelList: React.FC<ModelListProps> = ({ onModelSelect }) => {
{/* 模特卡片骨架 */} {/* 模特卡片骨架 */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
{[...Array(8)].map((_, i) => ( {[...Array(8)].map((_, i) => (
<ModelCardSkeleton key={i} /> <div key={i} className="bg-white rounded-xl border border-gray-200 p-4 space-y-4 animate-pulse">
<div className="flex items-center space-x-3">
<div className="h-12 w-12 bg-gray-300 rounded-full"></div>
<div className="space-y-2 flex-1">
<div className="h-4 bg-gray-300 rounded w-2/3"></div>
<div className="h-3 bg-gray-300 rounded w-1/2"></div>
</div>
</div>
<div className="space-y-2">
<div className="h-3 bg-gray-300 rounded"></div>
<div className="h-3 bg-gray-300 rounded w-4/5"></div>
</div>
<div className="flex gap-2">
<div className="h-6 w-16 bg-gray-300 rounded-full"></div>
<div className="h-6 w-20 bg-gray-300 rounded-full"></div>
</div>
<div className="flex gap-2 pt-2">
<div className="h-8 bg-gray-300 rounded flex-1"></div>
<div className="h-8 w-8 bg-gray-300 rounded"></div>
</div>
</div>
))} ))}
</div> </div>
</div> </div>

View File

@ -2,9 +2,9 @@ import React, { useState, useEffect } from 'react';
import { invoke } from '@tauri-apps/api/core'; import { invoke } from '@tauri-apps/api/core';
import { useProjectStore } from '../store/projectStore'; import { useProjectStore } from '../store/projectStore';
import { ProjectFormData, ProjectFormErrors } from '../types/project'; import { ProjectFormData, ProjectFormErrors } from '../types/project';
import { InteractiveInput, InteractiveTextarea } from './InteractiveInput'; import { InteractiveInput } from './InteractiveInput';
import { InteractiveButton } from './InteractiveButton'; import { InteractiveButton } from './InteractiveButton';
import { Folder, X, AlertCircle } from 'lucide-react'; import { Folder, X } from 'lucide-react';
interface ProjectFormProps { interface ProjectFormProps {
initialData?: Partial<ProjectFormData>; initialData?: Partial<ProjectFormData>;
@ -206,16 +206,35 @@ export const ProjectForm: React.FC<ProjectFormProps> = ({
</div> </div>
{/* 项目描述 */} {/* 项目描述 */}
<InteractiveTextarea <div className="form-group">
label="项目描述" <label htmlFor="description" className="form-label">
value={formData.description}
onChange={(value) => setFormData(prev => ({ ...prev, description: value }))} </label>
placeholder="描述一下这个项目的用途和内容(可选)" <textarea
error={errors.description} id="description"
hint="添加描述有助于您更好地管理项目" className={`form-textarea ${errors.description ? 'error' : ''}`}
rows={4} value={formData.description}
maxLength={500} onChange={(e) => setFormData(prev => ({ ...prev, description: e.target.value }))}
/> placeholder="描述一下这个项目的用途和内容(可选)"
rows={4}
maxLength={500}
/>
<div className="flex justify-between items-center">
<div className="form-hint">
</div>
<div className="text-xs text-gray-500">
{formData.description.length}/500
</div>
</div>
{errors.description && (
<div className="form-error">
<span className="text-red-600">
{errors.description}
</span>
</div>
)}
</div>
</form> </form>
{/* 模态框底部 */} {/* 模态框底部 */}

View File

@ -4,11 +4,11 @@ import { invoke } from '@tauri-apps/api/core';
import { useProjectStore } from '../store/projectStore'; import { useProjectStore } from '../store/projectStore';
import { useUIStore } from '../store/uiStore'; import { useUIStore } from '../store/uiStore';
import { ProjectCard } from './ProjectCard'; import { ProjectCard } from './ProjectCard';
import { EmptyProjectList } from './EmptyState'; import { EmptyState } from './EmptyState';
import { LoadingSpinner } from './LoadingSpinner'; import { LoadingSpinner } from './LoadingSpinner';
import { ErrorMessage } from './ErrorMessage'; import { ErrorMessage } from './ErrorMessage';
import { DeleteConfirmDialog } from './DeleteConfirmDialog'; import { DeleteConfirmDialog } from './DeleteConfirmDialog';
import { ProjectCardSkeleton, PageLoadingSkeleton } from './SkeletonLoader'; import { PageLoadingSkeleton } from './SkeletonLoader';
import { InteractiveButton } from './InteractiveButton'; import { InteractiveButton } from './InteractiveButton';
import { Plus, Trash2 } from 'lucide-react'; import { Plus, Trash2 } from 'lucide-react';
@ -222,7 +222,18 @@ export const ProjectList: React.FC = () => {
{/* 项目内容区域 */} {/* 项目内容区域 */}
{projects.length === 0 ? ( {projects.length === 0 ? (
<div className="animate-fade-in-up"> <div className="animate-fade-in-up">
<EmptyProjectList onCreateProject={openCreateProjectModal} /> <EmptyState
illustration="folder"
title="还没有项目"
description="创建您的第一个项目开始使用 MixVideo"
actionText="新建项目"
onAction={openCreateProjectModal}
showTips
tips={[
"提示:您可以通过拖拽文件夹到此处快速创建项目",
"支持导入现有的视频项目文件夹"
]}
/>
</div> </div>
) : ( ) : (
<div className="space-y-6"> <div className="space-y-6">