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.
Files changed (42) hide show
  1. package/assets/icons/common/flag.svg +1 -1
  2. package/assets/icons/common/heart-stroke.svg +1 -1
  3. package/assets/icons/common/heart.svg +1 -1
  4. package/assets/icons/common/share.svg +1 -1
  5. package/assets/icons/common/thumbs-down-filled.svg +1 -0
  6. package/assets/icons/common/thumbs-down.svg +1 -1
  7. package/assets/icons/common/thumbs-up-filled.svg +1 -0
  8. package/assets/icons/common/thumbs-up.svg +1 -1
  9. package/assets/scss/themes/dark/_theme.scss +49 -19
  10. package/assets/scss/themes/light/_theme.scss +46 -16
  11. package/assets/scss/vars/_palette.scss +5 -0
  12. package/assets/scss/vars/_vars.scss +1 -0
  13. package/components/auth/login.vue +2 -2
  14. package/components/auth/recovery.vue +2 -2
  15. package/components/auth/register.vue +2 -2
  16. package/components/card/collections-more.vue +133 -0
  17. package/components/card/playlist.vue +6 -1
  18. package/components/grid/playlists.vue +3 -0
  19. package/components/info/main.vue +18 -14
  20. package/components/library/feed.vue +20 -39
  21. package/components/library/follows.vue +19 -4
  22. package/components/player/interface.vue +132 -58
  23. package/components/player/like.vue +82 -60
  24. package/components/playlist/add.vue +2 -2
  25. package/components/playlist/delete-video.vue +2 -2
  26. package/components/playlist/edit.vue +3 -3
  27. package/components/profile/delete.vue +2 -2
  28. package/components/profile/setup.vue +2 -2
  29. package/components/report/main.vue +9 -4
  30. package/components/search/input.vue +9 -9
  31. package/components/section/collections.vue +110 -0
  32. package/components/ui/follow-btn.vue +162 -0
  33. package/components/ui/section-title.vue +2 -0
  34. package/components/ui/snackbar.vue +93 -44
  35. package/composables/__tests__/use-snackbar.test.ts +126 -20
  36. package/composables/use-snackbar.ts +75 -20
  37. package/composables/use-user.ts +4 -4
  38. package/package.json +1 -1
  39. package/pages/contacts.vue +2 -2
  40. package/pages/library/index.vue +1 -1
  41. package/pages/playlists/index.vue +55 -4
  42. package/assets/icons/common/crest-in-circle.svg +0 -1
@@ -1 +1 @@
1
- <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1zm0 7v-7"/></svg>
1
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 22V4a1 1 0 0 1 .4-.8A6 6 0 0 1 8 2c3 0 5 2 7.333 2q2 0 3.067-.8A1 1 0 0 1 20 4v10a1 1 0 0 1-.4.8A6 6 0 0 1 16 16c-3 0-5-2-8-2a6 6 0 0 0-4 1.528"></path></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-heart w-5 h-5" aria-hidden="true"><path d="M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5"></path></svg>
1
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5"></path></svg>
@@ -1 +1 @@
1
- <svg fill="currentColor" viewBox="0 0 24 24"><path d="m12 21.35-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54z"/></svg>
1
+ <svg viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5"></path></svg>
@@ -1 +1 @@
1
- <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="m8.59 13.51 6.83 3.98m-.01-10.98-6.82 3.98"/></svg>
1
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="5" r="3"></circle><circle cx="6" cy="12" r="3"></circle><circle cx="18" cy="19" r="3"></circle><line x1="8.59" x2="15.42" y1="13.51" y2="17.49"></line><line x1="15.41" x2="8.59" y1="6.51" y2="10.49"></line></svg>
@@ -0,0 +1 @@
1
+ <svg viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z"></path><path d="M17 14V2"></path></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" viewBox="0 0 24 24"><path d="M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88M17 14V2"/></svg>
1
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z"></path><path d="M17 14V2"></path></svg>
@@ -0,0 +1 @@
1
+ <svg viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z"></path><path d="M7 10v12"></path></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" viewBox="0 0 24 24"><path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88M7 10v12"/></svg>
1
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z"></path><path d="M7 10v12"></path></svg>
@@ -43,7 +43,7 @@ $nav-border--hover: transparent;
43
43
  $nav-border: $color-zinc-700-50;
44
44
  $nav-icon: $color-zinc-400;
45
45
  $nav-icon-accent: $color-red-400;
46
- $nav-icon--active: $nav-text--active;
46
+ $nav-icon--active: $color-zinc-400;
47
47
  $nav-container-bg: $color-black;
48
48
  $nav-down-icon: $color-zinc-500;
49
49
  $nav-menu-bg: $color-zinc-900;
@@ -105,7 +105,7 @@ $count-bg: $color-zinc-800;
105
105
  $count-text: $color-zinc-400;
106
106
 
107
107
  // ─── Search ───
108
- $search-bg: $color-zinc-800;
108
+ $search-bg: $color-zinc-800-50;
109
109
  $search-text: $color-white;
110
110
  $search-bg--mobile: $color-zinc-800;
111
111
  $search-border--active--mobile: $color-indigo-500;
@@ -119,7 +119,7 @@ $search-button-bg: $color-indigo-600;
119
119
  $search-button-bg--hover: $color-indigo-500;
120
120
  $search-max-width: 500px;
121
121
  $search-max-width-md: 672px;
122
- $search-mobile-bg: $mono-black-95;
122
+ $search-mobile-bg: $color-neutral-940-95;
123
123
  $search-mobile-border: $color-zinc-800;
124
124
  $search-mobile-decorate: $mono-black-50;
125
125
  $search-mobile-button: $color-zinc-200;
@@ -230,6 +230,13 @@ $video-info-description-text: $color-zinc-400;
230
230
  // ─── Video interface ───
231
231
  $video-interface-button-bg: $color-zinc-800;
232
232
  $video-interface-button-text: $color-zinc-400;
233
+ $video-interface-button-bg--hover: $color-zinc-700;
234
+ $video-interface-button-text--hover: $color-white;
235
+ $video-interface-button-bg--active: $color-zinc-700;
236
+ $video-interface-button-text--active: $color-white;
237
+ $video-interface-mobile-icon: $color-white;
238
+ $video-interface-mobile-label: $color-zinc-300;
239
+ $video-interface-mobile-border: $color-zinc-800;
233
240
 
234
241
  // ─── Video channel ───
235
242
  $video-channel-bg: $color-zinc-800-60;
@@ -283,11 +290,12 @@ $video-playlist-header-button-text--active: $color-indigo-400;
283
290
  $video-playlist-header-button-bg--active: $color-indigo-500-10;
284
291
 
285
292
  // ─── Like ───
286
- $like-text: $color-zinc-400;
287
293
  $like-icon: $color-zinc-400;
288
- $like-text--hover: $color-white;
289
- $like-icon--active: $color-green-500;
290
- $like-icon-dislike--active: $color-red-500;
294
+ $like-icon--hover: $color-white;
295
+ $like-icon--active: $color-white;
296
+ $like-count: $color-zinc-500;
297
+ $like-mobile-icon: $color-white;
298
+ $like-mobile-count: $color-zinc-300;
291
299
  $like-bar-bg: $color-zinc-700;
292
300
  $like-bar-likes: $color-zinc-500;
293
301
 
@@ -460,18 +468,29 @@ $dropdown-crest: $color-zinc-500;
460
468
  $dropdown-separator: $color-zinc-800-60;
461
469
 
462
470
  // ─── Snackbar ───
471
+ $snackbar-bg: $color-zinc-800;
472
+ $snackbar-border: $color-zinc-700;
463
473
  $snackbar-text: $color-zinc-200;
464
- $snackbar-close: $color-zinc-500;
465
- $snackbar-close--hover: $color-zinc-300;
466
- $snackbar-close-bg--hover: $color-zinc-700;
467
- $snackbar-success: $color-green-200;
468
- $snackbar-success-bg: $color-green-925;
469
- $snackbar-success-icon: $color-green-300;
470
- $snackbar-success-icon-bg: $color-green-800;
471
- $snackbar-error: $color-red-200;
472
- $snackbar-error-bg: $color-red-925;
473
- $snackbar-error-icon: $color-red-300;
474
- $snackbar-error-icon-bg: $color-red-800;
474
+ $snackbar-highlight: $color-white;
475
+ $snackbar-icon: $color-zinc-300;
476
+ $snackbar-icon-bg: $color-zinc-700-60;
477
+ $snackbar-shadow: 0 10px 15px -3px #{$mono-black-25}, 0 4px 6px -4px #{$mono-black-25};
478
+ $snackbar-action-bg: $color-indigo-600;
479
+ $snackbar-action-bg--hover: $color-indigo-500;
480
+ $snackbar-action-text: $color-white;
481
+
482
+ // ─── Follow button ───
483
+ $follow-btn-bg: $color-indigo-600;
484
+ $follow-btn-bg--hover: $color-indigo-500;
485
+ $follow-btn-border: $color-indigo-500;
486
+ $follow-btn-border--hover: $color-indigo-500;
487
+ $follow-btn-text: $color-white;
488
+ $follow-btn-following-bg: $color-zinc-800;
489
+ $follow-btn-following-bg--hover: $color-red-600;
490
+ $follow-btn-following-border: $color-zinc-800;
491
+ $follow-btn-following-border--hover: $color-red-500;
492
+ $follow-btn-following-text: $color-white;
493
+ $follow-btn-following-text--hover: $color-white;
475
494
 
476
495
  // ─── Button ───
477
496
  $button-primary-bg: $color-indigo-600;
@@ -846,6 +865,18 @@ $playlist-card-placeholder-bg: $color-zinc-700;
846
865
  $playlist-card-dropdown-icon: $color-zinc-500;
847
866
  $playlist-card-dropdown-icon--hover: $color-white;
848
867
 
868
+ // ─── Collections section ───
869
+ $collections-badge-text: $color-indigo-300;
870
+ $collections-badge-bg: $color-indigo-500-20;
871
+ $collections-badge-border: $color-indigo-500-40;
872
+ $collections-more-bg: $color-zinc-800;
873
+ $collections-more-border: $color-zinc-800-50;
874
+ $collections-more-border--hover: $color-zinc-700;
875
+ $collections-more-scrim: $color-black-50;
876
+ $collections-more-scrim--hover: $color-black-42;
877
+ $collections-more-count: $color-white;
878
+ $collections-more-text: $color-zinc-200;
879
+
849
880
  // ─── Channel card ───
850
881
  $channel-card-border: $color-zinc-800-50;
851
882
  $channel-card-bg: $color-zinc-800-50;
@@ -978,7 +1009,6 @@ $library-item-badge-bordered-text: $color-zinc-400;
978
1009
  // ─── Library feed (блок подписки: модель / канал / категория) ───
979
1010
  $library-feed-bg: $color-zinc-900-40;
980
1011
  $library-feed-border: $color-zinc-800;
981
- $library-feed-fade: $color-zinc-950;
982
1012
  $library-feed-avatar-border: $color-zinc-700;
983
1013
  $library-feed-avatar-border--hover: $color-zinc-500;
984
1014
  $library-feed-initials: $color-zinc-400;
@@ -287,6 +287,13 @@ $video-info-description-text: $color-gray-700;
287
287
  // ─── Video interface ───
288
288
  $video-interface-button-bg: $color-slate-750;
289
289
  $video-interface-button-text: $color-gray-400;
290
+ $video-interface-button-bg--hover: $color-slate-700;
291
+ $video-interface-button-text--hover: $color-white;
292
+ $video-interface-button-bg--active: $color-slate-700;
293
+ $video-interface-button-text--active: $color-white;
294
+ $video-interface-mobile-icon: $color-gray-900;
295
+ $video-interface-mobile-label: $color-gray-500;
296
+ $video-interface-mobile-border: $color-gray-200;
290
297
 
291
298
  // ─── Video channel ───
292
299
  $video-channel-bg: $color-gray-200;
@@ -340,11 +347,12 @@ $video-playlist-header-button-text--active: $color-indigo-soft;
340
347
  $video-playlist-header-button-bg--active: $color-indigo-500-10;
341
348
 
342
349
  // ─── Like ───
343
- $like-text: $color-gray-400;
344
350
  $like-icon: $color-gray-500;
345
- $like-text--hover: $color-gray-900;
346
- $like-icon--active: $color-green-500;
347
- $like-icon-dislike--active: $color-red-500;
351
+ $like-icon--hover: $color-gray-900;
352
+ $like-icon--active: $color-gray-900;
353
+ $like-count: $color-gray-400;
354
+ $like-mobile-icon: $color-gray-900;
355
+ $like-mobile-count: $color-gray-500;
348
356
  $like-bar-bg: $color-slate-700;
349
357
  $like-bar-likes: $color-gray-500;
350
358
 
@@ -515,18 +523,29 @@ $dropdown-crest: $color-gray-400;
515
523
  $dropdown-separator: $color-slate-750;
516
524
 
517
525
  // ─── Snackbar ───
526
+ $snackbar-bg: $color-slate-800;
527
+ $snackbar-border: $color-slate-750;
518
528
  $snackbar-text: $color-gray-200;
519
- $snackbar-close: $color-gray-500;
520
- $snackbar-close--hover: $color-gray-300;
521
- $snackbar-close-bg--hover: $color-slate-700;
522
- $snackbar-success: $color-green-200;
523
- $snackbar-success-bg: $color-green-925;
524
- $snackbar-success-icon: $color-green-300;
525
- $snackbar-success-icon-bg: $color-green-800;
526
- $snackbar-error: $color-red-200;
527
- $snackbar-error-bg: $color-red-925;
528
- $snackbar-error-icon: $color-red-300;
529
- $snackbar-error-icon-bg: $color-red-800;
529
+ $snackbar-highlight: $color-white;
530
+ $snackbar-icon: $color-gray-300;
531
+ $snackbar-icon-bg: $color-slate-700;
532
+ $snackbar-shadow: 0 10px 15px -3px #{$mono-black-25}, 0 4px 6px -4px #{$mono-black-25};
533
+ $snackbar-action-bg: $color-indigo-600;
534
+ $snackbar-action-bg--hover: $color-indigo-500;
535
+ $snackbar-action-text: $color-white;
536
+
537
+ // ─── Follow button ───
538
+ $follow-btn-bg: $color-indigo-600;
539
+ $follow-btn-bg--hover: $color-indigo-500;
540
+ $follow-btn-border: $color-indigo-500;
541
+ $follow-btn-border--hover: $color-indigo-500;
542
+ $follow-btn-text: $color-white;
543
+ $follow-btn-following-bg: $color-gray-300;
544
+ $follow-btn-following-bg--hover: $color-red-500;
545
+ $follow-btn-following-border: $color-gray-300;
546
+ $follow-btn-following-border--hover: $color-red-500;
547
+ $follow-btn-following-text: $color-gray-700;
548
+ $follow-btn-following-text--hover: $color-white;
530
549
 
531
550
  // ─── Button ───
532
551
  $button-primary-bg: $color-indigo-600;
@@ -874,6 +893,18 @@ $playlist-card-placeholder-bg: $color-gray-300;
874
893
  $playlist-card-dropdown-icon: $color-gray-600;
875
894
  $playlist-card-dropdown-icon--hover: $color-gray-900;
876
895
 
896
+ // ─── Collections section ───
897
+ $collections-badge-text: $color-indigo-600;
898
+ $collections-badge-bg: $color-indigo-500-10;
899
+ $collections-badge-border: $color-indigo-500-20;
900
+ $collections-more-bg: $color-gray-300;
901
+ $collections-more-border: $color-gray-300;
902
+ $collections-more-border--hover: $color-gray-400;
903
+ $collections-more-scrim: $color-black-45;
904
+ $collections-more-scrim--hover: $color-black-32;
905
+ $collections-more-count: $color-white;
906
+ $collections-more-text: $color-white;
907
+
877
908
  // ─── Channel card ───
878
909
  $channel-card-border: transparent;
879
910
  $channel-card-bg: $color-gray-100;
@@ -1006,7 +1037,6 @@ $library-item-badge-bordered-text: $color-gray-600;
1006
1037
  // ─── Library feed (блок подписки: модель / канал / категория) ───
1007
1038
  $library-feed-bg: $color-gray-100;
1008
1039
  $library-feed-border: transparent;
1009
- $library-feed-fade: $color-gray-100;
1010
1040
  $library-feed-avatar-border: $color-gray-300;
1011
1041
  $library-feed-avatar-border--hover: $color-indigo-500-50;
1012
1042
  $library-feed-initials: $color-gray-600;
@@ -22,6 +22,7 @@ $color-zinc-750: lab(21.3843% .9572 -2.5207); // #333337
22
22
  $color-zinc-700: lab(26.8019% 1.35387 -4.68303); // #3f3f46
23
23
  $color-zinc-700-80: lab(26.8019% 1.35387 -4.68303 / 80%); // zinc-700 / 70%
24
24
  $color-zinc-700-70: lab(26.8019% 1.35387 -4.68303 / 70%); // zinc-700 / 70%
25
+ $color-zinc-700-60: lab(26.8019% 1.35387 -4.68303 / 60%); // zinc-700 / 60%
25
26
  $color-zinc-700-50: lab(26.8019% 1.35387 -4.68303 / 50%); // zinc-700 / 50%
26
27
  $color-zinc-700-30: lab(26.8019% 1.35387 -4.68303 / 30%); // zinc-700 / 50%
27
28
  $color-zinc-650: lab(31.3256% 2.0703 -5.3354); // #494952
@@ -65,6 +66,10 @@ $color-indigo-800: lab(26.6645% 37.9804 -68.6402); // #372aac
65
66
  $color-indigo-900: lab(23.3911% 24.6978 -50.4718); // #312c85
66
67
  $color-indigo-950: lab(12.9255% 18.7583 -31.0075); // #1e1a4d
67
68
 
69
+ // Neutral gray (untinted — no zinc blue tint)
70
+ $color-neutral-940: lab(3.6355% 0 0); // #0d0d0d
71
+ $color-neutral-940-95: lab(3.6355% 0 0 / 95%); // #0d0d0d / 95%
72
+
68
73
  // Monochrome black (opacity variants)
69
74
  $mono-black-100: lab(0% 0 0);
70
75
  $mono-black-95: lab(0% 0 0 / 95%);
@@ -5,6 +5,7 @@ $radius: 10px;
5
5
  $radius-small: 4px;
6
6
  $radius-md: 8px;
7
7
  $radius-lg: 10px;
8
+ $radius-12: 12px;
8
9
  $radius-xl: 14px;
9
10
  $radius-2xl: 16px;
10
11
  $radius-full: 9999px;
@@ -94,7 +94,7 @@ function onCreateClick() {
94
94
 
95
95
  const loading = ref(false);
96
96
 
97
- const { setErrorState, showError, showSuccess, resetSnackbar } = useSnackbar();
97
+ const { setErrorState, showError, show, resetSnackbar } = useSnackbar();
98
98
 
99
99
  async function login() {
100
100
  resetSnackbar();
@@ -115,7 +115,7 @@ async function login() {
115
115
  loading.value = true;
116
116
  await useUser(AuthorizationApiService).login(form.value);
117
117
  useAuthPopup().closeAuthPopup();
118
- showSuccess('Welcome back!');
118
+ show('Welcome back!');
119
119
  } catch (error) {
120
120
  setErrorState(error);
121
121
  } finally {
@@ -70,7 +70,7 @@ function onLoginClick() {
70
70
 
71
71
  const loading = ref(false);
72
72
 
73
- const { setErrorState, showError, showSuccess, resetSnackbar } = useSnackbar();
73
+ const { setErrorState, showError, show, resetSnackbar } = useSnackbar();
74
74
 
75
75
  // Загружаем reCAPTCHA при открытии формы (onMounted) — даёт Google время собрать данные о поведении
76
76
  onMounted(async () => {
@@ -97,7 +97,7 @@ async function submit() {
97
97
  form.value.token = await getRecaptchaToken('password_reset');
98
98
  await useUser(AuthorizationApiService).password(form.value);
99
99
  useAuthPopup().closeAuthPopup();
100
- showSuccess('Check your email');
100
+ show('Check your email');
101
101
  } catch (error) {
102
102
  setErrorState(error);
103
103
  } finally {
@@ -129,7 +129,7 @@ function onLoginClick() {
129
129
 
130
130
  const loading = ref(false);
131
131
 
132
- const { setErrorState, showError, showSuccess, resetSnackbar } = useSnackbar();
132
+ const { setErrorState, showError, show, resetSnackbar } = useSnackbar();
133
133
  // Загружаем reCAPTCHA при открытии формы (onMounted) — даёт Google время собрать данные о поведении
134
134
  onMounted(async () => {
135
135
  try {
@@ -176,7 +176,7 @@ async function submit() {
176
176
  // await PlaylistsApiService.postPlaylist(FAVORITES_KEY, PlaylistType.Private);
177
177
 
178
178
  useAuthPopup().closeAuthPopup();
179
- showSuccess('Registration success');
179
+ show('Registration success');
180
180
  } catch (err) {
181
181
  setErrorState(err);
182
182
  console.error('Ошибка reCAPTCHA или регистрации:', err);
@@ -0,0 +1,133 @@
1
+ <!-- Плитка «показать ещё» в сетке коллекций: 16 размытых обложек сеткой 4×4, поверх счётчик и подпись -->
2
+ <template>
3
+ <NuxtLink
4
+ :to="generateLink(to)"
5
+ class="card-collections-more"
6
+ >
7
+ <span
8
+ v-if="images.length > 0"
9
+ class="card-collections-more__thumbs"
10
+ aria-hidden="true"
11
+ >
12
+ <UiImg
13
+ v-for="(src, index) in images"
14
+ :key="`collections-more-thumb-${index}`"
15
+ :src="src"
16
+ :width="ThumbSize.Small.split('x')[0]"
17
+ :height="ThumbSize.Small.split('x')[1]"
18
+ alt=""
19
+ class="card-collections-more__thumb"
20
+ />
21
+ </span>
22
+
23
+ <span class="card-collections-more__content">
24
+ <span
25
+ v-if="count"
26
+ class="card-collections-more__count"
27
+ >+{{ count }}</span>
28
+ <span class="card-collections-more__text">{{ text }}</span>
29
+ </span>
30
+ </NuxtLink>
31
+ </template>
32
+
33
+ <script setup lang="ts">
34
+ import { ThumbSize } from '../../runtime';
35
+ import type { IThumbUrls } from '../../types';
36
+
37
+ const props = defineProps<{
38
+ to: string
39
+ text: string
40
+ /** Обложки для мозаики: лишние отбрасываем, если меньше 16 — повторяем по кругу */
41
+ thumbs?: IThumbUrls[]
42
+ /** Сколько коллекций осталось за кадром — «+18» */
43
+ count?: number
44
+ }>();
45
+
46
+ const { generateLink } = useGenerateLink();
47
+
48
+ /** Ячеек в мозаике — сетка 4×4 */
49
+ const CELLS = 16;
50
+
51
+ const images = computed(() => {
52
+ const sources = (props.thumbs || [])
53
+ .map(thumb => thumb?.webp?.[ThumbSize.Small])
54
+ .filter((src): src is string => Boolean(src));
55
+
56
+ if (sources.length === 0) return [];
57
+
58
+ /* добиваем по кругу, чтобы мозаика всегда была полной, а не с дырами */
59
+ return Array.from({ length: CELLS }, (_, index) => sources[index % sources.length]);
60
+ });
61
+ </script>
62
+
63
+ <style lang="scss">
64
+ .card-collections-more {
65
+ position: relative;
66
+ display: grid;
67
+ place-content: center;
68
+ min-height: 240px;
69
+ padding: 12px;
70
+ overflow: hidden;
71
+ text-align: center;
72
+ border-radius: $radius-xl;
73
+ border: 1px solid $collections-more-border;
74
+ background-color: $collections-more-bg;
75
+
76
+ @include hover(border-color) {
77
+ border-color: $collections-more-border--hover;
78
+
79
+ &::after {
80
+ background-color: $collections-more-scrim--hover;
81
+ }
82
+ }
83
+
84
+ /* затемнение поверх обложек — псевдоэлементом, без отдельной ноды-оверлея */
85
+ &::after {
86
+ content: '';
87
+ position: absolute;
88
+ inset: 0;
89
+ background-color: $collections-more-scrim;
90
+ transition: var(--transition) background-color;
91
+ }
92
+ }
93
+
94
+ .card-collections-more__thumbs {
95
+ position: absolute;
96
+ inset: 0;
97
+ display: grid;
98
+
99
+ /* minmax(0, 1fr), иначе auto-минимум трека = min-content картинки и сетка распирает блок */
100
+ grid-template-columns: repeat(4, minmax(0, 1fr));
101
+ grid-template-rows: repeat(4, minmax(0, 1fr));
102
+ gap: 2px;
103
+ filter: blur(12px);
104
+ transform: scale(1.1);
105
+ }
106
+
107
+ .card-collections-more__thumb {
108
+ width: 100%;
109
+ height: 100%;
110
+ object-fit: cover;
111
+ }
112
+
113
+ .card-collections-more__content {
114
+ position: relative;
115
+ z-index: $z-index-plus;
116
+ display: grid;
117
+ row-gap: 2px;
118
+ }
119
+
120
+ .card-collections-more__count {
121
+ @include font-2xl;
122
+
123
+ font-weight: 700;
124
+ color: $collections-more-count;
125
+ }
126
+
127
+ .card-collections-more__text {
128
+ @include font-sm;
129
+
130
+ font-weight: 500;
131
+ color: $collections-more-text;
132
+ }
133
+ </style>
@@ -107,7 +107,10 @@
107
107
  <p class="card-playlist__user">
108
108
  {{ card.username }}
109
109
  </p>
110
- <div class="card-playlist__content-wrapper">
110
+ <div
111
+ v-if="!noActions"
112
+ class="card-playlist__content-wrapper"
113
+ >
111
114
  <UiDropdown
112
115
  ref="dropdownRef"
113
116
  right
@@ -177,6 +180,8 @@ import { CSS_BREAKPOINTS } from '../../config/css-breakpoints';
177
180
  const props = defineProps<{
178
181
  card: IPlaylistCard
179
182
  topPlaylists?: boolean
183
+ /** Без меню «три точки» — вместе с ним уходят share и report */
184
+ noActions?: boolean
180
185
  priority?: boolean
181
186
  }>();
182
187
 
@@ -6,6 +6,7 @@
6
6
  :key="`user-playlist-${index}`"
7
7
  :card="item"
8
8
  :top-playlists="topPlaylists"
9
+ :no-actions="noActions"
9
10
  :priority="priority && index === 0"
10
11
  @share="onShare"
11
12
  />
@@ -32,6 +33,8 @@ import type { IPlaylistCard } from '../../types';
32
33
  defineProps<{
33
34
  items: IPlaylistCard[]
34
35
  topPlaylists?: boolean
36
+ /** Скрыть меню карточки (три точки: share/report) — например у редакционных подборок */
37
+ noActions?: boolean
35
38
  priority?: boolean
36
39
  }>();
37
40
 
@@ -30,19 +30,6 @@
30
30
  class="info-main__count"
31
31
  icon="video-camera"
32
32
  >{{ videosCount || card.videosCount }}</UiCount>
33
- <UiBtn
34
- v-if="featureFlags.FeatureFollowEnabled"
35
- theme="muted"
36
- class="info-main__header-button"
37
- size="s"
38
- @click="onFollowClick"
39
- >
40
- <UiIcon
41
- name="plus"
42
- size="16"
43
- />
44
- {{ t('follow') }}
45
- </UiBtn>
46
33
  <UiBtn
47
34
  theme="muted"
48
35
  size="s"
@@ -55,6 +42,14 @@
55
42
  />
56
43
  {{ t('share') }}
57
44
  </UiBtn>
45
+ <UiFollowBtn
46
+ v-if="featureFlags.FeatureFollowEnabled"
47
+ :following="isFollowing"
48
+ :name="title"
49
+ class="info-main__header-follow"
50
+ size="s"
51
+ @toggle="onFollowClick"
52
+ />
58
53
  </div>
59
54
  </div>
60
55
 
@@ -190,9 +185,12 @@ function showParameters() {
190
185
 
191
186
  const authPopupText = 'register_first';
192
187
 
188
+ /** Заглушка вместо ручки подписки: состояние живёт только в компоненте, на бэк ничего не уходит */
189
+ const isFollowing = ref(false);
190
+
193
191
  function onFollowClick() {
194
192
  if (isAuthorized.value) {
195
- console.log('чото делать');
193
+ isFollowing.value = !isFollowing.value;
196
194
  } else {
197
195
  openAuthPopup(AuthSteps.Login, authPopupText);
198
196
  }
@@ -464,4 +462,10 @@ const socialItems = computed<ILinkItem[]>(() => {
464
462
  .info-main__header-button {
465
463
  @include button-variant(info-button);
466
464
  }
465
+
466
+ .info-main__header-follow {
467
+ @include to-br(sm) {
468
+ margin-inline-start: auto;
469
+ }
470
+ }
467
471
  </style>