feat: reveal secondary song actions on hover

This commit is contained in:
DiheChen committed 2026-11-05 12:26:31 +08:00
1 parent a4805e957d
commit baa69f74b0
4 files changed
+11 -4

No files matched your search

+1 -1
View File
@@ -48,7 +48,7 @@ function HistoryRow({ record, compact, connected, playing }: { record: PlayRecor
/>
<IconButton
icon={Trash2}
className="song-action"
className="song-action song-action-secondary"
label={`删除${bookTitle(title)}的播放记录`}
onClick={() => {
historyStore.removePlay(record)
+2 -2
View File
@@ -74,8 +74,8 @@ export function QueuePage({ compact = false }: { compact?: boolean }) {
<SongList
songs={items.map(songItem)}
actions={song => [
{ icon: Heart, label: `点赞${bookTitle(song.title)}`, disabled: !connected, run: () => likeEntry(song.key, song.title) },
{ icon: Trash2, label: `移除${bookTitle(song.title)}`, disabled: !connected, run: () => removeEntry(song.key, song.title) },
{ icon: Heart, label: `点赞${bookTitle(song.title)}`, disabled: !connected, secondary: true, run: () => likeEntry(song.key, song.title) },
{ icon: Trash2, label: `移除${bookTitle(song.title)}`, disabled: !connected, secondary: true, run: () => removeEntry(song.key, song.title) },
]}
/>
)
+3 -1
View File
@@ -24,6 +24,8 @@ export interface SongAction {
icon: LucideIcon
label: string
disabled?: boolean
// 次要操作只在鼠标移到这一行时出现。
secondary?: boolean
run: () => Promise<void>
}
@@ -47,7 +49,7 @@ export function SongList({ songs, actions }: { songs: SongItem[], actions: (song
<span className="song-album text-ui-sm muted truncate">{song.album}</span>
<span className="song-duration text-ui-sm muted">{song.durationMs > 0 ? formatDuration(song.durationMs) : ''}</span>
{actions(song, index).map(action => (
<AsyncIconButton key={action.label} icon={action.icon} className="song-action" label={action.label} disabled={action.disabled} onAction={action.run} />
<AsyncIconButton key={action.label} icon={action.icon} className={action.secondary ? 'song-action song-action-secondary' : 'song-action'} label={action.label} disabled={action.disabled} onAction={action.run} />
))}
</li>
))}
+5
View File
@@ -62,6 +62,11 @@
.song-action:hover:not(:disabled), .song-action:focus-visible:not(:disabled) { color: var(--color-brand); background: transparent; }
.song-action:active:not(:disabled) { color: var(--color-brand); background: transparent; transform: none; }
.song-action[aria-busy='true'] { cursor: progress; opacity: .7; color: var(--color-brand); }
/* 触屏没有悬停,按钮要一直显示。占位不变,出现时这一行的文字不会跳动。 */
@media (hover: hover) {
.song-action-secondary { opacity: 0; transition: opacity 120ms ease; }
.song-row:hover .song-action-secondary, .song-row:focus-within .song-action-secondary, .song-action-secondary[aria-busy='true'] { opacity: 1; }
}
.song-index { width: 22px; flex-shrink: 0; }
.song-copy { display: flex; flex-direction: column; min-width: 0; gap: 3px; flex: 1; }
.song-title { display: flex; align-items: center; gap: 8px; min-width: 0; }