itube-specs 0.0.920 → 0.0.922

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.
@@ -82,15 +82,18 @@ summary::-webkit-details-marker {
82
82
  clip-path: inset(100%);
83
83
  }
84
84
 
85
+ // Убрать элемент из потока целиком, в отличие от ._visually-hidden.
85
86
  ._hidden {
86
87
  display: none !important;
87
88
  }
88
89
 
89
90
  @for $i from 1 through 12 {
91
+ // Отбивка снизу: чётные значения 2…24px (._mb-8 = margin-bottom: 8px).
90
92
  ._mb-#{$i * 2} {
91
93
  margin-bottom: #{$i * 2}px;
92
94
  }
93
95
 
96
+ // Отбивка сверху: чётные значения 2…24px (._mt-8 = margin-top: 8px).
94
97
  ._mt-#{$i * 2} {
95
98
  margin-top: #{$i * 2}px;
96
99
  }
@@ -1,5 +1,6 @@
1
1
  @use 'vars' as *;
2
2
 
3
+ // Состояние загрузки блока: заблюренная подложка со спиннером поверх содержимого (::before/::after).
3
4
  ._loading {
4
5
  position: relative;
5
6
 
@@ -1,21 +1,31 @@
1
1
  @use '../mixins/breakpoints' as *;
2
2
 
3
+ // Виден только ниже xs (475px), на xs и шире скрыт.
3
4
  @include from-br(xs) { ._to-xs { display: none !important; } }
4
5
 
6
+ // Виден только ниже sm (960px), на sm и шире скрыт.
5
7
  @include from-br(sm) { ._to-sm { display: none !important; } }
6
8
 
9
+ // Виден только ниже md (1350px), на md и шире скрыт.
7
10
  @include from-br(md) { ._to-md { display: none !important; } }
8
11
 
12
+ // Виден только ниже lg (1792px), на lg и шире скрыт.
9
13
  @include from-br(lg) { ._to-lg { display: none !important; } }
10
14
 
15
+ // Виден с xs (475px) и шире, ниже скрыт.
11
16
  @include to-br(xs) { ._from-xs { display: none !important; } }
12
17
 
18
+ // Виден с sm (960px) и шире, ниже скрыт.
13
19
  @include to-br(sm) { ._from-sm { display: none !important; } }
14
20
 
21
+ // Виден с md (1350px) и шире, ниже скрыт.
15
22
  @include to-br(md) { ._from-md { display: none !important; } }
16
23
 
24
+ // Виден с lg (1792px) и шире, ниже скрыт.
17
25
  @include to-br(lg) { ._from-lg { display: none !important; } }
18
26
 
27
+ // Обрезка текста в N строк: число строк задаётся --line-clamp (по умолчанию 1),
28
+ // выравнивание — --align, перенос — --word-break.
19
29
  ._truncate {
20
30
  display: -webkit-box !important;
21
31
  -webkit-line-clamp: var(--line-clamp, 1);
@@ -1,15 +1,18 @@
1
1
  @use 'vars' as *;
2
2
  @use '../mixins' as *;
3
3
 
4
+ // Корень страницы: колонка с вертикальными отступами. Вешается на корневой элемент в pages/**.
4
5
  ._page {
5
6
  @include page;
6
7
  }
7
8
 
9
+ // Хлебные крошки. Свой верхний отступ нужен, когда крошки лежат вне ._page.
8
10
  ._breadcrumbs {
9
11
  margin-bottom: 24px;
10
12
  padding-top: 24px;
11
13
  }
12
14
 
15
+ // Крошки на страницах с инфо-блоком — отбивка снизу меньше.
13
16
  ._breadcrumbs-info {
14
17
  margin-bottom: 16px;
15
18
  padding-top: 24px;
@@ -20,20 +23,24 @@
20
23
  padding-top: 0;
21
24
  }
22
25
 
26
+ // Блок SEO-ссылок внизу страницы: прижат к низу и отбит линией.
23
27
  ._footer-links {
24
28
  @include page-footer-links;
25
29
  }
26
30
 
31
+ // Заголовок страницы: font-lg, uppercase, 700.
27
32
  ._title {
28
33
  @include page-title;
29
34
 
30
35
  margin-bottom: 24px;
31
36
  }
32
37
 
38
+ // Строка фильтров/навигации под заголовком — только отбивка снизу.
33
39
  ._nav-filter {
34
40
  margin-bottom: 32px;
35
41
  }
36
42
 
43
+ // Центрирующий контейнер: боковые паддинги из --container-padding-inline, с md — max-width.
37
44
  ._container {
38
45
  width: 100%;
39
46
  margin: 0 auto;
@@ -44,6 +51,7 @@
44
51
  }
45
52
  }
46
53
 
54
+ // Пагинация внизу листинга — только отбивка сверху.
47
55
  ._pagination {
48
56
  margin-top: 32px;
49
57
  }
@@ -60,9 +60,9 @@ $brkpnts: (
60
60
  }
61
61
 
62
62
  /**
63
- Container query брейкпоинты
64
- @include from-cq($width) { ... }
65
- @include to-cq($width) { ... }
63
+ Container query брейкпоинты — меряют контейнер, а не окно. Требуют `container-type`
64
+ на предке; значение только в единицах, ключей из $brkpnts тут нет.
65
+ @include from-cq(400px) { ... }
66
66
  */
67
67
  @mixin from-cq($bp) {
68
68
  @container (min-width: #{$bp}) {
@@ -70,6 +70,9 @@ $brkpnts: (
70
70
  }
71
71
  }
72
72
 
73
+ /**
74
+ @include to-cq(400px) { ... }
75
+ */
73
76
  @mixin to-cq($bp) {
74
77
  @container (max-width: #{$bp - 1px}) {
75
78
  @content;
@@ -1,58 +1,70 @@
1
+ // 10px / 10px
1
2
  @mixin font-4xs {
2
3
  font-size: 10px;
3
4
  line-height: 1;
4
5
  }
5
6
 
7
+ // 11px / 11px
6
8
  @mixin font-3xs {
7
9
  font-size: 11px;
8
10
  line-height: 1;
9
11
  }
10
12
 
13
+ // 12px / 16px
11
14
  @mixin font-xs {
12
15
  font-size: 12px;
13
16
  line-height: 1.333;
14
17
  }
15
18
 
19
+ // 13px / 19.5px
16
20
  @mixin font-2xs {
17
21
  font-size: 13px;
18
22
  line-height: 1.5;
19
23
  }
20
24
 
25
+ // 14px / 20px
21
26
  @mixin font-sm {
22
27
  font-size: 14px;
23
28
  line-height: 1.429;
24
29
  }
25
30
 
31
+ // 15px / 22.5px
26
32
  @mixin font-md {
27
33
  font-size: 15px;
28
34
  line-height: 1.5;
29
35
  }
30
36
 
37
+ // 16px / 24px
31
38
  @mixin font-base {
32
39
  font-size: 16px;
33
40
  line-height: 1.5;
34
41
  }
35
42
 
43
+ // 18px / 28px
36
44
  @mixin font-lg {
37
45
  font-size: 18px;
38
46
  line-height: 1.556;
39
47
  }
40
48
 
49
+ // 20px / 28px
41
50
  @mixin font-xl {
42
51
  font-size: 20px;
43
52
  line-height: 1.4;
44
53
  }
45
54
 
55
+ // 24px / 32px
46
56
  @mixin font-2xl {
47
57
  font-size: 24px;
48
58
  line-height: 1.333;
49
59
  }
50
60
 
61
+ // 30px / 36px
51
62
  @mixin font-3xl {
52
63
  font-size: 30px;
53
64
  line-height: 1.2;
54
65
  }
55
66
 
67
+ // 36px / 40px
56
68
  @mixin font-4xl {
57
69
  font-size: 36px;
58
70
  line-height: 1.111;
@@ -2,6 +2,8 @@
2
2
  @use 'font-sizes' as *;
3
3
  @use 'vars' as *;
4
4
 
5
+ // Каркас страницы: колонка с вертикальными отступами. В разметке используется через
6
+ // глобальный класс `._page` (layout/_page.scss), напрямую в компонентах не нужен.
5
7
  @mixin page {
6
8
  display: flex;
7
9
  flex-direction: column;
@@ -9,6 +11,7 @@
9
11
  padding-bottom: 24px;
10
12
  }
11
13
 
14
+ // Заголовок страницы: font-lg, uppercase, 700. В разметке — глобальный класс `._title`.
12
15
  @mixin page-title {
13
16
  @include font-lg;
14
17
 
@@ -17,6 +20,8 @@
17
20
  font-weight: 700;
18
21
  }
19
22
 
23
+ // Блок SEO-ссылок внизу страницы: прижат к низу (margin-top: auto) и отбит линией.
24
+ // В разметке — глобальный класс `._footer-links`.
20
25
  @mixin page-footer-links {
21
26
  margin-top: auto;
22
27
  padding-top: 8px;
@@ -2,6 +2,7 @@
2
2
  @use 'font-sizes' as *;
3
3
  @use 'vars' as *;
4
4
 
5
+ // Каркас карточки видео: колонка «постер + мета» с зазором 16px, контент прижат к верху.
5
6
  @mixin video-card {
6
7
  display: grid;
7
8
  row-gap: 16px;
@@ -32,6 +33,7 @@
32
33
  }
33
34
  }
34
35
 
36
+ // Постер карточки: 16/9, скруглённый, с обрезкой — база для абсолютных бейджей поверх.
35
37
  @mixin video-card-poster {
36
38
  position: relative;
37
39
  aspect-ratio: 16/9;
@@ -720,6 +720,7 @@ $player-menu-option-bar--active: $color-zinc-400; // bg-zinc-400
720
720
  $player-menu-row-bg--hover: $mono-white-10;
721
721
  $player-menu-option-bg--hover: $mono-white-5; // hover:bg-white/5
722
722
  $player-menu-toggle-bg--active: $color-indigo-500; // switch on: bg-indigo-500
723
+ $player-center-label-shadow: $color-black-50; // мета в центре бара поверх видео
723
724
 
724
725
  // accordion (scene types)
725
726
  $player-menu-acc-border: $color-zinc-800-60; // border-zinc-800/60
@@ -771,6 +771,7 @@ $player-menu-option-bar--active: $color-gray-400; // bg-zinc-400
771
771
  $player-menu-row-bg--hover: $mono-white-10;
772
772
  $player-menu-option-bg--hover: $mono-white-5; // hover:bg-white/5
773
773
  $player-menu-toggle-bg--active: $color-indigo-500; // switch on: bg-indigo-500
774
+ $player-center-label-shadow: $color-black-50; // мета в центре бара поверх видео
774
775
 
775
776
  // accordion (scene types)
776
777
  $player-menu-acc-border: $color-slate-700; // border-zinc-800/60
@@ -208,7 +208,7 @@ function nextPreviewMeta(card: IVideoCard): PreviewMetaItem[] {
208
208
  { text: card.channelName || t('user_uploaded'), icon: CHANNEL_META_ICON },
209
209
  ];
210
210
  if (!props.hideViews && card.views != null) {
211
- meta.push(`${n(card.views, 'compact')} ${t('views')}`);
211
+ meta.push(`${n(card.views, 'compact')} ${t('views', card.views)}`);
212
212
  }
213
213
  return meta;
214
214
  }
@@ -244,6 +244,32 @@ watch(() => props.data.videoUrl, () => {
244
244
  source.value = buildSource();
245
245
  });
246
246
 
247
+ /**
248
+ * Центр контрол-бара: «N просмотров · 3 месяца назад» вместо названия текущей
249
+ * сцены (опция `controls.centerLabel`, плеер 0.11.0+). Больше этой меты на
250
+ * странице нигде нет — под плеером её не выводим.
251
+ *
252
+ * Отдаём СВОЙ элемент, а не строку: кастомный центр плеер рисует один раз при
253
+ * инициализации и больше не трогает, а ролик на странице меняется без пересоздания
254
+ * плеера (`externalAdvance` → `player.load()`), так что строка осталась бы от
255
+ * предыдущего ролика. Свой элемент мы просто переписываем сами.
256
+ */
257
+ const centerLabel = shallowRef<HTMLElement | null>(null);
258
+
259
+ if (import.meta.client) {
260
+ centerLabel.value = document.createElement('span');
261
+ }
262
+
263
+ watchEffect(() => {
264
+ if (!centerLabel.value) return;
265
+
266
+ const parts: string[] = [];
267
+ if (props.data.views != null) parts.push(`${n(props.data.views, 'compact')} ${t('views', props.data.views)}`);
268
+ if (props.data.created) parts.push(useFormatTimeAgo(props.data.created, locale.value));
269
+
270
+ centerLabel.value.textContent = parts.join(' · ');
271
+ });
272
+
247
273
  const options = computed<Omit<PlayerOptions, 'source'>>(() => ({
248
274
  playOnInit: true,
249
275
  muted: false,
@@ -265,6 +291,8 @@ const options = computed<Omit<PlayerOptions, 'source'>>(() => ({
265
291
  scenes: false,
266
292
  // Порядок правого кластера: sceneTypes → gear (настройки) → fullscreen (последней).
267
293
  order: ['sceneTypes', 'gear', 'fullscreen'],
294
+ // Центр бара — мета ролика вместо названия текущей сцены (см. centerLabel выше).
295
+ centerLabel: centerLabel.value || false,
268
296
  },
269
297
  icons: PLAYER_ICONS,
270
298
  // Заголовок дропдауна выбора типа сцен (дефолт «Scene type»).
@@ -300,4 +328,12 @@ async function loadAdConfig(): Promise<AdsOptions | undefined> {
300
328
  border-radius: 0;
301
329
  }
302
330
  }
331
+
332
+ // Мета ролика в центре бара: по макету белая с тенью и средней жирностью,
333
+ // у плеера по умолчанию — приглушённая и без тени.
334
+ .player-core .imp-controls__chapter {
335
+ font-weight: 500;
336
+ opacity: 1;
337
+ filter: drop-shadow(0 1px 2px $player-center-label-shadow);
338
+ }
303
339
  </style>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "itube-specs",
3
3
  "type": "module",
4
- "version": "0.0.920",
4
+ "version": "0.0.922",
5
5
  "main": "./nuxt.config.ts",
6
6
  "types": "./types/index.d.ts",
7
7
  "scripts": {
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Гарантирует `X-Domain` у запросов к BFF.
3
+ *
4
+ * Бекенд разруливает сайты по этому заголовку — у stripcash-ручек к домену
5
+ * привязан ещё и ключ провайдера, поэтому без него они отвечают 500
6
+ * («mux: route doesn't have a host»). Заголовок ставит `ApiHelper`, но не каждый
7
+ * вызов идёт через него: блок вебкамов, например, дёргает свою ручку обычным
8
+ * `useFetch`, и тогда до бекенда доезжали только проксированные заголовки запроса
9
+ * страницы — на локальной машине это прощалось, а за прокси на стенде ломалось.
10
+ *
11
+ * Значение берём из runtimeConfig сайта и НЕ перебиваем то, что уже пришло.
12
+ */
13
+ export default defineEventHandler((event) => {
14
+ if (!event.path.startsWith('/api/') && !event.path.startsWith('/bff/')) return;
15
+ if (event.node.req.headers['x-domain']) return;
16
+
17
+ const xDomain = useRuntimeConfig(event).public.xDomain;
18
+ if (xDomain) event.node.req.headers['x-domain'] = String(xDomain);
19
+ });