itube-specs 0.0.902 → 0.0.910
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/icons/common/flag.svg +1 -1
- package/assets/icons/common/heart-stroke.svg +1 -1
- package/assets/icons/common/heart.svg +1 -1
- package/assets/icons/common/share.svg +1 -1
- package/assets/icons/common/thumbs-down-filled.svg +1 -0
- package/assets/icons/common/thumbs-down.svg +1 -1
- package/assets/icons/common/thumbs-up-filled.svg +1 -0
- package/assets/icons/common/thumbs-up.svg +1 -1
- package/assets/scss/themes/dark/_theme.scss +49 -19
- package/assets/scss/themes/light/_theme.scss +46 -16
- package/assets/scss/vars/_palette.scss +5 -0
- package/assets/scss/vars/_vars.scss +1 -0
- package/components/auth/login.vue +2 -2
- package/components/auth/recovery.vue +2 -2
- package/components/auth/register.vue +2 -2
- package/components/card/collections-more.vue +133 -0
- package/components/card/playlist.vue +6 -1
- package/components/grid/playlists.vue +3 -0
- package/components/info/main.vue +18 -14
- package/components/library/feed.vue +20 -39
- package/components/library/follows.vue +19 -4
- package/components/player/interface.vue +132 -58
- package/components/player/like.vue +82 -60
- package/components/playlist/add.vue +2 -2
- package/components/playlist/delete-video.vue +2 -2
- package/components/playlist/edit.vue +3 -3
- package/components/profile/delete.vue +2 -2
- package/components/profile/setup.vue +2 -2
- package/components/report/main.vue +9 -4
- package/components/search/input.vue +9 -9
- package/components/section/collections.vue +110 -0
- package/components/ui/follow-btn.vue +162 -0
- package/components/ui/section-title.vue +2 -0
- package/components/ui/snackbar.vue +93 -44
- package/composables/__tests__/use-snackbar.test.ts +126 -20
- package/composables/use-snackbar.ts +75 -20
- package/composables/use-user.ts +4 -4
- package/package.json +1 -1
- package/pages/contacts.vue +2 -2
- package/pages/library/index.vue +1 -1
- package/pages/playlists/index.vue +55 -4
- package/assets/icons/common/crest-in-circle.svg +0 -1
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
class="library-feed__tags"
|
|
60
60
|
hydrate-on-visible
|
|
61
61
|
micro
|
|
62
|
+
hide-more
|
|
62
63
|
/>
|
|
63
64
|
|
|
64
65
|
<p
|
|
@@ -86,22 +87,17 @@
|
|
|
86
87
|
</p>
|
|
87
88
|
</div>
|
|
88
89
|
|
|
89
|
-
<div class="library-feed__actions
|
|
90
|
-
<
|
|
91
|
-
:
|
|
92
|
-
|
|
93
|
-
@
|
|
94
|
-
|
|
95
|
-
<UiIcon
|
|
96
|
-
:name="following ? 'check' : 'plus'"
|
|
97
|
-
size="16"
|
|
98
|
-
/>
|
|
99
|
-
{{ following ? t('library.following_state') : t('follow') }}
|
|
100
|
-
</UiBtn>
|
|
90
|
+
<div class="library-feed__actions">
|
|
91
|
+
<UiFollowBtn
|
|
92
|
+
:following="following"
|
|
93
|
+
:name="item.title"
|
|
94
|
+
@toggle="emit('toggle-follow', item)"
|
|
95
|
+
/>
|
|
101
96
|
|
|
102
97
|
<UiLink
|
|
103
98
|
:to="item.to"
|
|
104
99
|
theme="secondary"
|
|
100
|
+
class="_from-sm"
|
|
105
101
|
>
|
|
106
102
|
{{ videosText }}
|
|
107
103
|
<UiIcon
|
|
@@ -112,10 +108,10 @@
|
|
|
112
108
|
</div>
|
|
113
109
|
</header>
|
|
114
110
|
|
|
115
|
-
<h3
|
|
111
|
+
<!-- <h3
|
|
116
112
|
v-if="item.feedTitle"
|
|
117
113
|
class="library-feed__feed-title"
|
|
118
|
-
>{{ item.feedTitle }}</h3>
|
|
114
|
+
>{{ item.feedTitle }}</h3> -->
|
|
119
115
|
|
|
120
116
|
<div class="library-feed__grid">
|
|
121
117
|
<CardVideo
|
|
@@ -128,7 +124,7 @@
|
|
|
128
124
|
/>
|
|
129
125
|
</div>
|
|
130
126
|
|
|
131
|
-
<UiLink
|
|
127
|
+
<!-- <UiLink
|
|
132
128
|
:to="item.to"
|
|
133
129
|
theme="secondary"
|
|
134
130
|
class="library-feed__all _to-sm"
|
|
@@ -139,7 +135,7 @@
|
|
|
139
135
|
name="arrow-right"
|
|
140
136
|
size="16"
|
|
141
137
|
/>
|
|
142
|
-
</UiLink>
|
|
138
|
+
</UiLink> -->
|
|
143
139
|
</article>
|
|
144
140
|
</template>
|
|
145
141
|
|
|
@@ -185,9 +181,6 @@ const ageText = computed(() => {
|
|
|
185
181
|
|
|
186
182
|
<style lang="scss">
|
|
187
183
|
.library-feed {
|
|
188
|
-
/* Растушёвка «ещё» у тегов уходит в фон карточки, а не страницы */
|
|
189
|
-
--expand-row-fade-end: #{$library-feed-fade};
|
|
190
|
-
|
|
191
184
|
@include from-br(sm) {
|
|
192
185
|
padding: 20px;
|
|
193
186
|
border: 1px solid $library-feed-border;
|
|
@@ -198,23 +191,15 @@ const ageText = computed(() => {
|
|
|
198
191
|
|
|
199
192
|
.library-feed__header {
|
|
200
193
|
display: grid;
|
|
201
|
-
grid-template-columns: auto minmax(0, 1fr);
|
|
194
|
+
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
202
195
|
column-gap: 16px;
|
|
203
196
|
row-gap: 12px;
|
|
204
197
|
align-items: center;
|
|
205
198
|
margin-bottom: 20px;
|
|
206
|
-
|
|
207
|
-
@include from-br(sm) {
|
|
208
|
-
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
209
|
-
}
|
|
210
199
|
}
|
|
211
200
|
|
|
212
201
|
.library-feed__header.--without-avatar {
|
|
213
|
-
grid-template-columns: minmax(0, 1fr);
|
|
214
|
-
|
|
215
|
-
@include from-br(sm) {
|
|
216
|
-
grid-template-columns: minmax(0, 1fr) auto;
|
|
217
|
-
}
|
|
202
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
218
203
|
}
|
|
219
204
|
|
|
220
205
|
.library-feed__avatar {
|
|
@@ -344,17 +329,13 @@ const ageText = computed(() => {
|
|
|
344
329
|
column-gap: 8px;
|
|
345
330
|
}
|
|
346
331
|
|
|
347
|
-
.library-
|
|
348
|
-
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
.library-feed__feed-title {
|
|
352
|
-
@include font-sm;
|
|
332
|
+
// .library-feed__feed-title {
|
|
333
|
+
// @include font-sm;
|
|
353
334
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}
|
|
335
|
+
// margin: 0 0 12px;
|
|
336
|
+
// font-weight: 400;
|
|
337
|
+
// color: $library-feed-title;
|
|
338
|
+
// }
|
|
358
339
|
|
|
359
340
|
.library-feed__grid {
|
|
360
341
|
display: grid;
|
|
@@ -84,10 +84,21 @@ function isFollowing(item: ILibraryFeedItem) {
|
|
|
84
84
|
return !unfollowed.value.includes(item.guid);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
function follow(guid: string) {
|
|
88
|
+
unfollowed.value = unfollowed.value.filter(item => item !== guid);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function unfollow(guid: string) {
|
|
92
|
+
unfollowed.value = [...unfollowed.value, guid];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Заглушка: подписка живёт в локальном стейте, API ещё нет. Снекбар с undo рисует сама кнопка. */
|
|
87
96
|
function onToggleFollow(item: ILibraryFeedItem) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
97
|
+
if (isFollowing(item)) {
|
|
98
|
+
unfollow(item.guid);
|
|
99
|
+
} else {
|
|
100
|
+
follow(item.guid);
|
|
101
|
+
}
|
|
91
102
|
}
|
|
92
103
|
</script>
|
|
93
104
|
|
|
@@ -106,6 +117,10 @@ function onToggleFollow(item: ILibraryFeedItem) {
|
|
|
106
117
|
|
|
107
118
|
.library-follows__list {
|
|
108
119
|
display: grid;
|
|
109
|
-
row-gap:
|
|
120
|
+
row-gap: 40px;
|
|
121
|
+
|
|
122
|
+
@include from-br(sm) {
|
|
123
|
+
row-gap: 24px;
|
|
124
|
+
}
|
|
110
125
|
}
|
|
111
126
|
</style>
|
|
@@ -6,49 +6,60 @@
|
|
|
6
6
|
:video-md5="data.md5"
|
|
7
7
|
:likes="data.likes"
|
|
8
8
|
:dislikes="data.dislikes"
|
|
9
|
-
|
|
10
|
-
<PlayerInfo
|
|
11
|
-
:created="data.created"
|
|
12
|
-
:views="data.views"
|
|
13
|
-
class="_from-sm"
|
|
9
|
+
class="player-interface__like"
|
|
14
10
|
/>
|
|
15
11
|
<div class="player-interface__wrapper">
|
|
16
|
-
<
|
|
12
|
+
<button
|
|
13
|
+
:class="{'--favorite': isFavorite}"
|
|
14
|
+
:aria-pressed="isFavorite"
|
|
15
|
+
type="button"
|
|
17
16
|
class="player-interface__button"
|
|
18
|
-
|
|
19
|
-
size="s"
|
|
20
|
-
@click="onAddPlaylistClick"
|
|
17
|
+
@click="isFavorite = !isFavorite"
|
|
21
18
|
>
|
|
22
19
|
<UiIcon
|
|
23
|
-
name="
|
|
24
|
-
|
|
20
|
+
:name="isFavorite ? 'heart' : 'heart-stroke'"
|
|
21
|
+
class="player-interface__button-icon"
|
|
22
|
+
size="24"
|
|
25
23
|
/>
|
|
26
|
-
<span class="
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
<span class="player-interface__button-label _to-sm">{{ t('favorite') }}</span>
|
|
25
|
+
<span class="player-interface__button-label _from-sm">{{ isFavorite ? t('favorite_remove') : t('favorite') }}</span>
|
|
26
|
+
</button>
|
|
27
|
+
<button
|
|
28
|
+
type="button"
|
|
29
29
|
class="player-interface__button"
|
|
30
|
-
|
|
31
|
-
size="s"
|
|
32
|
-
@click="openReportPopup(videoCard)"
|
|
30
|
+
@click="onAddPlaylistClick"
|
|
33
31
|
>
|
|
34
32
|
<UiIcon
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
class="player-interface__button-icon"
|
|
34
|
+
name="playlist"
|
|
35
|
+
size="24"
|
|
37
36
|
/>
|
|
38
|
-
<span class="
|
|
39
|
-
</
|
|
40
|
-
<
|
|
37
|
+
<span class="player-interface__button-label">{{ t('playlist.playlist') }}</span>
|
|
38
|
+
</button>
|
|
39
|
+
<button
|
|
40
|
+
type="button"
|
|
41
41
|
class="player-interface__button"
|
|
42
|
-
theme="muted"
|
|
43
|
-
size="s"
|
|
44
42
|
@click="isShareOpen = true"
|
|
45
43
|
>
|
|
46
44
|
<UiIcon
|
|
45
|
+
class="player-interface__button-icon"
|
|
47
46
|
name="share"
|
|
48
|
-
size="
|
|
47
|
+
size="24"
|
|
49
48
|
/>
|
|
50
|
-
<span class="
|
|
51
|
-
</
|
|
49
|
+
<span class="player-interface__button-label">{{ t('share') }}</span>
|
|
50
|
+
</button>
|
|
51
|
+
<button
|
|
52
|
+
type="button"
|
|
53
|
+
class="player-interface__button"
|
|
54
|
+
@click="openReportPopup(videoCard)"
|
|
55
|
+
>
|
|
56
|
+
<UiIcon
|
|
57
|
+
class="player-interface__button-icon"
|
|
58
|
+
name="flag"
|
|
59
|
+
size="24"
|
|
60
|
+
/>
|
|
61
|
+
<span class="player-interface__button-label">{{ t('report') }}</span>
|
|
62
|
+
</button>
|
|
52
63
|
</div>
|
|
53
64
|
</div>
|
|
54
65
|
<div
|
|
@@ -135,21 +146,13 @@ const { openReportPopup } = useReportPopup();
|
|
|
135
146
|
|
|
136
147
|
const isShareOpen = ref(false);
|
|
137
148
|
|
|
138
|
-
const
|
|
149
|
+
const isFavorite = ref(false);
|
|
139
150
|
|
|
140
151
|
const { isAuthorized } = useUser(AuthorizationApiService);
|
|
141
152
|
|
|
142
153
|
function onAddPlaylistClick() {
|
|
143
154
|
usePlaylistAdd().openPlaylistAdd(isAuthorized, props.data);
|
|
144
155
|
}
|
|
145
|
-
|
|
146
|
-
const isLiked = ref(false);
|
|
147
|
-
|
|
148
|
-
onMounted(() => {
|
|
149
|
-
isLiked.value = !!localStorage.getItem(props.data.guid);
|
|
150
|
-
resultLikes.value = localStorage.getItem(props.data.guid) ? resultLikes.value += 1 : resultLikes.value;
|
|
151
|
-
});
|
|
152
|
-
|
|
153
156
|
</script>
|
|
154
157
|
|
|
155
158
|
<style lang="scss">
|
|
@@ -158,40 +161,111 @@ onMounted(() => {
|
|
|
158
161
|
gap: 12px;
|
|
159
162
|
}
|
|
160
163
|
|
|
164
|
+
/* На мобиле лайк/дизлайк и кнопки действий — единый ряд из шести равных ячеек «иконка над
|
|
165
|
+
подписью»: обе обёртки становятся `display: contents`, чтобы их кнопки легли прямо в грид
|
|
166
|
+
заголовка. От sm возвращается десктопная раскладка — лайк-блок слева, пилюли справа. */
|
|
161
167
|
.player-interface__header {
|
|
162
|
-
display:
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
168
|
+
display: grid;
|
|
169
|
+
grid-template-columns: repeat(6, 1fr);
|
|
170
|
+
gap: 4px;
|
|
171
|
+
padding-block: 12px;
|
|
172
|
+
border-bottom: 1px solid $video-interface-mobile-border;
|
|
173
|
+
|
|
174
|
+
@include from-br(sm) {
|
|
175
|
+
display: flex;
|
|
176
|
+
align-items: center;
|
|
177
|
+
column-gap: 8px;
|
|
178
|
+
justify-content: space-between;
|
|
179
|
+
padding-block: 0;
|
|
180
|
+
border-bottom: none;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
166
183
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
scrollbar-width: none;
|
|
184
|
+
.player-like.player-interface__like {
|
|
185
|
+
display: contents;
|
|
170
186
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
187
|
+
@include from-br(sm) {
|
|
188
|
+
display: flex;
|
|
174
189
|
}
|
|
175
190
|
}
|
|
176
191
|
|
|
177
192
|
.player-interface__wrapper {
|
|
178
|
-
display:
|
|
179
|
-
|
|
180
|
-
|
|
193
|
+
display: contents;
|
|
194
|
+
|
|
195
|
+
@include from-br(sm) {
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
column-gap: 8px;
|
|
199
|
+
}
|
|
181
200
|
}
|
|
182
201
|
|
|
202
|
+
/* Нативный `<button>`, а не `<UiBtn>`: на мобиле у кнопки нет ни подложки, ни паддингов
|
|
203
|
+
пилюли, а перебить геометрию `.ui-btn.--s` из компонента-потребителя можно только
|
|
204
|
+
гонкой специфичности. Тему кнопка всё равно спрашивает через `button-variant()`. */
|
|
183
205
|
.player-interface__button {
|
|
184
|
-
@include font-
|
|
185
|
-
@include button-variant(interface-button);
|
|
206
|
+
@include font-xs;
|
|
186
207
|
|
|
187
|
-
display:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
padding: 6px 12px;
|
|
192
|
-
background-color: $video-interface-button-bg;
|
|
208
|
+
display: grid;
|
|
209
|
+
justify-items: center;
|
|
210
|
+
row-gap: 6px;
|
|
211
|
+
padding-block: 4px;
|
|
193
212
|
border-radius: $radius-lg;
|
|
194
|
-
color: $video-interface-
|
|
213
|
+
color: $video-interface-mobile-icon;
|
|
214
|
+
cursor: pointer;
|
|
215
|
+
transition: var(--transition) opacity;
|
|
216
|
+
|
|
217
|
+
@include from-br(sm) {
|
|
218
|
+
@include font-sm;
|
|
219
|
+
@include button-variant(interface-button);
|
|
220
|
+
|
|
221
|
+
grid-auto-flow: column;
|
|
222
|
+
align-items: center;
|
|
223
|
+
row-gap: 0;
|
|
224
|
+
column-gap: 6px;
|
|
225
|
+
padding: 6px 12px;
|
|
226
|
+
font-weight: 500;
|
|
227
|
+
white-space: nowrap;
|
|
228
|
+
background-color: var(--button-bg, #{$video-interface-button-bg});
|
|
229
|
+
color: var(--button-text, #{$video-interface-button-text});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
@include hover(background-color, color, opacity) {
|
|
233
|
+
background-color: var(--button-bg--hover, #{$video-interface-button-bg--hover});
|
|
234
|
+
color: var(--button-text--hover, #{$video-interface-button-text--hover});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.player-interface__button:active {
|
|
239
|
+
opacity: 0.7;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.player-interface__button.--favorite {
|
|
243
|
+
@include from-br(sm) {
|
|
244
|
+
background-color: $video-interface-button-bg--active;
|
|
245
|
+
color: $video-interface-button-text--active;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.player-interface__button-icon {
|
|
250
|
+
$size: 24px;
|
|
251
|
+
|
|
252
|
+
width: $size;
|
|
253
|
+
height: $size;
|
|
254
|
+
|
|
255
|
+
@include from-br(sm) {
|
|
256
|
+
$size: 16px;
|
|
257
|
+
|
|
258
|
+
width: $size;
|
|
259
|
+
height: $size;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.player-interface__button-label {
|
|
264
|
+
color: $video-interface-mobile-label;
|
|
265
|
+
|
|
266
|
+
@include from-br(sm) {
|
|
267
|
+
color: inherit;
|
|
268
|
+
}
|
|
195
269
|
}
|
|
196
270
|
|
|
197
271
|
.player-interface__description {
|
|
@@ -6,19 +6,18 @@
|
|
|
6
6
|
>
|
|
7
7
|
<button
|
|
8
8
|
:class="{'--active': isLiked}"
|
|
9
|
+
:aria-pressed="isLiked"
|
|
9
10
|
:title="t('like')"
|
|
10
11
|
class="player-like__control"
|
|
11
12
|
type="button"
|
|
12
13
|
@click="onReactionClick('like')"
|
|
13
14
|
>
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
</span>
|
|
21
|
-
<span class="player-like__control-text">{{ $n(Number(resultLikes), 'compact') }}</span>
|
|
15
|
+
<UiIcon
|
|
16
|
+
:name="isLiked ? 'thumbs-up-filled' : 'thumbs-up'"
|
|
17
|
+
class="player-like__control-icon"
|
|
18
|
+
size="24"
|
|
19
|
+
/>
|
|
20
|
+
<span class="player-like__count">{{ $n(Number(resultLikes), 'compact') }}</span>
|
|
22
21
|
</button>
|
|
23
22
|
<div
|
|
24
23
|
v-if="bar"
|
|
@@ -28,26 +27,21 @@
|
|
|
28
27
|
:style="{ width: likePercent + '%' }"
|
|
29
28
|
class="player-like__bar-likes"
|
|
30
29
|
/>
|
|
31
|
-
<div
|
|
32
|
-
:style="{ width: dislikePercent + '%' }"
|
|
33
|
-
class="player-like__bar-dislikes"
|
|
34
|
-
/>
|
|
35
30
|
</div>
|
|
36
31
|
<button
|
|
37
32
|
:class="{'--active': isDisliked}"
|
|
33
|
+
:aria-pressed="isDisliked"
|
|
38
34
|
:title="t('dislike')"
|
|
39
35
|
class="player-like__control"
|
|
40
36
|
type="button"
|
|
41
37
|
@click="onReactionClick('dislike')"
|
|
42
38
|
>
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
</span>
|
|
50
|
-
<span class="player-like__control-text">{{ $n(Math.abs(Number(resultDislikes)), 'compact') }}</span>
|
|
39
|
+
<UiIcon
|
|
40
|
+
:name="isDisliked ? 'thumbs-down-filled' : 'thumbs-down'"
|
|
41
|
+
class="player-like__control-icon"
|
|
42
|
+
size="24"
|
|
43
|
+
/>
|
|
44
|
+
<span class="player-like__count">{{ $n(Math.abs(Number(resultDislikes)), 'compact') }}</span>
|
|
51
45
|
</button>
|
|
52
46
|
</div>
|
|
53
47
|
</template>
|
|
@@ -126,9 +120,7 @@ async function onReactionClick(type: 'like' | 'dislike') {
|
|
|
126
120
|
}
|
|
127
121
|
}
|
|
128
122
|
|
|
129
|
-
const
|
|
130
|
-
const likePercent = computed(() => percents.value.likePercent);
|
|
131
|
-
const dislikePercent = computed(() => percents.value.dislikePercent);
|
|
123
|
+
const likePercent = computed(() => getReactionPercents(resultLikes.value, resultDislikes.value).likePercent);
|
|
132
124
|
</script>
|
|
133
125
|
|
|
134
126
|
<style lang="scss">
|
|
@@ -142,22 +134,59 @@ const dislikePercent = computed(() => percents.value.dislikePercent);
|
|
|
142
134
|
column-gap: 4px;
|
|
143
135
|
}
|
|
144
136
|
|
|
145
|
-
|
|
146
|
-
|
|
137
|
+
/* На мобиле контрол — вертикальная ячейка «иконка над числом», как в остальном мобильном
|
|
138
|
+
ряду действий; от sm возвращается в строку с числом сбоку. */
|
|
139
|
+
.player-like__control {
|
|
140
|
+
display: flex;
|
|
141
|
+
flex-direction: column;
|
|
142
|
+
align-items: center;
|
|
143
|
+
row-gap: 6px;
|
|
144
|
+
padding-block: 4px;
|
|
145
|
+
color: $like-mobile-icon;
|
|
146
|
+
cursor: pointer;
|
|
147
|
+
transition: var(--transition) color, var(--transition) opacity;
|
|
148
|
+
|
|
149
|
+
@include from-br(sm) {
|
|
150
|
+
flex-direction: row;
|
|
151
|
+
row-gap: 0;
|
|
152
|
+
column-gap: 6px;
|
|
153
|
+
padding: 6px;
|
|
154
|
+
border-radius: $radius-small;
|
|
155
|
+
color: $like-icon;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@include hover(color, opacity) {
|
|
159
|
+
color: $like-icon--hover;
|
|
160
|
+
}
|
|
147
161
|
}
|
|
148
162
|
|
|
149
|
-
.player-like__control {
|
|
150
|
-
|
|
163
|
+
.player-like__control:active {
|
|
164
|
+
opacity: 0.7;
|
|
165
|
+
}
|
|
151
166
|
|
|
152
|
-
|
|
153
|
-
|
|
167
|
+
.player-like__control.--active {
|
|
168
|
+
color: $like-icon--active;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.player-like.--mini .player-like__control {
|
|
172
|
+
flex-direction: row;
|
|
154
173
|
column-gap: 4px;
|
|
155
|
-
|
|
174
|
+
padding: 0;
|
|
175
|
+
|
|
176
|
+
/* Только до sm: от sm цвет и так берётся из базового правила, а трёхклассовый
|
|
177
|
+
селектор перебивал бы им ховер. */
|
|
178
|
+
@include to-br(sm) {
|
|
179
|
+
color: $like-icon;
|
|
180
|
+
}
|
|
156
181
|
}
|
|
157
182
|
|
|
158
183
|
.player-like__control-icon {
|
|
159
|
-
|
|
160
|
-
|
|
184
|
+
@include from-br(sm) {
|
|
185
|
+
$size: 16px;
|
|
186
|
+
|
|
187
|
+
width: $size;
|
|
188
|
+
height: $size;
|
|
189
|
+
}
|
|
161
190
|
}
|
|
162
191
|
|
|
163
192
|
.--mini .player-like__control-icon {
|
|
@@ -167,50 +196,43 @@ const dislikePercent = computed(() => percents.value.dislikePercent);
|
|
|
167
196
|
height: $size;
|
|
168
197
|
}
|
|
169
198
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
199
|
+
.player-like__count {
|
|
200
|
+
@include font-xs;
|
|
173
201
|
|
|
174
|
-
|
|
175
|
-
min-width: auto;
|
|
176
|
-
}
|
|
202
|
+
color: $like-mobile-count;
|
|
177
203
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
color: $like-text--hover;
|
|
204
|
+
@include from-br(sm) {
|
|
205
|
+
color: $like-count;
|
|
181
206
|
}
|
|
182
207
|
}
|
|
183
208
|
|
|
184
|
-
|
|
185
|
-
color: $like-
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.player-like__control.--active .player-like__control-icon.--dislike {
|
|
189
|
-
color: $like-icon-dislike--active;
|
|
209
|
+
.--mini .player-like__count {
|
|
210
|
+
color: $like-count;
|
|
190
211
|
}
|
|
191
212
|
|
|
192
213
|
.player-like__bar {
|
|
193
|
-
display:
|
|
214
|
+
display: none;
|
|
215
|
+
width: 64px;
|
|
194
216
|
height: 6px;
|
|
217
|
+
margin-inline: 4px;
|
|
195
218
|
border-radius: $radius-full;
|
|
196
219
|
overflow: hidden;
|
|
197
220
|
background-color: $like-bar-bg;
|
|
198
|
-
width: 40px;
|
|
199
|
-
}
|
|
200
221
|
|
|
201
|
-
|
|
202
|
-
|
|
222
|
+
@include from-br(sm) {
|
|
223
|
+
display: flex;
|
|
224
|
+
width: 48px;
|
|
225
|
+
height: 4px;
|
|
226
|
+
}
|
|
203
227
|
}
|
|
204
228
|
|
|
205
|
-
.player-like__bar
|
|
206
|
-
|
|
229
|
+
.--mini .player-like__bar {
|
|
230
|
+
display: flex;
|
|
231
|
+
width: 36px;
|
|
207
232
|
}
|
|
208
233
|
|
|
209
|
-
.player-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
text-overflow: ellipsis;
|
|
213
|
-
white-space: nowrap;
|
|
214
|
-
overflow: hidden;
|
|
234
|
+
.player-like__bar-likes {
|
|
235
|
+
background-color: $like-bar-likes;
|
|
236
|
+
border-radius: $radius-full;
|
|
215
237
|
}
|
|
216
238
|
</style>
|
|
@@ -261,7 +261,7 @@ const postVideoForm = computed(() => ({
|
|
|
261
261
|
duration: videoCard.value?.duration ?? 0,
|
|
262
262
|
}));
|
|
263
263
|
|
|
264
|
-
const { setErrorState,
|
|
264
|
+
const { setErrorState, show, showError } = useSnackbar();
|
|
265
265
|
|
|
266
266
|
async function onSaveClick() {
|
|
267
267
|
let newPlaylist: IPlaylistShort | undefined;
|
|
@@ -293,7 +293,7 @@ async function onSaveClick() {
|
|
|
293
293
|
newPlaylist,
|
|
294
294
|
});
|
|
295
295
|
closePopup();
|
|
296
|
-
|
|
296
|
+
show('video_added');
|
|
297
297
|
} catch (error) {
|
|
298
298
|
setErrorState(error);
|
|
299
299
|
console.log(error, 'error add video to playlist');
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
import { PlaylistStep } from '../../runtime';
|
|
48
48
|
|
|
49
49
|
const { isPlaylistEditOpen, closePlaylistEdit, currentStep, selectedPlaylist, deletedVideo } = usePlaylistEdit();
|
|
50
|
-
const {
|
|
50
|
+
const { show } = useSnackbar();
|
|
51
51
|
|
|
52
52
|
const props = defineProps<{
|
|
53
53
|
loadingDeleteVideo: boolean
|
|
@@ -71,7 +71,7 @@ async function onBinClick() {
|
|
|
71
71
|
playlistId: playlistId.value,
|
|
72
72
|
deletedVideoId: deletedVideo.value?.id || ''
|
|
73
73
|
});
|
|
74
|
-
|
|
74
|
+
show('video_removed');
|
|
75
75
|
closePlaylistEdit();
|
|
76
76
|
} catch {
|
|
77
77
|
console.log('error delete');
|
|
@@ -147,7 +147,7 @@ const inputValue = ref('');
|
|
|
147
147
|
const toggleValue = ref(false);
|
|
148
148
|
|
|
149
149
|
const { isPlaylistEditOpen, closePlaylistEdit, currentStep, selectedPlaylist, openPlaylistEdit } = usePlaylistEdit();
|
|
150
|
-
const {
|
|
150
|
+
const { show } = useSnackbar();
|
|
151
151
|
|
|
152
152
|
const route = useRoute();
|
|
153
153
|
const id = computed(() => route.params[ 'playlistId' ] ? String(route.params[ 'playlistId' ]) : selectedPlaylist.value?.id);
|
|
@@ -168,7 +168,7 @@ const playlistsData = useState<IPlaylistData>(`data-${AsyncData.PlaylistById}-${
|
|
|
168
168
|
async function onDeleteClick() {
|
|
169
169
|
try {
|
|
170
170
|
emit('delete-playlist', id.value || '');
|
|
171
|
-
|
|
171
|
+
show('playlist_deleted');
|
|
172
172
|
closePlaylistEdit();
|
|
173
173
|
} catch {
|
|
174
174
|
console.log('error delete');
|
|
@@ -190,7 +190,7 @@ async function onSaveClick() {
|
|
|
190
190
|
playlistsData.value.playlistType = playlistType;
|
|
191
191
|
}
|
|
192
192
|
closePlaylistEdit();
|
|
193
|
-
|
|
193
|
+
show('changes_soon');
|
|
194
194
|
} catch {
|
|
195
195
|
console.log('error save');
|
|
196
196
|
}
|