itube-specs 0.0.858 → 0.0.861

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/README.md CHANGED
@@ -1,11 +1,14 @@
1
1
  # itube-specs
2
2
 
3
3
  Общий **Nuxt Layer** для сайтов itube. Держит единую базу: компоненты, composables, сервисы, утилиты,
4
- runtime-хелперы, типы, lib-данные, а также middleware, SSR-плагины и BFF-хендлеры (`server/api`).
4
+ runtime-хелперы, типы, lib-данные, middleware, SSR-плагины, BFF-хендлеры (`server/api`) и **весь SCSS —
5
+ палитру, темы, миксины и глобальные стили**.
5
6
  Приложения расширяют слой (`extends: ['itube-specs']`) и форкаются под разные сайты одной ниши —
6
7
  поэтому слой должен оставаться **самодостаточным и site-agnostic**.
7
8
 
8
9
  > Bitbucket: https://bitbucket.org/luckytube/specs/src/master/
10
+ >
11
+ > Заводишь новый сайт поверх слоя — [**NEW_SITE_CHECKLIST.md**](./NEW_SITE_CHECKLIST.md).
9
12
 
10
13
  ---
11
14
 
@@ -63,6 +66,9 @@ npm run patch # npm version patch — бамп версии перед п
63
66
  ```
64
67
 
65
68
  Pre-commit (husky + lint-staged): на закоммиченных файлах прогоняются `eslint --fix` и `stylelint --fix`.
69
+ ⚠️ **Шаблоны `.vue` не типизируются вообще.** Обычный `tsc` их не читает, а `vue-tsc` не подключён (накопился
70
+ бэклог ошибок в шаблонах, подключение — отдельная задача). Значит чистый `tsc` ничего не говорит про выражения
71
+ в шаблоне: арифметика над строковым union, неверный тип пропа, переименованное поле пройдут молча.
66
72
 
67
73
  ---
68
74
 
@@ -81,10 +87,52 @@ lib/ # статические scheme/config-данные (barrel index
81
87
  middleware/ # глобальные: auth.global, normalize.global, age.global
82
88
  plugins/ # SSR/клиент: country/countries/mobile (SSR), services.client, sentry.client, adv
83
89
  server/ # BFF: api/** (тонкие прокси к внешнему API), utils/metrics, plugins/*, tasks
90
+ assets/
91
+ icons/ # спрайты/svg для <UiIcon>
92
+ scss/
93
+ vars/ # _palette (сырые $color-*), _vars (скаляры), _tokens (CSS custom props), _z-index, _index
94
+ themes/ # по папке на тему: light/_theme.scss, dark/_theme.scss — токены по компонентам
95
+ mixins/ # font-sizes, breakpoints, accessibility, page, video-card, surface, button
96
+ base/ # document, global, hacks, animations, loading
97
+ layout/ # layout, page
98
+ main.scss # точка входа: vars/tokens + base + layout
84
99
  ```
85
100
 
86
- > `middleware`/`plugins`/`server` обязаны быть в `files` (whitelist) — иначе не попадут в паблиш
87
- > (см. раздел `files`/`exports`).
101
+ > `middleware`/`plugins`/`server` и каждая подпапка `assets/scss/*` обязаны быть в `files` (whitelist) —
102
+ > иначе не попадут в паблиш (см. раздел `files`/`exports`).
103
+
104
+ ---
105
+
106
+ ## Темы
107
+
108
+ Темы живут здесь, по папке на тему, и раздаются всем сайтам:
109
+
110
+ ```
111
+ assets/scss/themes/light/_theme.scss
112
+ assets/scss/themes/dark/_theme.scss
113
+ ```
114
+
115
+ Приложение только **выбирает** одну — `theme:` в его `config/site.config.ts`. Оттуда значение читают
116
+ и `app.config.ts` (в рантайм), и `nuxt.config.ts`, который добавляет `themes/<theme>/` в Sass
117
+ `loadPaths`. `@forward 'theme'` в `vars/_index.scss` резолвится туда, потому что рядом с ним
118
+ `_theme.scss` нет.
119
+
120
+ **Папка-на-тему обязательна:** Sass требует литеральный путь в `@use`/`@forward`, значит имя файла
121
+ всегда `_theme.scss`, а варьироваться может только папка. Плоские `themes/light.scss` потребовали бы
122
+ `@forward 'themes/light'` — литерал, который нельзя подставить на билде.
123
+
124
+ Приоритет `loadPaths` — приложение первым, поэтому сайт может перекрыть любой партиал по имени:
125
+ свой `assets/scss/vars/_theme.scss` в проекте выиграет у темы слоя (относительный резолв Sass старше
126
+ `loadPaths`). Это точка пер-сайтовой темизации.
127
+
128
+ **Все токены обязаны быть во всех темах.** Отсутствующий токен — жёсткая ошибка Sass в момент, когда
129
+ тема выбрана, то есть падает вся сборка сайта, а не «поехал цвет». Сверять набор имён после любой
130
+ правки темы.
131
+
132
+ Контекстные различия (контрол внутри попапа, вариант кнопки, зависящий от темы) решают миксины
133
+ `surface()` и `button-variant()` из `mixins/`: место объявляет себя, а значения даёт тема через карты
134
+ `$surfaces` / `$button-variant-overrides`. Компоненты про темы не знают. `appConfig.theme` — только
135
+ для структурных различий (`v-if`, другой элемент), никогда для цвета.
88
136
 
89
137
  ---
90
138
 
@@ -117,8 +165,9 @@ ad-конфиг), теперь читается из `runtimeConfig.public` (з
117
165
  `lib/` (scheme, css-breakpoints), middleware (`auth`/`normalize`/`age`), SSR-плагины
118
166
  (`country`/`mobile`/`services`/`sentry`/`adv`), BFF-хендлеры `server/api/**` — всё site-agnostic.
119
167
  - **Приложение:** только per-site — **значения** config (флаги/реклама/локали) через `runtimeConfig.public`
120
- (слой держит пустые контейнеры-заглушки), `assets/scss` (токены), страницы, i18n-локали и остаток
121
- `server/`, завязанный на локали (`locale-guard`, `site/languages`, `is-locale-blocked`).
168
+ (слой держит пустые контейнеры-заглушки), i18n-локали, `public/` и **выбор темы** (`theme:` в
169
+ `config/site.config.ts`). Своего SCSS у приложения нет: `assets/scss/` — пустой слот-оверрайд.
170
+ `server/` целиком в слое, включая locale-кластер.
122
171
 
123
172
  ---
124
173
 
@@ -128,10 +177,14 @@ ad-конфиг), теперь читается из `runtimeConfig.public` (з
128
177
 
129
178
  - **Компоненты** — `pathPrefix: true`: имя = папка + файл (`ui/icon.vue` → `<UiIcon>`), BEM-класс = kebab
130
179
  тега. Корень папки — `index.vue` (или `main.vue`, если иначе имя было бы односложным).
131
- - **`as const`** вместо `enum` — доменные наборы в `runtime/constants/`.
180
+ - **`as const`** вместо `enum` — доменные наборы в `runtime/constants/`, тип через
181
+ `typeof X[keyof typeof X]`. В enum не положить строку из API, он остаётся в бандле, и в
182
+ опубликованном пакете `import type` на нём ломается в рантайме. Фреймворковые union'ы не
183
+ оборачивать. Подробнее — в [CLAUDE.md](./CLAUDE.md).
132
184
  - **Стили** — co-location в `<style lang="scss">` без `scoped`, flat-BEM, только дизайн-токены.
133
- ⚠️ Токены (`vars`/`mixins`) инжектит **приложение** — в слое нет `assets/scss` и `sass`, стили компонентов
134
- компилируются только внутри приложения.
185
+ `vars` и `mixins` **авто-инжектятся** через `additionalData` приложения, поэтому в блоке компонента
186
+ `@use` писать не надо. Сам `sass` в слое не установлен — SCSS компилируется внутри приложения, но
187
+ все исходники (палитра, темы, миксины) лежат здесь.
135
188
  - **Разметка** — семантические теги, `<div>` только когда ничего не подходит.
136
189
  - **TS/JS** — всегда точка с запятой, без лишних комментариев.
137
190
 
@@ -10,7 +10,7 @@
10
10
  transparent-backdrop
11
11
  :back="isBackShow"
12
12
  class="auth-popup"
13
- @back="currentStep -= 1"
13
+ @back="goBack"
14
14
  >
15
15
  <template #title>{{ $t('auth.create_new') }}</template>
16
16
  <AuthRegister
@@ -27,12 +27,12 @@
27
27
  transparent-backdrop
28
28
  :back="isBackShow"
29
29
  class="auth-popup"
30
- @back="currentStep -= 1"
30
+ @back="goBack"
31
31
  >
32
32
  <template #title>{{ $t('auth.welcome_back') }}</template>
33
33
  <AuthLogin
34
34
  @forgot="onRecoveryClick"
35
- @create="currentStep -= 1"
35
+ @create="currentStep = AuthSteps.Registration"
36
36
  />
37
37
  </UiPopup>
38
38
  </transition>
@@ -44,7 +44,7 @@
44
44
  transparent-backdrop
45
45
  :back="isBackShow"
46
46
  class="auth-popup"
47
- @back="currentStep -= 1"
47
+ @back="goBack"
48
48
  >
49
49
  <template #title>{{ $t('auth.recovery_title')}}</template>
50
50
  <AuthRecovery @login="onLoginClick"/>
@@ -59,6 +59,20 @@ const { isAuthPopupOpen, currentStep, additionalText } = useAuthPopup();
59
59
 
60
60
  const backShow = ref(false);
61
61
 
62
+ // Куда ведёт «назад» с каждого шага. Registration — начальный, назад с него нет.
63
+ const previousStep: Partial<Record<AuthSteps, AuthSteps>> = {
64
+ [AuthSteps.Login]: AuthSteps.Registration,
65
+ [AuthSteps.Recovery]: AuthSteps.Login,
66
+ };
67
+
68
+ function goBack(): void {
69
+ const previous = previousStep[currentStep.value];
70
+
71
+ if (previous) {
72
+ currentStep.value = previous;
73
+ }
74
+ }
75
+
62
76
  function onLoginClick(): void {
63
77
  currentStep.value = AuthSteps.Login;
64
78
  backShow.value = true;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "itube-specs",
3
3
  "type": "module",
4
- "version": "0.0.858",
4
+ "version": "0.0.861",
5
5
  "main": "./nuxt.config.ts",
6
6
  "types": "./types/index.d.ts",
7
7
  "scripts": {
@@ -1,7 +1,7 @@
1
1
  export const AuthSteps = {
2
- Registration: 1,
3
- Login: 2,
4
- Recovery: 3,
2
+ Registration: 'registration',
3
+ Login: 'login',
4
+ Recovery: 'recovery',
5
5
  } as const;
6
6
 
7
7
  export type AuthSteps = typeof AuthSteps[keyof typeof AuthSteps];
@@ -1,7 +1,7 @@
1
1
  export const PlaylistStep = {
2
- Edit: 1,
3
- Delete: 2,
4
- DeleteVideo: 3,
2
+ Edit: 'edit',
3
+ Delete: 'delete',
4
+ DeleteVideo: 'delete-video',
5
5
  } as const;
6
6
 
7
7
  export type PlaylistStep = typeof PlaylistStep[keyof typeof PlaylistStep];