itube-specs 0.0.923 → 0.0.928
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/DOCS/STYLES.md +10 -1
- package/assets/scss/base/_utils.scss +6 -0
- package/assets/scss/layout/_layout.scss +1 -1
- package/assets/scss/mixins/_badge.scss +18 -0
- package/assets/scss/mixins/_breakpoints.scss +24 -3
- package/assets/scss/mixins/_cards-grid.scss +32 -0
- package/assets/scss/mixins/_index.scss +2 -0
- package/assets/scss/mixins/_page.scss +5 -1
- package/assets/scss/mixins/_video-card.scss +3 -13
- package/assets/scss/themes/dark/_theme.scss +25 -6
- package/assets/scss/themes/light/_theme.scss +25 -6
- package/assets/scss/vars/_tokens.scss +5 -1
- package/components/card/video/index.vue +137 -8
- package/components/grid/categories.vue +3 -6
- package/components/grid/channels.vue +2 -12
- package/components/grid/playlists.vue +2 -8
- package/components/layout/burger.vue +4 -3
- package/components/layout/footer-language.vue +37 -61
- package/components/layout/header-user.vue +1 -1
- package/components/layout/header.vue +42 -41
- package/components/layout/language.vue +89 -58
- package/components/layout/nav.vue +1 -1
- package/components/layout/niche.vue +5 -5
- package/components/layout/notifications.vue +1 -1
- package/components/search/main.vue +18 -10
- package/components/section/swiper-cards.vue +17 -4
- package/components/view/model-videos.vue +2 -1
- package/components/view/video.vue +2 -3
- package/components/view/videos.vue +1 -0
- package/config/css-breakpoints.ts +2 -1
- package/layouts/default.vue +1 -1
- package/lib/scheme/sort-items-default.ts +2 -0
- package/lib/scheme/sort-items-search.ts +2 -0
- package/package.json +1 -1
- package/runtime/utils/check-device-width.ts +7 -3
- package/runtime/utils/converters/__tests__/group-categories-by-first-letter.test.ts +2 -3
- package/runtime/utils/converters/group-categories-by-first-letter.ts +3 -3
- package/utils/category-letter-groups/__tests__/group-by-first-letter.test.ts +2 -2
- package/utils/category-letter-groups/group-by-first-letter.ts +3 -3
package/DOCS/STYLES.md
CHANGED
|
@@ -120,8 +120,17 @@ Text-only elements (`title`, `name`, `subtext`, `description`, `label`, `count`)
|
|
|
120
120
|
`font-size`/`line-height`.
|
|
121
121
|
- Breakpoints: `@include from-br(sm)`, `to-br(xs)`. Container: `from-cq($bp)`. JS mirror of `$brkpnts` in
|
|
122
122
|
`config/`, guarded by `check:breakpoints`.
|
|
123
|
+
- `$brkpnts` holds layout tiers only — points the whole page frame turns on, needed by many components. A
|
|
124
|
+
one-off threshold of a single block (how many columns fit, where a word wraps) stays a px literal next to
|
|
125
|
+
that block: `from-br`/`to-br` take a number too.
|
|
126
|
+
- Card grids (videos, channels, playlists, categories) all key off `mixins/_cards-grid.scss` — one ladder
|
|
127
|
+
1 → 2 (370px) → 3 (900px) → 4 (1440px). Take columns from `@include cards-grid-columns`, set `display` and
|
|
128
|
+
`gap` yourself; don't hand-roll a per-grid column ladder or an `auto-fill` variant.
|
|
129
|
+
- `$brkpnt-burger` (= `sd`, 1024px) is the burger ↔ desktop-menu line: below it the nav and the right half of
|
|
130
|
+
the header collapse into the burger. Header, nav, search, niche, language and `--header-height` key off this
|
|
131
|
+
variable, not off `sm` — move the line here, not per file. Utility classes: `._to-sd` / `._from-sd`.
|
|
123
132
|
|
|
124
133
|
**All mixins** (auto-injected, never `@use`): `font-4xs|3xs|xs|2xs|sm|md|base|lg|xl|2xl|3xl|4xl`,
|
|
125
134
|
`from-br|to-br`, `from-cq|to-cq`, `hover`, `surface`, `button-variant`, `page|page-title|page-footer-links`,
|
|
126
|
-
`video-card|video-card-grid|video-card-poster`, `area-point`. Signatures — SCSS-mixins table in the app's
|
|
135
|
+
`cards-grid-columns`, `video-card|video-card-grid|video-card-poster`, `area-point`. Signatures — SCSS-mixins table in the app's
|
|
127
136
|
`DOCS/CATALOG.md`.
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
// Виден только ниже sm (960px), на sm и шире скрыт.
|
|
7
7
|
@include from-br(sm) { ._to-sm { display: none !important; } }
|
|
8
8
|
|
|
9
|
+
// Виден только ниже sd (1024px, граница бургера), на sd и шире скрыт.
|
|
10
|
+
@include from-br(sd) { ._to-sd { display: none !important; } }
|
|
11
|
+
|
|
9
12
|
// Виден только ниже md (1350px), на md и шире скрыт.
|
|
10
13
|
@include from-br(md) { ._to-md { display: none !important; } }
|
|
11
14
|
|
|
@@ -18,6 +21,9 @@
|
|
|
18
21
|
// Виден с sm (960px) и шире, ниже скрыт.
|
|
19
22
|
@include to-br(sm) { ._from-sm { display: none !important; } }
|
|
20
23
|
|
|
24
|
+
// Виден с sd (1024px, граница бургера) и шире, ниже скрыт.
|
|
25
|
+
@include to-br(sd) { ._from-sd { display: none !important; } }
|
|
26
|
+
|
|
21
27
|
// Виден с md (1350px) и шире, ниже скрыт.
|
|
22
28
|
@include to-br(md) { ._from-md { display: none !important; } }
|
|
23
29
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
@use 'font-sizes' as *;
|
|
2
|
+
@use 'vars' as *;
|
|
3
|
+
|
|
4
|
+
// Плашка с кодом локали в переключателях языка (шапка, футер, список языков).
|
|
5
|
+
// Цвета не задаёт — фон и текст ставит вызывающий компонент своими токенами.
|
|
6
|
+
@mixin locale-badge {
|
|
7
|
+
@include font-xs;
|
|
8
|
+
|
|
9
|
+
display: inline-flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
padding: 2px 6px;
|
|
13
|
+
border-radius: $radius-small;
|
|
14
|
+
font-weight: 600;
|
|
15
|
+
line-height: 1;
|
|
16
|
+
letter-spacing: var(--tracking-wide);
|
|
17
|
+
text-transform: uppercase;
|
|
18
|
+
}
|
|
@@ -1,19 +1,40 @@
|
|
|
1
1
|
@use 'sass:map';
|
|
2
2
|
@use 'sass:list';
|
|
3
|
+
@use 'sass:math';
|
|
3
4
|
@use 'sass:meta';
|
|
4
5
|
|
|
5
|
-
//
|
|
6
|
+
// Тиры раскладки. Сюда попадают только точки, вокруг которых перестраивается общий каркас
|
|
7
|
+
// страницы, и потому нужные многим компонентам. Разовый порог одного блока (сколько колонок
|
|
8
|
+
// влезло, где переносится слово) держим литералом рядом с этим блоком — from-br/to-br
|
|
9
|
+
// принимают и число в px.
|
|
6
10
|
|
|
7
11
|
$brkpnts: (
|
|
8
12
|
xs: 475px,
|
|
9
13
|
xm: 650px,
|
|
10
14
|
sm: 960px,
|
|
15
|
+
sd: 1024px,
|
|
11
16
|
md: 1350px,
|
|
12
17
|
ml: 1500px,
|
|
13
18
|
lg: 1792px,
|
|
14
19
|
xl: 2560px,
|
|
15
20
|
);
|
|
16
21
|
|
|
22
|
+
/**
|
|
23
|
+
Граница «бургер ↔ десктопное меню»: ниже неё навигация и правая часть шапки свёрнуты
|
|
24
|
+
в бургер, выше — разложены в шапку и в строку навигации под ней. Отдельная переменная,
|
|
25
|
+
а не литерал `sd`, чтобы двигать эту границу, не перебирая шапку по файлам.
|
|
26
|
+
*/
|
|
27
|
+
$brkpnt-burger: sd;
|
|
28
|
+
|
|
29
|
+
// Литерал-порог можно писать и как 370, и как 370px — приводим к px.
|
|
30
|
+
@function _to-px($bp) {
|
|
31
|
+
@if math.is-unitless($bp) {
|
|
32
|
+
@return $bp * 1px;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@return $bp;
|
|
36
|
+
}
|
|
37
|
+
|
|
17
38
|
/**
|
|
18
39
|
Mobile first брейкпоинты
|
|
19
40
|
@include from-br(sm) { ... }
|
|
@@ -27,7 +48,7 @@ $brkpnts: (
|
|
|
27
48
|
@content;
|
|
28
49
|
}
|
|
29
50
|
} @else if meta.type-of($bp) == 'number' {
|
|
30
|
-
$pixelyzed: $bp
|
|
51
|
+
$pixelyzed: _to-px($bp);
|
|
31
52
|
|
|
32
53
|
@media (min-width: $pixelyzed) {
|
|
33
54
|
@content;
|
|
@@ -49,7 +70,7 @@ $brkpnts: (
|
|
|
49
70
|
@content;
|
|
50
71
|
}
|
|
51
72
|
} @else if meta.type-of($bp) == 'number' {
|
|
52
|
-
$pixelyzed: $bp
|
|
73
|
+
$pixelyzed: _to-px($bp) - 1px;
|
|
53
74
|
|
|
54
75
|
@media (max-width: $pixelyzed) {
|
|
55
76
|
@content;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
@use 'breakpoints' as *;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Пороги плотности сеток карточек — тумб, каналов, плейлистов, категорий. Это не тиры
|
|
5
|
+
раскладки, а ответ на вопрос «сколько карточек влезает по ширине», поэтому литералы,
|
|
6
|
+
а не ключи $brkpnts: 900px и 1440px намеренно не совпадают с sm/md и в общую карту не идут.
|
|
7
|
+
*/
|
|
8
|
+
$cards-grid-2-cols: 370px;
|
|
9
|
+
$cards-grid-3-cols: 900px;
|
|
10
|
+
$cards-grid-4-cols: 1440px;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
Колонки сетки карточек: 1, 2 с 370px, 3 с 900px, 4 с 1440px. Только grid-template-columns —
|
|
14
|
+
`display` и `gap` остаются на вызывающей стороне, они у сеток разные.
|
|
15
|
+
minmax(0, 1fr) обязателен, не `1fr`: нешринкуемая мета-строка (карточка истории) задаёт
|
|
16
|
+
колонке min-content, из-за которого грид вылезает за контейнер на телефоне.
|
|
17
|
+
*/
|
|
18
|
+
@mixin cards-grid-columns {
|
|
19
|
+
grid-template-columns: minmax(0, 1fr);
|
|
20
|
+
|
|
21
|
+
@include from-br($cards-grid-2-cols) {
|
|
22
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@include from-br($cards-grid-3-cols) {
|
|
26
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@include from-br($cards-grid-4-cols) {
|
|
30
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -13,11 +13,15 @@
|
|
|
13
13
|
|
|
14
14
|
// Заголовок страницы: font-lg, uppercase, 700. В разметке — глобальный класс `._title`.
|
|
15
15
|
@mixin page-title {
|
|
16
|
-
@include font-
|
|
16
|
+
@include font-base;
|
|
17
17
|
|
|
18
18
|
text-transform: uppercase;
|
|
19
19
|
letter-spacing: var(--tracking-wide);
|
|
20
20
|
font-weight: 700;
|
|
21
|
+
|
|
22
|
+
@include from-br(xm) {
|
|
23
|
+
@include font-lg;
|
|
24
|
+
}
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
// Блок SEO-ссылок внизу страницы: прижат к низу (margin-top: auto) и отбит линией.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@use 'breakpoints' as *;
|
|
2
|
+
@use 'cards-grid' as *;
|
|
2
3
|
@use 'font-sizes' as *;
|
|
3
4
|
@use 'vars' as *;
|
|
4
5
|
|
|
@@ -10,27 +11,16 @@
|
|
|
10
11
|
align-content: start;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
Сетка карточек видео: 2 колонки, 3 с xs, 4 с md.
|
|
15
|
-
minmax(0, 1fr) обязателен, не `1fr`: мета-строка карточки истории нешринкуема и задаёт
|
|
16
|
-
колонке min-content, из-за которого грид вылезает за контейнер на телефоне.
|
|
17
|
-
*/
|
|
14
|
+
// Сетка карточек видео: колонки общие для всех сеток карточек, свой только зазор.
|
|
18
15
|
@mixin video-card-grid {
|
|
19
16
|
display: grid;
|
|
20
17
|
gap: 12px;
|
|
21
|
-
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
22
18
|
|
|
23
|
-
@include
|
|
24
|
-
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
25
|
-
}
|
|
19
|
+
@include cards-grid-columns;
|
|
26
20
|
|
|
27
21
|
@include from-br(sm) {
|
|
28
22
|
gap: 24px;
|
|
29
23
|
}
|
|
30
|
-
|
|
31
|
-
@include from-br(md) {
|
|
32
|
-
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
33
|
-
}
|
|
34
24
|
}
|
|
35
25
|
|
|
36
26
|
// Постер карточки: 16/9, скруглённый, с обрезкой — база для абсолютных бейджей поверх.
|
|
@@ -224,6 +224,15 @@ $video-card-action-active-icon--hover: $color-white;
|
|
|
224
224
|
$video-card-dropdown-border: $color-zinc-800;
|
|
225
225
|
$video-card-dropdown-size--hover: 1;
|
|
226
226
|
|
|
227
|
+
// ─── Video card tags (ряд плашек моделей и поповер «ещё») ───
|
|
228
|
+
$video-card-tags-more-bg: $color-zinc-800-80;
|
|
229
|
+
$video-card-tags-more-bg--hover: $color-zinc-700;
|
|
230
|
+
$video-card-tags-more-text: $color-zinc-300;
|
|
231
|
+
$video-card-tags-more-text--hover: $color-white;
|
|
232
|
+
$video-card-tags-popover-bg: $color-zinc-900;
|
|
233
|
+
$video-card-tags-popover-border: $color-zinc-800;
|
|
234
|
+
$video-card-tags-popover-shadow: 0 10px 15px -3px #{$mono-black-25}, 0 4px 6px -4px #{$mono-black-25};
|
|
235
|
+
|
|
227
236
|
// ─── Video info ───
|
|
228
237
|
$video-info-item-text: $color-zinc-500-70;
|
|
229
238
|
$video-info-handler-text: $color-zinc-400;
|
|
@@ -367,6 +376,8 @@ $language-icon: $color-zinc-400;
|
|
|
367
376
|
$language--current: $color-zinc-500;
|
|
368
377
|
$language-title: $color-zinc-500;
|
|
369
378
|
$language-item-text: $color-zinc-300;
|
|
379
|
+
$language-code-bg: $color-zinc-700;
|
|
380
|
+
$language-code-text: $color-zinc-200;
|
|
370
381
|
$language-item-bg--hover: $color-zinc-800;
|
|
371
382
|
$language-item-text--current: $color-white;
|
|
372
383
|
$language-item-bg--current: $color-zinc-700;
|
|
@@ -390,11 +401,12 @@ $niche-item-bg--current: $color-zinc-700;
|
|
|
390
401
|
$footer-language-bg: $color-zinc-800-50;
|
|
391
402
|
$footer-language-bg--hover: $color-zinc-700;
|
|
392
403
|
$footer-language-text: $color-zinc-400;
|
|
393
|
-
$footer-language-
|
|
394
|
-
$footer-language-
|
|
395
|
-
$footer-language-
|
|
396
|
-
$footer-language-
|
|
397
|
-
$footer-language-
|
|
404
|
+
$footer-language-badge-bg: $color-zinc-800;
|
|
405
|
+
$footer-language-badge-text: $color-zinc-200;
|
|
406
|
+
$footer-language-menu-bg: $color-night;
|
|
407
|
+
$footer-language-menu-border: $color-zinc-800;
|
|
408
|
+
$footer-language-menu-shadow: 0 20px 25px -5px #{$mono-black-25}, 0 8px 10px -6px #{$mono-black-25};
|
|
409
|
+
$footer-language-menu-item--hover: $color-zinc-800-50;
|
|
398
410
|
|
|
399
411
|
// ─── Burger ───
|
|
400
412
|
$burger-backdrop: $mono-black-50;
|
|
@@ -422,9 +434,12 @@ $header-bg: $color-black;
|
|
|
422
434
|
$header-burger-icon: $color-zinc-200;
|
|
423
435
|
$header-user-icon: $color-zinc-500;
|
|
424
436
|
$header-language-trigger: $color-zinc-400;
|
|
425
|
-
$header-language-
|
|
437
|
+
$header-language-trigger--hover: $color-white;
|
|
438
|
+
$header-language-badge-bg: $color-zinc-800;
|
|
439
|
+
$header-language-badge-text: $color-zinc-200;
|
|
426
440
|
$header-language-menu-bg: $color-night;
|
|
427
441
|
$header-language-menu-border: $color-zinc-800;
|
|
442
|
+
$header-language-menu-shadow: 0 20px 25px -5px #{$mono-black-25}, 0 8px 10px -6px #{$mono-black-25};
|
|
428
443
|
$header-language-menu-item--hover: $color-zinc-800-50;
|
|
429
444
|
|
|
430
445
|
// ─── notifications ───
|
|
@@ -540,6 +555,10 @@ $swiper-nav-bg--hover: transparent;
|
|
|
540
555
|
$swiper-nav-text: $color-white;
|
|
541
556
|
$swiper-nav-shadow: transparent;
|
|
542
557
|
|
|
558
|
+
// ─── Section swiper cards ───
|
|
559
|
+
$section-swiper-cards-link: $color-zinc-400;
|
|
560
|
+
$section-swiper-cards-link--hover: $color-white;
|
|
561
|
+
|
|
543
562
|
// ─── Select ───
|
|
544
563
|
$select-icon: $color-zinc-400;
|
|
545
564
|
$select-bg: $color-zinc-800-60;
|
|
@@ -281,6 +281,15 @@ $video-card-action-active-icon--hover: $color-white;
|
|
|
281
281
|
// ─── Video card dropdown ───
|
|
282
282
|
$video-card-dropdown-border: transparent;
|
|
283
283
|
|
|
284
|
+
// ─── Video card tags (ряд плашек моделей и поповер «ещё») ───
|
|
285
|
+
$video-card-tags-more-bg: $color-gray-300;
|
|
286
|
+
$video-card-tags-more-bg--hover: $color-gray-400;
|
|
287
|
+
$video-card-tags-more-text: $color-gray-700;
|
|
288
|
+
$video-card-tags-more-text--hover: $color-gray-900;
|
|
289
|
+
$video-card-tags-popover-bg: $color-white;
|
|
290
|
+
$video-card-tags-popover-border: $color-gray-300;
|
|
291
|
+
$video-card-tags-popover-shadow: 0 10px 15px -3px #{$mono-black-25}, 0 4px 6px -4px #{$mono-black-25};
|
|
292
|
+
|
|
284
293
|
// ─── Video info ───
|
|
285
294
|
$video-info-item-text: $color-gray-400;
|
|
286
295
|
$video-info-handler-text: $color-gray-400;
|
|
@@ -424,6 +433,8 @@ $language-icon: $color-gray-400;
|
|
|
424
433
|
$language--current: $color-gray-400;
|
|
425
434
|
$language-title: $color-gray-400;
|
|
426
435
|
$language-item-text: $color-gray-300;
|
|
436
|
+
$language-code-bg: $color-slate-700;
|
|
437
|
+
$language-code-text: $color-white;
|
|
427
438
|
$language-item-bg--hover: $color-white-5;
|
|
428
439
|
$language-item-text--current: $color-white;
|
|
429
440
|
$language-item-bg--current: $color-slate-750;
|
|
@@ -447,11 +458,12 @@ $niche-item-bg--current: $color-indigo-soft;
|
|
|
447
458
|
$footer-language-bg: $color-slate-750;
|
|
448
459
|
$footer-language-bg--hover: $color-slate-700;
|
|
449
460
|
$footer-language-text: $color-white;
|
|
450
|
-
$footer-language-
|
|
451
|
-
$footer-language-
|
|
452
|
-
$footer-language-
|
|
453
|
-
$footer-language-
|
|
454
|
-
$footer-language-
|
|
461
|
+
$footer-language-badge-bg: $color-slate-850;
|
|
462
|
+
$footer-language-badge-text: $color-white;
|
|
463
|
+
$footer-language-menu-bg: $color-slate-850;
|
|
464
|
+
$footer-language-menu-border: $color-white-10;
|
|
465
|
+
$footer-language-menu-shadow: 0 20px 25px -5px #{$mono-black-25}, 0 8px 10px -6px #{$mono-black-25};
|
|
466
|
+
$footer-language-menu-item--hover: $color-white-5;
|
|
455
467
|
|
|
456
468
|
// ─── Burger ───
|
|
457
469
|
$burger-backdrop: $mono-black-50;
|
|
@@ -479,9 +491,12 @@ $header-bg: $color-slate-800;
|
|
|
479
491
|
$header-burger-icon: $color-gray-200;
|
|
480
492
|
$header-user-icon: $color-gray-500;
|
|
481
493
|
$header-language-trigger: $color-gray-500;
|
|
482
|
-
$header-language-
|
|
494
|
+
$header-language-trigger--hover: $color-gray-300;
|
|
495
|
+
$header-language-badge-bg: $color-slate-750;
|
|
496
|
+
$header-language-badge-text: $color-white;
|
|
483
497
|
$header-language-menu-bg: $color-slate-850;
|
|
484
498
|
$header-language-menu-border: $color-white-10;
|
|
499
|
+
$header-language-menu-shadow: 0 20px 25px -5px #{$mono-black-25}, 0 8px 10px -6px #{$mono-black-25};
|
|
485
500
|
$header-language-menu-item--hover: $color-white-5;
|
|
486
501
|
$notifications-icon: $color-gray-300;
|
|
487
502
|
$notifications-icon--mobile: $color-gray-200;
|
|
@@ -591,6 +606,10 @@ $swiper-nav-bg: $color-white;
|
|
|
591
606
|
$swiper-nav-bg--hover: $color-gray-300;
|
|
592
607
|
$swiper-nav-shadow: $mono-black-10;
|
|
593
608
|
|
|
609
|
+
// ─── Section swiper cards ───
|
|
610
|
+
$section-swiper-cards-link: $color-gray-600;
|
|
611
|
+
$section-swiper-cards-link--hover: $color-gray-900;
|
|
612
|
+
|
|
594
613
|
// ─── Select ───
|
|
595
614
|
$select-bg: $color-white;
|
|
596
615
|
$select-icon: $color-gray-500;
|
|
@@ -38,9 +38,13 @@
|
|
|
38
38
|
--container-padding-inline: 24px;
|
|
39
39
|
--chips-height: 32px;
|
|
40
40
|
--chips-height-small: 28px;
|
|
41
|
-
--header-height: 71px;
|
|
42
41
|
--control-min-width: 296px;
|
|
43
42
|
--max-width-container: 1600px;
|
|
44
43
|
--card-round-size: 96px;
|
|
45
44
|
}
|
|
45
|
+
|
|
46
|
+
// Высота шапки меняется вместе с её раскладкой, а не на общем тире sm.
|
|
47
|
+
@include from-br($brkpnt-burger) {
|
|
48
|
+
--header-height: 71px;
|
|
49
|
+
}
|
|
46
50
|
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
{'--no-channel': isChannelPage},
|
|
9
9
|
{'--progress': hasProgress},
|
|
10
10
|
{'--favorite': isFavoriteCard},
|
|
11
|
+
{'--tags-open': isTagsOpen},
|
|
11
12
|
]"
|
|
12
13
|
class="card-video"
|
|
13
14
|
>
|
|
@@ -131,11 +132,15 @@
|
|
|
131
132
|
</p>
|
|
132
133
|
<div
|
|
133
134
|
v-if="!mini && !compact && !history && cardTags && cardTags.length > 0"
|
|
135
|
+
ref="tagsRef"
|
|
134
136
|
class="card-video__tags"
|
|
135
137
|
>
|
|
136
|
-
<div
|
|
138
|
+
<div
|
|
139
|
+
class="card-video__tags-wrapper"
|
|
140
|
+
@click="isTagsOpen = false"
|
|
141
|
+
>
|
|
137
142
|
<UiChips
|
|
138
|
-
v-for="(item, index) in cardTags
|
|
143
|
+
v-for="(item, index) in cardTags"
|
|
139
144
|
micro
|
|
140
145
|
:key="`${card.guid}-tag-${index}`"
|
|
141
146
|
:item="item"
|
|
@@ -143,6 +148,14 @@
|
|
|
143
148
|
is-link
|
|
144
149
|
/>
|
|
145
150
|
</div>
|
|
151
|
+
<button
|
|
152
|
+
v-if="hasMoreTags"
|
|
153
|
+
:aria-label="t('show_all_models')"
|
|
154
|
+
:aria-expanded="isTagsOpen"
|
|
155
|
+
class="card-video__tags-more"
|
|
156
|
+
type="button"
|
|
157
|
+
@click="isTagsOpen = !isTagsOpen"
|
|
158
|
+
>+</button>
|
|
146
159
|
</div>
|
|
147
160
|
<CardDropdownTrigger
|
|
148
161
|
:card="card"
|
|
@@ -161,9 +174,13 @@
|
|
|
161
174
|
|
|
162
175
|
<script setup lang="ts">
|
|
163
176
|
import type { IVideoCard } from '../../../types';
|
|
177
|
+
import { onClickOutside } from '@vueuse/core';
|
|
164
178
|
import { convertString, getDuration } from '../../../runtime';
|
|
165
179
|
import { CSS_BREAKPOINTS } from '../../../config/css-breakpoints';
|
|
166
180
|
|
|
181
|
+
/** Потолок плашек в разметке: ряд скроллится, но неограниченный список раздувает DOM всей сетки */
|
|
182
|
+
const TAGS_LIMIT = 8;
|
|
183
|
+
|
|
167
184
|
const featureFlags = useRuntimeConfig().public.featureFlags;
|
|
168
185
|
|
|
169
186
|
const props = defineProps<{
|
|
@@ -280,7 +297,16 @@ const cardTags = computed(() => {
|
|
|
280
297
|
searchRank(a) - searchRank(b) || a.localeCompare(b)
|
|
281
298
|
);
|
|
282
299
|
|
|
283
|
-
return sortModels
|
|
300
|
+
return sortModels.slice(0, TAGS_LIMIT).map(item => convertString().toChips(item, 'models'));
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
const tagsRef = ref();
|
|
304
|
+
const isTagsOpen = ref(false);
|
|
305
|
+
|
|
306
|
+
const hasMoreTags = computed(() => cardTags.value.length > 1);
|
|
307
|
+
|
|
308
|
+
onClickOutside(tagsRef, () => {
|
|
309
|
+
isTagsOpen.value = false;
|
|
284
310
|
});
|
|
285
311
|
</script>
|
|
286
312
|
|
|
@@ -288,6 +314,7 @@ const cardTags = computed(() => {
|
|
|
288
314
|
$inset-label: 8px;
|
|
289
315
|
$layout-breakpoint: 250px;
|
|
290
316
|
$progress-height: 4px;
|
|
317
|
+
$tags-fade: 40px;
|
|
291
318
|
|
|
292
319
|
// Колонка под меню карточки фиксирована, а не auto: иначе ширина зависит от того, отрисовано меню
|
|
293
320
|
// или нет, и в момент подмены кнопки заголовок дёргается
|
|
@@ -590,10 +617,36 @@ $dropdown-column: 18px;
|
|
|
590
617
|
aspect-ratio: 16/9;
|
|
591
618
|
}
|
|
592
619
|
|
|
620
|
+
@property --card-video-tags-fade {
|
|
621
|
+
syntax: '<length>';
|
|
622
|
+
inherits: false;
|
|
623
|
+
initial-value: 0;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/* Затемнение гаснет на последних 15% прокрутки — доехал до конца, подсказывать больше нечего */
|
|
627
|
+
@keyframes card-video-tags-fade {
|
|
628
|
+
0%,
|
|
629
|
+
85% {
|
|
630
|
+
--card-video-tags-fade: #{$tags-fade};
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
100% {
|
|
634
|
+
--card-video-tags-fade: 0px;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
@keyframes card-video-tags-more {
|
|
639
|
+
0%,
|
|
640
|
+
100% {
|
|
641
|
+
visibility: visible;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
593
645
|
.card-video__tags {
|
|
594
|
-
|
|
595
|
-
gap: 8px;
|
|
646
|
+
position: relative;
|
|
596
647
|
grid-column: 1;
|
|
648
|
+
min-height: var(--chips-height-micro);
|
|
649
|
+
timeline-scope: --card-video-tags;
|
|
597
650
|
|
|
598
651
|
@include from-cq($layout-breakpoint) {
|
|
599
652
|
grid-column: 2;
|
|
@@ -602,11 +655,87 @@ $dropdown-column: 18px;
|
|
|
602
655
|
}
|
|
603
656
|
|
|
604
657
|
.card-video__tags-wrapper {
|
|
605
|
-
max-height: calc( var(--chips-height-micro) * 2 + 8px);
|
|
606
|
-
overflow: hidden;
|
|
607
658
|
display: flex;
|
|
608
|
-
flex-wrap:
|
|
659
|
+
flex-wrap: nowrap;
|
|
660
|
+
align-items: center;
|
|
609
661
|
gap: 8px;
|
|
662
|
+
min-width: 0;
|
|
663
|
+
overflow-x: auto;
|
|
664
|
+
overscroll-behavior-inline: contain;
|
|
665
|
+
scrollbar-width: none;
|
|
666
|
+
|
|
667
|
+
&::-webkit-scrollbar {
|
|
668
|
+
display: none;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
.card-video__tags-more {
|
|
673
|
+
@include font-xs;
|
|
674
|
+
|
|
675
|
+
position: absolute;
|
|
676
|
+
inset-block: 0;
|
|
677
|
+
right: 0;
|
|
678
|
+
z-index: $z-index-dropdown;
|
|
679
|
+
display: grid;
|
|
680
|
+
place-content: center;
|
|
681
|
+
padding-inline: 8px;
|
|
682
|
+
visibility: hidden;
|
|
683
|
+
color: $video-card-tags-more-text;
|
|
684
|
+
background-color: $video-card-tags-more-bg;
|
|
685
|
+
border-radius: $radius-6;
|
|
686
|
+
|
|
687
|
+
@include hover(background-color, color) {
|
|
688
|
+
background-color: $video-card-tags-more-bg--hover;
|
|
689
|
+
color: $video-card-tags-more-text--hover;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
@include to-br(sm) {
|
|
693
|
+
display: none;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/* Влезли плашки в ряд или нет, решает сам браузер: у непрокручиваемого контейнера scroll-таймлайн
|
|
698
|
+
неактивен, анимации не применяются — ни затемнения, ни кнопки. Без замеров и без JS, то есть
|
|
699
|
+
ещё до гидрации. Где scroll() не поддержан — ряд просто обрезается по краю. */
|
|
700
|
+
@supports (animation-timeline: scroll()) {
|
|
701
|
+
.card-video__tags-wrapper {
|
|
702
|
+
scroll-timeline: --card-video-tags inline;
|
|
703
|
+
animation: card-video-tags-fade linear both;
|
|
704
|
+
animation-timeline: --card-video-tags;
|
|
705
|
+
mask-image: linear-gradient(to right, currentcolor calc(100% - var(--card-video-tags-fade)), transparent);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
.card-video__tags-more {
|
|
709
|
+
animation: card-video-tags-more linear both;
|
|
710
|
+
animation-timeline: --card-video-tags;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/* Раскрытый список — тот же DOM: ряд перестаёт быть скроллом и разворачивается поповером поверх */
|
|
715
|
+
.--tags-open .card-video__tags-wrapper {
|
|
716
|
+
position: absolute;
|
|
717
|
+
top: 0;
|
|
718
|
+
left: 0;
|
|
719
|
+
z-index: $z-index-dropdown;
|
|
720
|
+
flex-wrap: wrap;
|
|
721
|
+
width: max-content;
|
|
722
|
+
max-width: 100%;
|
|
723
|
+
padding: 8px $tags-fade 8px 8px;
|
|
724
|
+
overflow: visible;
|
|
725
|
+
background-color: $video-card-tags-popover-bg;
|
|
726
|
+
border: 1px solid $video-card-tags-popover-border;
|
|
727
|
+
border-radius: $radius-md;
|
|
728
|
+
box-shadow: $video-card-tags-popover-shadow;
|
|
729
|
+
mask-image: none;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
.--tags-open .card-video__tags-more {
|
|
733
|
+
visibility: visible;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/* Карточка — свой контекст наложения из-за container-type, поповер иначе уйдёт под соседнюю */
|
|
737
|
+
.card-video.--tags-open {
|
|
738
|
+
z-index: $z-index-dropdown;
|
|
610
739
|
}
|
|
611
740
|
|
|
612
741
|
.card-video__user {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!--
|
|
1
|
+
<!-- Сетка карточек категорий, 1-4 колонки -->
|
|
2
2
|
<template>
|
|
3
3
|
<div class="grid-categories">
|
|
4
4
|
<CardCategory
|
|
@@ -22,15 +22,12 @@ defineProps<{
|
|
|
22
22
|
|
|
23
23
|
<style lang="scss">
|
|
24
24
|
.grid-categories {
|
|
25
|
-
--min-width: 150px;
|
|
26
|
-
|
|
27
25
|
display: grid;
|
|
28
26
|
gap: 12px;
|
|
29
|
-
grid-template-columns: repeat(auto-fill, minmax(var(--min-width), 1fr));
|
|
30
27
|
|
|
31
|
-
@include
|
|
32
|
-
--min-width: 250px;
|
|
28
|
+
@include cards-grid-columns;
|
|
33
29
|
|
|
30
|
+
@include from-br(sm) {
|
|
34
31
|
gap: 16px;
|
|
35
32
|
}
|
|
36
33
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Сетка карточек каналов,
|
|
1
|
+
<!-- Сетка карточек каналов, 1-4 колонки -->
|
|
2
2
|
<template>
|
|
3
3
|
<div
|
|
4
4
|
id="anchor"
|
|
@@ -28,16 +28,6 @@ defineProps<{
|
|
|
28
28
|
display: grid;
|
|
29
29
|
gap: 24px;
|
|
30
30
|
|
|
31
|
-
@include
|
|
32
|
-
grid-template-columns: repeat(2, 1fr);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
@include from-br(sm) {
|
|
36
|
-
grid-template-columns: repeat(3, 1fr);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
@include from-br(md) {
|
|
40
|
-
grid-template-columns: repeat(4, 1fr);
|
|
41
|
-
}
|
|
31
|
+
@include cards-grid-columns;
|
|
42
32
|
}
|
|
43
33
|
</style>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Сетка карточек плейлистов,
|
|
1
|
+
<!-- Сетка карточек плейлистов, 1-4 колонки; попап шаринга — один на список -->
|
|
2
2
|
<template>
|
|
3
3
|
<div class="grid-playlists">
|
|
4
4
|
<CardPlaylist
|
|
@@ -64,12 +64,6 @@ function onShare(card: IPlaylistCard) {
|
|
|
64
64
|
display: grid;
|
|
65
65
|
gap: 24px;
|
|
66
66
|
|
|
67
|
-
@include
|
|
68
|
-
grid-template-columns: repeat(2, 1fr);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
@include from-br(sm) {
|
|
72
|
-
grid-template-columns: repeat(4, 1fr);
|
|
73
|
-
}
|
|
67
|
+
@include cards-grid-columns;
|
|
74
68
|
}
|
|
75
69
|
</style>
|