itube-specs 0.0.866 → 0.0.868

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.
@@ -338,6 +338,18 @@ $language-value-text: $color-white;
338
338
  $language-description: $color-zinc-500;
339
339
  $language-empty-text: $color-zinc-300;
340
340
 
341
+ // ─── Niche ───
342
+ $niche-trigger-text: $color-zinc-400;
343
+ $niche-angle--hover: $color-white;
344
+ $niche-title: $color-zinc-500;
345
+ $niche-value-text: $color-white;
346
+ $niche-menu-bg: $color-night;
347
+ $niche-menu-border: $color-zinc-800;
348
+ $niche-item-text: $color-zinc-300;
349
+ $niche-item-bg--hover: $color-zinc-800;
350
+ $niche-item-text--current: $color-white;
351
+ $niche-item-bg--current: $color-zinc-700;
352
+
341
353
  // ─── Footer language ───
342
354
  $footer-language-bg: $color-zinc-800-50;
343
355
  $footer-language-bg--hover: $color-zinc-700;
@@ -395,6 +395,18 @@ $language-value-text: $color-white;
395
395
  $language-description: $color-gray-500;
396
396
  $language-empty-text: $color-gray-400;
397
397
 
398
+ // ─── Niche ───
399
+ $niche-trigger-text: $color-gray-500;
400
+ $niche-angle--hover: $color-gray-300;
401
+ $niche-title: $color-gray-400;
402
+ $niche-value-text: $color-white;
403
+ $niche-menu-bg: $color-slate-850;
404
+ $niche-menu-border: $color-white-10;
405
+ $niche-item-text: $color-gray-300;
406
+ $niche-item-bg--hover: $color-slate-750;
407
+ $niche-item-text--current: $color-white;
408
+ $niche-item-bg--current: $color-indigo-soft;
409
+
398
410
  // ─── Footer language ───
399
411
  $footer-language-bg: $color-slate-750;
400
412
  $footer-language-bg--hover: $color-slate-700;
@@ -68,6 +68,11 @@
68
68
  </div>
69
69
  </nav>
70
70
 
71
+ <LayoutNiche
72
+ class="layout-burger__niche"
73
+ icon-size="20"
74
+ />
75
+
71
76
  <LayoutLanguage
72
77
  class="layout-burger__language"
73
78
  icon-size="20"
@@ -257,6 +262,10 @@ router.afterEach(() => {
257
262
  padding-bottom: 12px;
258
263
  }
259
264
 
265
+ .layout-burger__niche {
266
+ margin-bottom: 12px;
267
+ }
268
+
260
269
  .layout-burger__close {
261
270
  position: fixed;
262
271
  top: 16px;
@@ -10,6 +10,11 @@
10
10
  glow
11
11
  class="layout-header__logo"
12
12
  />
13
+ <LayoutNiche
14
+ class="layout-header__niche _from-sm"
15
+ icon-size="20"
16
+ />
17
+
13
18
  <div
14
19
  ref="languageRef"
15
20
  class="layout-header__language _from-sm"
@@ -135,7 +140,7 @@ $breakpoint: sm;
135
140
  width: 100%;
136
141
 
137
142
  @include from-br(sm) {
138
- grid-template-columns: auto 1fr auto auto;
143
+ grid-template-columns: auto 1fr auto auto auto;
139
144
  }
140
145
  }
141
146
 
@@ -180,7 +185,14 @@ $breakpoint: sm;
180
185
  .layout-header__user,
181
186
  .layout-header__sign-up {
182
187
  @include from-br(sm) {
183
- grid-column: 4;
188
+ grid-column: 5;
189
+ grid-row: 1;
190
+ }
191
+ }
192
+
193
+ .layout-header__niche {
194
+ @include from-br(sm) {
195
+ grid-column: 3;
184
196
  grid-row: 1;
185
197
  }
186
198
  }
@@ -194,7 +206,7 @@ $breakpoint: sm;
194
206
  .layout-header__language {
195
207
  @include from-br(sm) {
196
208
  position: relative;
197
- grid-column: 3;
209
+ grid-column: 4;
198
210
  grid-row: 1;
199
211
  }
200
212
  }
@@ -0,0 +1,179 @@
1
+ <template>
2
+ <div
3
+ v-if="niches.length > 1"
4
+ ref="nicheRef"
5
+ class="layout-niche"
6
+ @keydown.esc="isOpen = false"
7
+ >
8
+ <button
9
+ :class="{'--open': isOpen}"
10
+ :aria-expanded="isOpen"
11
+ :aria-label="$t('niche')"
12
+ class="layout-niche__trigger"
13
+ type="button"
14
+ @click="isOpen = !isOpen"
15
+ >
16
+ <UiIcon
17
+ :name="currentNiche.icon"
18
+ :size="iconSize"
19
+ class="layout-niche__icon"
20
+ />
21
+ <span class="layout-niche__current _to-sm">
22
+ <span>{{ $t('niche') }}:&nbsp;</span>
23
+ <span class="layout-niche__text">{{ $t(currentNiche.label) }}</span>
24
+ </span>
25
+ <UiIcon
26
+ class="layout-niche__angle"
27
+ name="angle-down"
28
+ size="12"
29
+ />
30
+ </button>
31
+ <ul
32
+ v-if="isOpen"
33
+ class="layout-niche__list"
34
+ >
35
+ <li
36
+ v-for="item in niches"
37
+ :key="`niche-${item.name}`"
38
+ >
39
+ <button
40
+ :class="{'--current': item.name === currentNiche.name}"
41
+ :aria-current="item.name === currentNiche.name ? 'true' : undefined"
42
+ class="layout-niche__item"
43
+ type="button"
44
+ @click="select(item.name)"
45
+ >
46
+ <UiIcon
47
+ :name="item.icon"
48
+ class="layout-niche__item-icon"
49
+ size="20"
50
+ />
51
+ {{ $t(item.label) }}
52
+ </button>
53
+ </li>
54
+ </ul>
55
+ </div>
56
+ </template>
57
+
58
+ <script setup lang="ts">
59
+ import { onClickOutside } from '@vueuse/core';
60
+ import type { Niche } from '../../runtime';
61
+
62
+ withDefaults(defineProps<{
63
+ iconSize?: string
64
+ }>(), {
65
+ iconSize: '20'
66
+ }
67
+ );
68
+
69
+ const { niches, currentNiche, changeNiche } = useNiches();
70
+
71
+ const nicheRef = ref<HTMLElement>();
72
+ const isOpen = ref(false);
73
+
74
+ onClickOutside(nicheRef, () => {
75
+ isOpen.value = false;
76
+ });
77
+
78
+ function select(name: Niche) {
79
+ isOpen.value = false;
80
+ changeNiche(name);
81
+ }
82
+ </script>
83
+
84
+ <style lang="scss">
85
+ .layout-niche {
86
+ display: grid;
87
+
88
+ @include from-br(sm) {
89
+ position: relative;
90
+ }
91
+ }
92
+
93
+ .layout-niche__trigger {
94
+ display: grid;
95
+ grid-auto-flow: column;
96
+ align-items: center;
97
+ justify-content: start;
98
+ column-gap: 6px;
99
+ padding: 6px 8px;
100
+ color: $niche-trigger-text;
101
+
102
+ @include to-br(sm) {
103
+ grid-template-columns: auto 1fr auto;
104
+ width: 100%;
105
+ padding: 10px 16px;
106
+ column-gap: 16px;
107
+ }
108
+ }
109
+
110
+ .layout-niche__current {
111
+ @include font-sm;
112
+
113
+ display: grid;
114
+ grid-template-columns: auto 1fr;
115
+ color: $niche-title;
116
+ }
117
+
118
+ .layout-niche__text {
119
+ color: $niche-value-text;
120
+ font-weight: 500;
121
+ }
122
+
123
+ .layout-niche__angle {
124
+ pointer-events: none;
125
+ transition: transform var(--transition), color var(--transition);
126
+ }
127
+
128
+ .layout-niche__trigger:hover .layout-niche__angle {
129
+ color: $niche-angle--hover;
130
+ }
131
+
132
+ .layout-niche__trigger.--open .layout-niche__angle {
133
+ transform: rotate(180deg);
134
+ }
135
+
136
+ .layout-niche__list {
137
+ display: grid;
138
+
139
+ @include from-br(sm) {
140
+ position: absolute;
141
+ right: 0;
142
+ bottom: -8px;
143
+ z-index: $z-index-plus;
144
+ min-width: 180px;
145
+ padding: 8px;
146
+ background-color: $niche-menu-bg;
147
+ border: 1px solid $niche-menu-border;
148
+ border-radius: $radius-xl;
149
+ transform: translateY(100%);
150
+ }
151
+ }
152
+
153
+ .layout-niche__item {
154
+ @include font-sm;
155
+
156
+ display: grid;
157
+ grid-template-columns: 20px 1fr;
158
+ align-items: center;
159
+ column-gap: 12px;
160
+ width: 100%;
161
+ padding: 10px 16px;
162
+ color: $niche-item-text;
163
+ text-align: start;
164
+ border-radius: $radius-lg;
165
+
166
+ @include hover(background-color) {
167
+ background-color: $niche-item-bg--hover;
168
+ }
169
+
170
+ @include from-br(sm) {
171
+ padding: 8px 10px;
172
+ }
173
+ }
174
+
175
+ .layout-niche__item.--current {
176
+ color: $niche-item-text--current;
177
+ background-color: $niche-item-bg--current;
178
+ }
179
+ </style>
@@ -0,0 +1,47 @@
1
+ import type { Niche } from '../runtime';
2
+ import { NicheHelper } from '../utils/niche-helper';
3
+
4
+ /** Иконка из assets/icons/common под каждую нишу. */
5
+ const NICHE_ICONS: Record<Niche, string> = {
6
+ straight: 'hetero',
7
+ gay: 'gay',
8
+ shemale: 'shemale',
9
+ };
10
+
11
+ export interface INicheItem {
12
+ name: Niche,
13
+ icon: string,
14
+ /** Ключ i18n с названием ниши */
15
+ label: string,
16
+ }
17
+
18
+ /**
19
+ * Ниши сайта для переключателя: список из per-site конфига проекта (appConfig.niches),
20
+ * текущая — из useState('niche') с фолбэком на дефолтную нишу окружения.
21
+ */
22
+ export const useNiches = () => {
23
+ const defaultNiche = NicheHelper.getSiteDefaultNiche();
24
+ const current = useState<Niche>('niche', () => defaultNiche);
25
+ const localePath = useLocalePath();
26
+
27
+ const niches = computed<INicheItem[]>(() =>
28
+ ((useAppConfig().niches as Niche[]) || []).map(name => ({
29
+ name,
30
+ icon: NICHE_ICONS[name] || 'earth',
31
+ label: `niches.${name}`,
32
+ })));
33
+
34
+ const currentNiche = computed(() => niches.value.find(item => item.name === current.value) || niches.value[0]);
35
+
36
+ /**
37
+ * Ниша влияет и на роутинг (префикс пути), и на заголовок X-Niche в SSR-запросах,
38
+ * поэтому переключение — полной перезагрузкой на корень выбранной ниши.
39
+ */
40
+ function changeNiche(name: Niche) {
41
+ if (name === current.value) return;
42
+ current.value = name;
43
+ window.location.href = localePath(name === defaultNiche ? '/' : `/${name}`);
44
+ }
45
+
46
+ return { niches, currentNiche, changeNiche };
47
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "itube-specs",
3
3
  "type": "module",
4
- "version": "0.0.866",
4
+ "version": "0.0.868",
5
5
  "main": "./nuxt.config.ts",
6
6
  "types": "./types/index.d.ts",
7
7
  "scripts": {