feat: 优化素材库检索列表视图显示效果
列表视图重新设计: - 采用水平布局:左侧缩略图 + 中间内容 + 右侧操作 - 紧凑的20x20图片尺寸,保持清晰度 - 优化信息层次:标题、描述、标签分层显示 - 右侧操作区域:颜色指示器 + 查看按钮 + 时间 交互优化: - 悬停效果:图片缩放、背景渐变、阴影变化 - 评分标识移至图片右上角 - AI推荐标识在悬停时显示 - 标签数量限制和省略显示 布局改进: - 列表项间距调整为3px,更紧凑 - 移除不必要的flex样式冲突 - 保持网格视图原有的卡片布局 - 响应式设计适配不同屏幕尺寸 现在列表视图更加美观实用,信息密度合理!
This commit is contained in:
parent
74c20f7e7b
commit
99763ebefb
|
|
@ -63,6 +63,170 @@ const MaterialCard: React.FC<MaterialCardProps> = ({
|
|||
const primaryProduct = material.products[0];
|
||||
const hasMultipleProducts = material.products.length > 1;
|
||||
|
||||
// 列表视图的特殊布局
|
||||
if (compact) {
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
card card-interactive group cursor-pointer animate-fade-in-up
|
||||
relative overflow-hidden bg-gradient-to-br from-white to-gray-50/50
|
||||
hover:from-white hover:to-primary-50/30 transition-all duration-300
|
||||
hover:shadow-md hover:shadow-primary-500/10
|
||||
border border-gray-200 hover:border-primary-300
|
||||
p-4 flex items-center gap-4
|
||||
${className}
|
||||
`}
|
||||
onClick={handleCardClick}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
>
|
||||
{/* 装饰性背景 */}
|
||||
<div className="absolute top-0 right-0 w-16 h-16 bg-gradient-to-br from-primary-100 to-primary-200 rounded-full -translate-y-8 translate-x-8 opacity-40 group-hover:opacity-60 transition-all duration-500"></div>
|
||||
|
||||
{/* 左侧图片 */}
|
||||
<div className="relative flex-shrink-0">
|
||||
<div className="w-20 h-20 rounded-lg overflow-hidden bg-gray-100">
|
||||
{!imageError ? (
|
||||
<img
|
||||
src={material.image_url}
|
||||
alt={material.style_description}
|
||||
className={`w-full h-full object-cover transition-all duration-300 group-hover:scale-105 ${
|
||||
imageLoaded ? 'opacity-100' : 'opacity-0'
|
||||
}`}
|
||||
onLoad={handleImageLoad}
|
||||
onError={handleImageError}
|
||||
/>
|
||||
) : (
|
||||
<div className="w-full h-full flex items-center justify-center bg-gray-100">
|
||||
<Package className="w-6 h-6 text-gray-400" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 加载状态 */}
|
||||
{!imageLoaded && !imageError && (
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-gray-100">
|
||||
<div className="w-4 h-4 border-2 border-primary-500 border-t-transparent rounded-full animate-spin"></div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 评分标识 */}
|
||||
{showScore && (
|
||||
<div className="absolute -top-2 -right-2 flex items-center gap-1 px-2 py-1 bg-yellow-100 text-yellow-700 rounded-full text-xs font-medium">
|
||||
<Star className="w-3 h-3 fill-current" />
|
||||
{MaterialSearchService.formatRelevanceScore(material.relevance_score)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 中间内容 */}
|
||||
<div className="flex-1 min-w-0 space-y-2">
|
||||
{/* 标题和描述 */}
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-high-emphasis line-clamp-1 group-hover:text-primary-600 transition-colors duration-200">
|
||||
{material.style_description || '时尚素材'}
|
||||
</h3>
|
||||
{primaryProduct && (
|
||||
<p className="text-xs text-gray-600 line-clamp-1 mt-1">
|
||||
{primaryProduct.description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 标签行 */}
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
{/* 类别标签 */}
|
||||
{primaryProduct && (
|
||||
<div className="flex items-center gap-1">
|
||||
<Tag className="w-3 h-3 text-gray-500" />
|
||||
<span className="text-xs font-medium text-gray-700">{primaryProduct.category}</span>
|
||||
{hasMultipleProducts && (
|
||||
<span className="text-xs text-gray-500">+{material.products.length - 1}</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 环境标签 */}
|
||||
{material.environment_tags.slice(0, 2).map((tag, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="px-2 py-0.5 bg-blue-100 text-blue-700 rounded text-xs"
|
||||
>
|
||||
{tag}
|
||||
</div>
|
||||
))}
|
||||
{material.environment_tags.length > 2 && (
|
||||
<div className="px-2 py-0.5 bg-gray-100 text-gray-500 rounded text-xs">
|
||||
+{material.environment_tags.length - 2}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 设计风格 */}
|
||||
{primaryProduct && primaryProduct.design_styles.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{primaryProduct.design_styles.slice(0, 3).map((style, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="px-2 py-0.5 bg-gray-100 text-gray-600 rounded text-xs"
|
||||
>
|
||||
{style}
|
||||
</div>
|
||||
))}
|
||||
{primaryProduct.design_styles.length > 3 && (
|
||||
<div className="px-2 py-0.5 bg-gray-100 text-gray-500 rounded text-xs">
|
||||
+{primaryProduct.design_styles.length - 3}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 右侧操作区域 */}
|
||||
<div className="flex-shrink-0 flex flex-col items-end gap-2">
|
||||
{/* 颜色信息 */}
|
||||
{primaryProduct && (
|
||||
<div className="flex items-center gap-2">
|
||||
<Palette className="w-3 h-3 text-gray-500" />
|
||||
<div
|
||||
className="w-4 h-4 rounded-full border border-gray-300 shadow-sm"
|
||||
style={{
|
||||
backgroundColor: `hsl(${primaryProduct.color_pattern.hue * 360}, ${primaryProduct.color_pattern.saturation * 100}%, ${primaryProduct.color_pattern.value * 100}%)`
|
||||
}}
|
||||
title="主要颜色"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 操作按钮 */}
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (onSelect) onSelect(material);
|
||||
}}
|
||||
className="flex items-center gap-1 px-3 py-1 text-primary-600 hover:text-primary-700 hover:bg-primary-50 rounded transition-colors duration-200 text-xs font-medium"
|
||||
>
|
||||
<Eye className="w-3 h-3" />
|
||||
查看
|
||||
<ChevronRight className="w-3 h-3" />
|
||||
</button>
|
||||
|
||||
{/* 时间信息 */}
|
||||
<div className="text-xs text-gray-500">
|
||||
{new Date(material.created_at).toLocaleDateString()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* AI推荐标识 */}
|
||||
<div className="absolute bottom-2 left-4 flex items-center gap-1 px-2 py-1 bg-gradient-to-r from-purple-100 to-pink-100 text-purple-700 rounded-full text-xs font-medium opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||
<Sparkles className="w-3 h-3" />
|
||||
AI推荐
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 网格视图的原有布局
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
|
|
@ -72,7 +236,7 @@ const MaterialCard: React.FC<MaterialCardProps> = ({
|
|||
hover:shadow-lg hover:shadow-primary-500/10 hover:-translate-y-1
|
||||
border border-gray-200 hover:border-primary-300
|
||||
transform-gpu will-change-transform
|
||||
${compact ? 'p-4' : 'p-5'}
|
||||
p-5
|
||||
${className}
|
||||
`}
|
||||
onClick={handleCardClick}
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ const MaterialSearchResults: React.FC<MaterialSearchResultsProps> = ({
|
|||
<div className={
|
||||
viewMode === 'grid'
|
||||
? "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"
|
||||
: "space-y-4"
|
||||
: "space-y-3"
|
||||
}>
|
||||
{results.map((material, index) => (
|
||||
<MaterialCard
|
||||
|
|
@ -200,9 +200,7 @@ const MaterialSearchResults: React.FC<MaterialSearchResultsProps> = ({
|
|||
onSelect={handleMaterialSelect}
|
||||
showScore={true}
|
||||
compact={viewMode === 'list'}
|
||||
className={`animate-fade-in-up ${isLoading ? 'opacity-50 pointer-events-none' : ''} ${
|
||||
viewMode === 'list' ? 'flex flex-row items-center gap-4 p-4' : ''
|
||||
}`}
|
||||
className={`animate-fade-in-up ${isLoading ? 'opacity-50 pointer-events-none' : ''}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue