11<template >
22 <div class =" copy-lyrics" >
3-
43 <n-scrollbar class =" lyrics-list" >
54 <n-checkbox-group v-model:value =" selectedLines" >
6- <div v-for =" line in displayLyrics" :key =" line.index" class =" lyric-item" >
7- <n-checkbox :value =" line.index" class =" lyric-checkbox" >
8- <div class =" lyric-content" >
9- <div v-if =" showOriginal && line.text" class =" text" >{{ line.text }}</div >
10- <div v-if =" showTranslation && line.translation" class =" translation" >
11- {{ line.translation }}
12- </div >
13- <div v-if =" showRomaji && line.romaji" class =" romaji" >{{ line.romaji }}</div >
14- </div >
15- </n-checkbox >
16- </div >
5+ <n-list hoverable >
6+ <n-list-item v-for =" line in displayLyrics" :key =" line.index" >
7+ <n-checkbox :value =" line.index" class =" lyric-checkbox" >
8+ <n-flex size =" small" class =" lyric-content" vertical >
9+ <n-text v-if =" line.text" class =" text" >{{ line.text }}</n-text >
10+ <n-text v-if =" showTranslation && line.translation" depth =" 1" class =" translation" >
11+ {{ line.translation }}
12+ </n-text >
13+ <n-text v-if =" showRomaji && line.romaji" depth =" 3" class =" romaji" >
14+ {{ line.romaji }}
15+ </n-text >
16+ </n-flex >
17+ </n-checkbox >
18+ </n-list-item >
19+ </n-list >
1720 </n-checkbox-group >
1821 </n-scrollbar >
19-
20- <div class =" footer" >
21- <div class =" filters" >
22+ <n-flex align =" center" justify =" space-between" class =" footer" >
23+ <n-flex align =" center" >
2224 <n-checkbox-group v-model:value =" selectedFilters" >
23- <n-space >
24- <n-checkbox value =" original" label =" 原词" />
25+ <n-flex align =" center" >
2526 <n-checkbox value =" translation" label =" 翻译" />
2627 <n-checkbox value =" romaji" label =" 音译" />
27- </n-space >
28+ </n-flex >
2829 </n-checkbox-group >
29- </div >
30- <div class =" actions" >
31- <n-button class =" action-btn" @click =" selectAll" >全选</n-button >
32- <n-button
33- class =" action-btn"
34- type =" primary"
35- :disabled =" selectedLines.length === 0"
36- @click =" handleCopy"
37- >
30+ </n-flex >
31+ <n-flex align =" center" >
32+ <n-button @click =" selectAll" >全选</n-button >
33+ <n-button type =" primary" :disabled =" selectedLines.length === 0" @click =" handleCopy" >
3834 复制 ({{ selectedLines.length }})
3935 </n-button >
40- </div >
41- </div >
36+ </n-flex >
37+ </n-flex >
4238 </div >
4339</template >
4440
4541<script setup lang="ts">
4642import { useMusicStore } from " @/stores" ;
47- import { useClipboard } from " @vueuse/core " ;
43+ import { copyData } from " @/utils/helper " ;
4844
49- const props = defineProps <{
50- onClose: () => void ;
51- }>();
45+ const props = defineProps <{ onClose: () => void }>();
5246
5347const musicStore = useMusicStore ();
54- const { copy } = useClipboard ();
5548
56- const selectedFilters = ref <string []>([" original " , " translation" , " romaji" ]);
49+ const selectedFilters = ref <string []>([" translation" , " romaji" ]);
5750const selectedLines = ref <number []>([]);
5851
5952const rawLyrics = computed (() => {
@@ -77,7 +70,6 @@ const displayLyrics = computed(() => {
7770 });
7871});
7972
80- const showOriginal = computed (() => selectedFilters .value .includes (" original" ));
8173const showTranslation = computed (() => selectedFilters .value .includes (" translation" ));
8274const showRomaji = computed (() => selectedFilters .value .includes (" romaji" ));
8375
@@ -89,12 +81,15 @@ const selectAll = () => {
8981 }
9082};
9183
84+ /**
85+ * 复制歌词
86+ */
9287const handleCopy = async () => {
9388 const linesToCopy = displayLyrics .value
9489 .filter ((l ) => selectedLines .value .includes (l .index ))
9590 .map ((l ) => {
9691 const parts: string [] = [];
97- if (showOriginal . value && l .text ) parts .push (l .text );
92+ if (l .text ) parts .push (l .text );
9893 if (showTranslation .value && l .translation ) parts .push (l .translation );
9994 if (showRomaji .value && l .romaji ) parts .push (l .romaji );
10095 return parts .join (" \n " );
@@ -103,8 +98,7 @@ const handleCopy = async () => {
10398 .join (" \n\n " );
10499
105100 if (linesToCopy ) {
106- await copy (linesToCopy );
107- window .$message .success (" 复制成功" );
101+ await copyData (linesToCopy );
108102 props .onClose ();
109103 } else {
110104 window .$message .warning (" 没有可复制的内容" );
@@ -120,68 +114,27 @@ const handleCopy = async () => {
120114 width : 100% ;
121115}
122116
123-
124117.lyrics-list {
125118 flex : 1 ;
126- padding : 12px 20px ;
127-
128- .lyric-item {
129- margin-bottom : 12px ;
130- padding : 8px ;
131- border-radius : 8px ;
132- transition : background-color 0.2s ;
133119
134- & :hover {
135- background-color : rgba (0 , 0 , 0 , 0.05 );
136- }
137-
138- .lyric-checkbox {
139- width : 100% ;
140- align-items : flex-start ;
120+ .lyric-checkbox {
121+ width : 100% ;
122+ }
141123
142- :deep (.n-checkbox__label ) {
143- flex : 1 ;
144- }
124+ .lyric-content {
125+ font-size : 14px ;
126+ line-height : 1.6 ;
127+ .translation {
128+ font-size : 12px ;
145129 }
146-
147- .lyric-content {
148- font-size : 14px ;
149- line-height : 1.6 ;
150-
151- .text {
152- font-weight : 500 ;
153- }
154- .translation {
155- color : var (--n-text-color-3 );
156- font-size : 13px ;
157- }
158- .romaji {
159- color : var (--n-text-color-3 );
160- font-size : 12px ;
161- font-style : italic ;
162- }
130+ .romaji {
131+ font-size : 12px ;
132+ font-style : italic ;
163133 }
164134 }
165135}
166136
167137.footer {
168- padding : 16px 20px ;
169- display : flex ;
170- justify-content : space-between ;
171- align-items : center ;
172- border-top : 1px solid var (--n-border-color );
173-
174- .filters {
175- display : flex ;
176- align-items : center ;
177- }
178-
179- .actions {
180- display : flex ;
181- gap : 12px ;
182- .action-btn {
183- width : 90px ;
184- }
185- }
138+ margin-top : 20px ;
186139}
187140 </style >
0 commit comments