feat(task-3.11): 升级配音库页面 — Tab分类+网格卡片+CosyVoice API预留
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,175 +1,112 @@
|
||||
/**
|
||||
* 配音库页面 - V21 设计系统样式
|
||||
* 两栏布局:左侧配音库分类列表(260px)+ 右侧配音卡片列表
|
||||
* 配音库页面 - V21 设计系统样式(任务 3.11 升级)
|
||||
* Tab 分类布局 + 网格卡片展示
|
||||
* 统一使用 CSS 变量,支持深色/浅色主题
|
||||
*/
|
||||
@import "../../styles/global.css";
|
||||
|
||||
/* ============================================================
|
||||
页面容器
|
||||
============================================================ */
|
||||
.xx-voices-page {
|
||||
min-height: 100%;
|
||||
padding: var(--space-xl);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
两栏布局
|
||||
============================================================ */
|
||||
.xx-voices-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 260px 1fr;
|
||||
gap: 20px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
左侧配音库列表
|
||||
============================================================ */
|
||||
.xx-voice-library-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-sm);
|
||||
position: sticky;
|
||||
top: var(--space-md);
|
||||
}
|
||||
|
||||
.xx-voice-library-item {
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--bg-primary);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 14px;
|
||||
cursor: pointer;
|
||||
transition: var(--transition-all);
|
||||
}
|
||||
|
||||
.xx-voice-library-item:hover {
|
||||
border-color: var(--primary-color);
|
||||
background: var(--primary-soft);
|
||||
}
|
||||
|
||||
.xx-voice-library-item.active {
|
||||
border-color: var(--primary-color);
|
||||
background: var(--primary-soft);
|
||||
box-shadow: var(--shadow-primary);
|
||||
}
|
||||
|
||||
.xx-voice-library-item h4 {
|
||||
margin: 0 0 4px;
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--text-primary);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.xx-voice-library-item span {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.xx-voice-library-delete {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--text-tertiary);
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: var(--radius-xs);
|
||||
font-size: var(--font-size-sm);
|
||||
transition: var(--transition-all);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.xx-voice-library-item:hover .xx-voice-library-delete {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.xx-voice-library-delete:hover {
|
||||
color: var(--error-color);
|
||||
background: var(--error-soft);
|
||||
}
|
||||
|
||||
.xx-voice-library-add {
|
||||
border: 1px dashed var(--border-color);
|
||||
background: transparent;
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 14px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-sm);
|
||||
transition: var(--transition-all);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.xx-voice-library-add:hover {
|
||||
border-color: var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
background: var(--primary-soft);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
右侧内容区
|
||||
============================================================ */
|
||||
.xx-voices-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-lg);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
筛选栏
|
||||
============================================================ */
|
||||
.xx-voices-actions {
|
||||
display: flex;
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
/* Tab 切换 */
|
||||
.xx-voices-tabs {
|
||||
display: flex;
|
||||
gap: var(--space-xs);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.xx-voices-tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-xs);
|
||||
padding: var(--space-sm) var(--space-lg);
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-medium);
|
||||
cursor: pointer;
|
||||
transition: var(--transition-all);
|
||||
border-bottom: 2px solid transparent;
|
||||
margin-bottom: -1px;
|
||||
border-radius: var(--radius-sm) var(--radius-sm) 0 0;
|
||||
}
|
||||
|
||||
.xx-voices-tab:hover {
|
||||
color: var(--primary-color);
|
||||
background: var(--primary-soft);
|
||||
}
|
||||
|
||||
.xx-voices-tab.active {
|
||||
color: var(--primary-color);
|
||||
border-bottom-color: var(--primary-color);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
}
|
||||
|
||||
.xx-voices-tab-count {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 20px;
|
||||
height: 20px;
|
||||
padding: 0 6px;
|
||||
border-radius: var(--radius-full);
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text-tertiary);
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
.xx-voices-tab.active .xx-voices-tab-count {
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.xx-voices-tab-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-lg);
|
||||
}
|
||||
|
||||
.xx-voices-filters {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-md);
|
||||
gap: var(--space-sm);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.xx-voices-filters-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
/* 网格 */
|
||||
.xx-voice-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
|
||||
gap: var(--space-md);
|
||||
}
|
||||
|
||||
.xx-voices-filters-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
配音卡片列表
|
||||
============================================================ */
|
||||
.xx-voice-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
配音卡片
|
||||
============================================================ */
|
||||
/* 卡片 */
|
||||
.xx-voice-card {
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--bg-primary);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-md);
|
||||
display: grid;
|
||||
grid-template-columns: 50px 1fr auto auto;
|
||||
gap: 14px;
|
||||
align-items: center;
|
||||
grid-template-columns: 48px 1fr auto;
|
||||
grid-template-rows: auto auto auto;
|
||||
gap: var(--space-sm) var(--space-md);
|
||||
align-items: start;
|
||||
transition: var(--transition-all);
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.xx-voice-card:hover {
|
||||
@@ -177,70 +114,182 @@
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
/* 头像 */
|
||||
.xx-voice-card.selected {
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: var(--shadow-primary);
|
||||
}
|
||||
|
||||
.xx-voice-card.playing {
|
||||
border-color: var(--secondary-color);
|
||||
}
|
||||
|
||||
.xx-voice-avatar {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: var(--radius-full);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: #fff;
|
||||
font-size: 22px;
|
||||
color: var(--text-inverse);
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
grid-row: 1 / 3;
|
||||
transition: var(--transition-all);
|
||||
}
|
||||
|
||||
/* 头像背景色(CSS 变量,无硬编码) */
|
||||
.xx-voice-card.xx-voice-gender--male .xx-voice-avatar {
|
||||
background: linear-gradient(135deg, var(--color-primary-700) 0%, var(--primary-color) 50%, var(--color-primary-400) 100%);
|
||||
}
|
||||
|
||||
.xx-voice-card.xx-voice-gender--female .xx-voice-avatar {
|
||||
background: linear-gradient(135deg, var(--color-secondary-700, #9d174d) 0%, var(--color-secondary-500, #db2777) 50%, var(--color-secondary-400, #ec4899) 100%);
|
||||
}
|
||||
|
||||
.xx-voice-card.xx-voice-gender--child .xx-voice-avatar {
|
||||
background: linear-gradient(135deg, var(--color-accent-700, #065f46) 0%, var(--secondary-color) 50%, var(--color-secondary-400, #34d399) 100%);
|
||||
}
|
||||
|
||||
.xx-voice-card.xx-voice-gender--elderly .xx-voice-avatar {
|
||||
background: linear-gradient(135deg, var(--color-accent-700, #92400e) 0%, var(--accent-color) 50%, var(--color-accent-400, #fbbf24) 100%);
|
||||
}
|
||||
|
||||
/* 信息区 */
|
||||
.xx-voice-info {
|
||||
min-width: 0;
|
||||
grid-column: 2 / -1;
|
||||
}
|
||||
|
||||
.xx-voice-name-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.xx-voice-name {
|
||||
margin: 0 0 4px;
|
||||
margin: 0;
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--text-primary);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.xx-voice-meta {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--text-secondary);
|
||||
.xx-voice-star {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--text-tertiary);
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
font-size: var(--font-size-base);
|
||||
transition: var(--transition-all);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-xs);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* 波形可视化 */
|
||||
.xx-voice-wave {
|
||||
height: 24px;
|
||||
width: 120px;
|
||||
.xx-voice-card:hover .xx-voice-star {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.xx-voice-star.active {
|
||||
opacity: 1;
|
||||
color: var(--accent-color);
|
||||
}
|
||||
|
||||
.xx-voice-star:hover {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.xx-voice-subtitle {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--text-secondary);
|
||||
margin-top: 2px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.xx-voice-tags {
|
||||
display: flex;
|
||||
gap: var(--space-xs);
|
||||
flex-wrap: wrap;
|
||||
margin-top: var(--space-xs);
|
||||
}
|
||||
|
||||
.xx-voice-tag {
|
||||
padding: 2px 8px;
|
||||
border-radius: var(--radius-full);
|
||||
background: repeating-linear-gradient(
|
||||
90deg,
|
||||
var(--primary-color) 0 5px,
|
||||
transparent 5px 10px
|
||||
);
|
||||
opacity: 0.3;
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-medium);
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
/* 状态 */
|
||||
.xx-voice-status {
|
||||
grid-column: 3;
|
||||
grid-row: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: var(--font-size-xs);
|
||||
padding: 2px 8px;
|
||||
border-radius: var(--radius-full);
|
||||
}
|
||||
|
||||
.xx-voice-status--processing {
|
||||
background: var(--warning-soft, #fef3c7);
|
||||
color: var(--warning-color, #92400e);
|
||||
}
|
||||
|
||||
.xx-voice-status--failed {
|
||||
background: var(--error-soft);
|
||||
color: var(--error-color);
|
||||
}
|
||||
|
||||
.xx-voice-status-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: var(--radius-full);
|
||||
background: var(--warning-color, #92400e);
|
||||
animation: xx-pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes xx-pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.3; }
|
||||
}
|
||||
|
||||
/* 波形 */
|
||||
.xx-voice-wave {
|
||||
grid-column: 1 / -1;
|
||||
height: 20px;
|
||||
border-radius: var(--radius-full);
|
||||
background: repeating-linear-gradient(90deg, var(--primary-color) 0 4px, transparent 4px 8px);
|
||||
opacity: 0.15;
|
||||
transition: var(--transition-all);
|
||||
}
|
||||
|
||||
.xx-voice-card:hover .xx-voice-wave {
|
||||
opacity: 0.5;
|
||||
.xx-voice-card:hover .xx-voice-wave { opacity: 0.3; }
|
||||
.xx-voice-card.playing .xx-voice-wave { opacity: 0.5; animation: xx-wave-pulse 0.8s ease-in-out infinite; }
|
||||
|
||||
@keyframes xx-wave-pulse {
|
||||
0%, 100% { opacity: 0.5; }
|
||||
50% { opacity: 0.3; }
|
||||
}
|
||||
|
||||
/* 播放控制区 */
|
||||
/* 播放控制 */
|
||||
.xx-voice-controls {
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.xx-voice-play-btn {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: var(--radius-full);
|
||||
background: var(--gradient-primary);
|
||||
color: var(--text-inverse);
|
||||
@@ -253,16 +302,9 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.xx-voice-play-btn:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: var(--shadow-primary);
|
||||
}
|
||||
.xx-voice-play-btn:hover { transform: scale(1.1); box-shadow: var(--shadow-primary); }
|
||||
.xx-voice-play-btn:active { transform: scale(0.95); }
|
||||
|
||||
.xx-voice-play-btn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
/* 进度条 */
|
||||
.xx-voice-progress {
|
||||
flex: 1;
|
||||
height: 4px;
|
||||
@@ -270,9 +312,10 @@
|
||||
border-radius: var(--radius-full);
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.xx-voice-progress:hover { height: 6px; }
|
||||
|
||||
.xx-voice-progress-bar {
|
||||
height: 100%;
|
||||
background: var(--gradient-primary);
|
||||
@@ -285,27 +328,10 @@
|
||||
color: var(--text-tertiary);
|
||||
white-space: nowrap;
|
||||
min-width: 40px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* 标签 */
|
||||
.xx-voice-tags {
|
||||
display: flex;
|
||||
gap: var(--space-xs);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.xx-voice-tag {
|
||||
padding: 2px 8px;
|
||||
border-radius: var(--radius-full);
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-medium);
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
空状态
|
||||
============================================================ */
|
||||
/* 空状态 */
|
||||
.xx-voices-empty {
|
||||
text-align: center;
|
||||
padding: var(--space-3xl) var(--space-xl);
|
||||
@@ -313,83 +339,57 @@
|
||||
}
|
||||
|
||||
.xx-voices-empty-icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: var(--space-md);
|
||||
opacity: 0.5;
|
||||
font-size: 56px;
|
||||
margin-bottom: var(--space-lg);
|
||||
opacity: 0.3;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
响应式
|
||||
============================================================ */
|
||||
.xx-voices-empty h3 {
|
||||
margin: 0 0 var(--space-sm);
|
||||
font-size: var(--font-size-lg);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.xx-voices-empty p {
|
||||
margin: 0 0 var(--space-lg);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* 提示条 */
|
||||
.xx-voices-notice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary-color);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--font-size-sm);
|
||||
border: 1px solid color-mix(in srgb, var(--primary-color) 20%, transparent);
|
||||
}
|
||||
|
||||
/* 响应式 */
|
||||
@media (max-width: 1200px) {
|
||||
.xx-voices-layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.xx-voice-library-list {
|
||||
flex-direction: row;
|
||||
overflow-x: auto;
|
||||
position: static;
|
||||
gap: var(--space-sm);
|
||||
padding-bottom: var(--space-sm);
|
||||
}
|
||||
|
||||
.xx-voice-library-item {
|
||||
min-width: 180px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.xx-voice-card {
|
||||
grid-template-columns: 50px 1fr;
|
||||
grid-template-rows: auto auto;
|
||||
}
|
||||
|
||||
.xx-voice-wave {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.xx-voice-controls {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
.xx-voice-grid { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.xx-voices-page {
|
||||
padding: var(--space-md);
|
||||
}
|
||||
|
||||
.xx-voice-card {
|
||||
padding: var(--space-sm);
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
.xx-voice-controls {
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
.xx-voices-filters {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.xx-voices-filters-left,
|
||||
.xx-voices-filters-right {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.xx-voices-page { padding: var(--space-md); gap: var(--space-md); }
|
||||
.xx-voice-grid { grid-template-columns: 1fr; }
|
||||
.xx-voice-card { padding: var(--space-sm); gap: var(--space-xs) var(--space-sm); }
|
||||
.xx-voices-filters { flex-direction: column; align-items: stretch; }
|
||||
.xx-voices-filters .xx-input, .xx-voices-filters .xx-select { width: 100% !important; }
|
||||
.xx-voices-tab { padding: var(--space-xs) var(--space-md); font-size: var(--font-size-sm); }
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.xx-voices-page {
|
||||
padding: var(--space-sm);
|
||||
}
|
||||
|
||||
.xx-voice-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.xx-voice-controls {
|
||||
min-width: 120px;
|
||||
}
|
||||
.xx-voices-page { padding: var(--space-sm); }
|
||||
.xx-voice-avatar { width: 40px; height: 40px; font-size: 16px; }
|
||||
.xx-voice-card { grid-template-columns: 40px 1fr; }
|
||||
.xx-voice-wave { height: 14px; }
|
||||
.xx-voice-play-btn { width: 28px; height: 28px; font-size: var(--font-size-sm); }
|
||||
.xx-voices-tab { padding: var(--space-xs) var(--space-sm); font-size: var(--font-size-xs); }
|
||||
.xx-voices-tab-count { min-width: 16px; height: 16px; font-size: 10px; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user