style(cover-avatar): 列表改为 avatar-card 卡片样式(hover 操作按钮 + 图片缩放 + 4 列网格)

This commit is contained in:
小鱼开发
2026-05-23 10:16:28 +08:00
parent db34090d5d
commit bf51d8b423
2 changed files with 60 additions and 54 deletions
@@ -1089,6 +1089,17 @@
flex: 1;
}
/* 封面形象网格 — 复用 avatar-card 风格 */
.cover-avatar-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: var(--spacing-xl);
padding: var(--spacing-sm) var(--spacing-xs);
flex: 1;
align-content: start;
align-items: start;
}
/* Content Page Compact variant */
.content-page-compact {
gap: var(--spacing-md);
@@ -285,62 +285,57 @@ export default function CoverAvatarLibrary() {
<p className="empty-state-desc"><br />AI </p>
</div>
) : (
<div style={{ display: 'flex', flexDirection: 'column', gap: 16, flex: 1, overflow: 'auto' }}>
<div className="voice-list" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 16, alignContent: 'start', alignItems: 'start' }}>
{coverAvatars.map(a => (
<div key={a.id} className="voice-row" style={{ cursor: 'default', padding: 12 }}>
{/* 图片预览 */}
<div style={{ marginBottom: 10, borderRadius: 'var(--radius-md)', overflow: 'hidden', background: '#f5f5f5', aspectRatio: '1', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<img
src={a.imageUrl}
alt={a.name}
style={{ width: '100%', height: '100%', objectFit: 'contain' }}
loading="lazy"
/>
</div>
<div className="voice-row-main" style={{ padding: 0 }}>
<div className="voice-row-info" style={{ flex: 1, minWidth: 0 }}>
{editingId === a.id ? (
<input
type="text"
className="input"
value={editingName}
onChange={e => setEditingName(e.target.value)}
onKeyDown={e => {
if (e.key === 'Enter') {confirmRename();}
if (e.key === 'Escape') {cancelRename();}
}}
onBlur={confirmRename}
autoFocus
style={{ width: '100%', height: 28, padding: '2px 8px', fontSize: 'var(--font-sm)' }}
/>
) : (
<div className="voice-row-name" style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
{a.name}
</div>
)}
</div>
<div className="voice-row-actions">
<button
className="action-icon"
onClick={() => startRename(a.id, a.name)}
title="重命名"
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round"><path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z" /></svg>
</button>
<button
className="action-icon"
onClick={() => openDeleteModal(a.id, a.name)}
title="删除"
>
</button>
</div>
<div className="cover-avatar-grid">
{coverAvatars.map(a => (
<div key={a.id} className="avatar-card">
{/* 图片预览 */}
<div className="avatar-card-thumb-container">
<img
src={a.imageUrl}
alt={a.name}
className="avatar-card-video"
style={{ objectFit: 'contain', background: 'var(--bg-input)' }}
loading="lazy"
/>
{/* 悬停操作按钮 */}
<div className="avatar-card-actions">
<button
className="avatar-card-action-btn"
onClick={() => startRename(a.id, a.name)}
title="重命名"
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round"><path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z" /></svg>
</button>
<button
className="avatar-card-action-btn delete"
onClick={() => openDeleteModal(a.id, a.name)}
title="删除"
>
</button>
</div>
</div>
))}
</div>
{/* 名称 */}
<div className="avatar-card-info">
{editingId === a.id ? (
<input
type="text"
className="avatar-card-name-input"
value={editingName}
onChange={e => setEditingName(e.target.value)}
onKeyDown={e => {
if (e.key === 'Enter') {confirmRename();}
if (e.key === 'Escape') {cancelRename();}
}}
onBlur={confirmRename}
autoFocus
/>
) : (
<div className="avatar-card-name">{a.name}</div>
)}
</div>
</div>
))}
</div>
)}