itube-specs 0.0.862 → 0.0.864
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 +13 -2
- package/assets/scss/mixins/_surface.scss +10 -8
- package/components/card/channel.vue +1 -1
- package/components/card/playlist.vue +1 -1
- package/components/card/video/index.vue +1 -1
- package/components/filter/selects.vue +1 -1
- package/components/layout/burger.vue +3 -2
- package/components/ui/dropdown.vue +2 -2
- package/components/ui/tooltip.vue +2 -2
- package/config/css-breakpoints.ts +22 -0
- package/config/index.ts +2 -0
- package/config/themes.ts +29 -0
- package/lib/index.ts +0 -1
- package/package.json +15 -6
- package/pages/videos/[slug].vue +1 -1
- package/runtime/utils/check-device-width.ts +3 -3
- package/runtime/utils/server/server-api-helper.ts +1 -1
- package/types/index.d.ts +0 -1
- package/lib/css-breakpoints.ts +0 -15
- package/types/css-breakpoints.d.ts +0 -1
package/README.md
CHANGED
|
@@ -61,11 +61,15 @@ npm run lint # ESLint (гейтит на ноль варнингов)
|
|
|
61
61
|
npm run lint:fix # ESLint --fix
|
|
62
62
|
npm run lint:css # Stylelint по **/*.{scss,vue}
|
|
63
63
|
npm run lint:css:fix # Stylelint --fix
|
|
64
|
+
npm run check:themes # сверяет наборы имён токенов во всех темах
|
|
65
|
+
npm run check:styles # компилирует стили каждого SFC каждой темой (~1.5s)
|
|
64
66
|
npm run test # vitest однократно
|
|
65
67
|
npm run patch # npm version patch — бамп версии перед публикацией
|
|
66
68
|
```
|
|
67
69
|
|
|
68
70
|
Pre-commit (husky + lint-staged): на закоммиченных файлах прогоняются `eslint --fix` и `stylelint --fix`.
|
|
71
|
+
Если в коммите есть `assets/scss/themes/**`, гоняется `check:themes`; если любой `.vue` или `assets/scss/**` —
|
|
72
|
+
`check:styles`. Оба есть и в CI, в шаге Lint.
|
|
69
73
|
⚠️ **Шаблоны `.vue` не типизируются вообще.** Обычный `tsc` их не читает, а `vue-tsc` не подключён (накопился
|
|
70
74
|
бэклог ошибок в шаблонах, подключение — отдельная задача). Значит чистый `tsc` ничего не говорит про выражения
|
|
71
75
|
в шаблоне: арифметика над строковым union, неверный тип пропа, переименованное поле пройдут молча.
|
|
@@ -126,8 +130,15 @@ assets/scss/themes/dark/_theme.scss
|
|
|
126
130
|
`loadPaths`). Это точка пер-сайтовой темизации.
|
|
127
131
|
|
|
128
132
|
**Все токены обязаны быть во всех темах.** Отсутствующий токен — жёсткая ошибка Sass в момент, когда
|
|
129
|
-
тема выбрана, то есть падает вся сборка сайта, а не «поехал цвет».
|
|
130
|
-
|
|
133
|
+
тема выбрана, то есть падает вся сборка сайта, а не «поехал цвет». Это гейтит `npm run check:themes`
|
|
134
|
+
(pre-commit при правке тем + CI). Сверяются только верхнеуровневые `$name:`, поэтому начинка
|
|
135
|
+
`$surfaces` / `$button-variant-overrides` игнорируется — она по замыслу разная.
|
|
136
|
+
|
|
137
|
+
Паритет доказывает лишь то, что темы согласованы **между собой**. Токен, использованный в компоненте, но не
|
|
138
|
+
заведённый **ни в одной** теме, эту проверку пройдёт и всё равно уронит сборку — для этого есть
|
|
139
|
+
`npm run check:styles`: он достаёт каждый `<style lang="scss">`, приписывает тот же `@use`-префикс, что
|
|
140
|
+
подставляет приложение, и компилирует по разу на тему. То же, что делает Vite, — значит ловит и неизвестные
|
|
141
|
+
миксины, и неверные аргументы `@include`, и показывает, в какой теме падает.
|
|
131
142
|
|
|
132
143
|
Контекстные различия (контрол внутри попапа, вариант кнопки, зависящий от темы) решают миксины
|
|
133
144
|
`surface()` и `button-variant()` из `mixins/`: место объявляет себя, а значения даёт тема через карты
|
|
@@ -64,16 +64,18 @@ $surface-roles: (
|
|
|
64
64
|
|
|
65
65
|
$overrides: map.get($surfaces, $name);
|
|
66
66
|
|
|
67
|
-
@
|
|
68
|
-
|
|
67
|
+
@if $overrides {
|
|
68
|
+
@each $role, $value in $overrides {
|
|
69
|
+
$props: map.get($surface-roles, $role);
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
@if not $props {
|
|
72
|
+
@error 'surface(#{$name}): неизвестная роль `#{$role}`. Допустимые: #{map.keys($surface-roles)}';
|
|
73
|
+
}
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
@if $value {
|
|
76
|
+
@each $prop in $props {
|
|
77
|
+
#{$prop}: #{$value};
|
|
78
|
+
}
|
|
77
79
|
}
|
|
78
80
|
}
|
|
79
81
|
}
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
<script setup lang="ts">
|
|
62
62
|
import { convertString, formatDate } from '../../runtime';
|
|
63
63
|
import type { IChannelCard } from '../../types';
|
|
64
|
-
import { CSS_BREAKPOINTS } from '../../
|
|
64
|
+
import { CSS_BREAKPOINTS } from '../../config/css-breakpoints';
|
|
65
65
|
|
|
66
66
|
const props = defineProps<{
|
|
67
67
|
card: IChannelCard
|
|
@@ -176,7 +176,7 @@
|
|
|
176
176
|
import { formatDate, ThumbSize } from '../../runtime';
|
|
177
177
|
import type { IPlaylistCard, IProfileData, IThumbUrls } from '../../types';
|
|
178
178
|
import { AuthorizationApiService } from '../../services/api/authorization.service';
|
|
179
|
-
import { CSS_BREAKPOINTS } from '../../
|
|
179
|
+
import { CSS_BREAKPOINTS } from '../../config/css-breakpoints';
|
|
180
180
|
|
|
181
181
|
const props = defineProps<{
|
|
182
182
|
card: IPlaylistCard
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
<script setup lang="ts">
|
|
138
138
|
import type { IVideoCard } from '../../../types';
|
|
139
139
|
import { convertString, getDuration } from '../../../runtime';
|
|
140
|
-
import { CSS_BREAKPOINTS } from '../../../
|
|
140
|
+
import { CSS_BREAKPOINTS } from '../../../config/css-breakpoints';
|
|
141
141
|
|
|
142
142
|
const featureFlags = useRuntimeConfig().public.featureFlags;
|
|
143
143
|
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
import type { IModelFilter } from '../../types';
|
|
112
112
|
import { onClickOutside } from '@vueuse/core';
|
|
113
113
|
import { convertString, checkDeviceWidth } from '../../runtime';
|
|
114
|
-
import { CSS_BREAKPOINTS } from '../../
|
|
114
|
+
import { CSS_BREAKPOINTS } from '../../config/css-breakpoints';
|
|
115
115
|
|
|
116
116
|
const props = defineProps<{
|
|
117
117
|
filters: IModelFilter[]
|
|
@@ -78,7 +78,8 @@
|
|
|
78
78
|
|
|
79
79
|
<script setup lang="ts">
|
|
80
80
|
import { AuthSteps, onBackdropClick, checkDeviceWidth } from '../../runtime';
|
|
81
|
-
import type {
|
|
81
|
+
import type { IProfileData } from '../../types';
|
|
82
|
+
import { CSS_BREAKPOINTS } from '../../config/css-breakpoints';
|
|
82
83
|
import { AuthorizationApiService } from '../../services/api/authorization.service';
|
|
83
84
|
|
|
84
85
|
import { getNavigationItems } from '../../lib';
|
|
@@ -110,7 +111,7 @@ const { isAuthorized } = useUser(AuthorizationApiService);
|
|
|
110
111
|
|
|
111
112
|
const burgerRef = ref();
|
|
112
113
|
|
|
113
|
-
const breakpoints =
|
|
114
|
+
const breakpoints = CSS_BREAKPOINTS;
|
|
114
115
|
const { isMobile } = checkDeviceWidth(breakpoints);
|
|
115
116
|
|
|
116
117
|
const { scrollLock, scrollUnlock } = useGlobalScrollLock();
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
<script setup lang="ts">
|
|
63
63
|
// На компоненте обязательно вызывать пропсы слота и вешать слот пропс (className) на непосредственных детей
|
|
64
64
|
import { checkDeviceWidth } from '../../runtime';
|
|
65
|
-
import
|
|
65
|
+
import { CSS_BREAKPOINTS } from '../../config/css-breakpoints';
|
|
66
66
|
import { onClickOutside } from '@vueuse/core';
|
|
67
67
|
|
|
68
68
|
const dropdownRef = ref();
|
|
@@ -89,7 +89,7 @@ onClickOutside(dropdownRef, () => {
|
|
|
89
89
|
|
|
90
90
|
const { scrollLock, scrollUnlock } = useGlobalScrollLock();
|
|
91
91
|
|
|
92
|
-
const breakpoints =
|
|
92
|
+
const breakpoints = CSS_BREAKPOINTS;
|
|
93
93
|
const { isTablet } = checkDeviceWidth(breakpoints);
|
|
94
94
|
|
|
95
95
|
function checkPosition() {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
<script setup lang="ts">
|
|
30
30
|
import { checkDeviceWidth } from '../../runtime';
|
|
31
31
|
import { onClickOutside } from '@vueuse/core';
|
|
32
|
-
import
|
|
32
|
+
import { CSS_BREAKPOINTS } from '../../config/css-breakpoints';
|
|
33
33
|
|
|
34
34
|
defineProps<{
|
|
35
35
|
right?: boolean
|
|
@@ -38,7 +38,7 @@ defineProps<{
|
|
|
38
38
|
const tooltipRef = ref<HTMLElement>();
|
|
39
39
|
const isOpen = ref(false);
|
|
40
40
|
|
|
41
|
-
const breakpoints =
|
|
41
|
+
const breakpoints = CSS_BREAKPOINTS;
|
|
42
42
|
const { isMobile } = checkDeviceWidth(breakpoints);
|
|
43
43
|
|
|
44
44
|
onClickOutside(tooltipRef, () => {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Имя брейкпоинта. Совпадает с ключами `$brkpnts` в assets/scss/mixins/_breakpoints.scss. */
|
|
2
|
+
export type CssBreakpointName = 'xs' | 'xm' | 'sm' | 'md' | 'ml' | 'lg' | 'xl';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* JS-зеркало брейкпоинтов из SCSS.
|
|
6
|
+
*
|
|
7
|
+
* Источник истины — `$brkpnts` в assets/scss/mixins/_breakpoints.scss: по нему работают
|
|
8
|
+
* миксины вёрстки. JS прочитать SCSS не может, поэтому здесь зеркало — оно нужно там, где
|
|
9
|
+
* ширину надо знать в скрипте: `sizes` у картинок, брейкпоинты свайпера, checkDeviceWidth.
|
|
10
|
+
*
|
|
11
|
+
* Значения обязаны совпадать с SCSS — это проверяет `check:breakpoints`. Разойдутся —
|
|
12
|
+
* атрибут `sizes` начнёт врать браузеру про точку переключения раскладки.
|
|
13
|
+
*/
|
|
14
|
+
export const CSS_BREAKPOINTS: Record<CssBreakpointName, number> = {
|
|
15
|
+
xs: 475,
|
|
16
|
+
xm: 650,
|
|
17
|
+
sm: 960,
|
|
18
|
+
md: 1350,
|
|
19
|
+
ml: 1500,
|
|
20
|
+
lg: 1792,
|
|
21
|
+
xl: 2560,
|
|
22
|
+
};
|
package/config/index.ts
ADDED
package/config/themes.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Имя темы = имя папки в assets/scss/themes/. */
|
|
2
|
+
export type ThemeName = 'light' | 'dark';
|
|
3
|
+
|
|
4
|
+
export interface ThemeMeta {
|
|
5
|
+
/** Подсказка браузеру для нативных контролов и скроллбаров. */
|
|
6
|
+
colorScheme: 'light' | 'dark';
|
|
7
|
+
/** Цвет хрома браузера. Обязан совпадать с `$body-bg` этой темы. */
|
|
8
|
+
themeColor: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* JS-сторона тем: то, что нужно знать о теме вне Sass.
|
|
13
|
+
*
|
|
14
|
+
* Цвета живут в SCSS (assets/scss/themes/<name>/_theme.scss), но `theme-color` и
|
|
15
|
+
* `color-scheme` нужны в `nuxt.config` на этапе сборки, куда SCSS не дотягивается.
|
|
16
|
+
* Поэтому здесь минимальное дублирование — только хром браузера.
|
|
17
|
+
*
|
|
18
|
+
* Список должен совпадать с папками в assets/scss/themes/ — это проверяет `check:themes`.
|
|
19
|
+
*/
|
|
20
|
+
export const themes: Record<ThemeName, ThemeMeta> = {
|
|
21
|
+
light: {
|
|
22
|
+
colorScheme: 'light',
|
|
23
|
+
themeColor: '#1e2a3a', // = $body-bg темы light ($color-slate-800)
|
|
24
|
+
},
|
|
25
|
+
dark: {
|
|
26
|
+
colorScheme: 'dark',
|
|
27
|
+
themeColor: '#0d0d0d', // = $body-bg темы dark ($color-black)
|
|
28
|
+
},
|
|
29
|
+
};
|
package/lib/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "itube-specs",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.864",
|
|
5
5
|
"main": "./nuxt.config.ts",
|
|
6
6
|
"types": "./types/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
"lint:fix": "eslint . --fix",
|
|
12
12
|
"lint:css": "stylelint \"**/*.{scss,vue}\" --max-warnings=0 --allow-empty-input",
|
|
13
13
|
"lint:css:fix": "stylelint \"**/*.{scss,vue}\" --fix --allow-empty-input",
|
|
14
|
+
"check:themes": "node scripts/check-themes.mjs",
|
|
15
|
+
"check:styles": "node scripts/check-styles.mjs",
|
|
16
|
+
"check:breakpoints": "node scripts/check-breakpoints.mjs",
|
|
14
17
|
"test": "NODE_OPTIONS='--no-warnings' vitest",
|
|
15
18
|
"prepare": "husky"
|
|
16
19
|
},
|
|
@@ -39,6 +42,10 @@
|
|
|
39
42
|
"import": "./lib/index.ts",
|
|
40
43
|
"default": "./lib/index.ts"
|
|
41
44
|
},
|
|
45
|
+
"./config": {
|
|
46
|
+
"import": "./config/index.ts",
|
|
47
|
+
"default": "./config/index.ts"
|
|
48
|
+
},
|
|
42
49
|
"./services/*": "./services/*.ts",
|
|
43
50
|
"./composables/*": "./composables/*.ts",
|
|
44
51
|
"./utils/*": "./utils/*.ts",
|
|
@@ -51,6 +58,7 @@
|
|
|
51
58
|
"services/",
|
|
52
59
|
"utils/",
|
|
53
60
|
"types/",
|
|
61
|
+
"config/",
|
|
54
62
|
"lib/",
|
|
55
63
|
"middleware/",
|
|
56
64
|
"plugins/",
|
|
@@ -69,26 +77,27 @@
|
|
|
69
77
|
],
|
|
70
78
|
"devDependencies": {
|
|
71
79
|
"@intlify/eslint-plugin-vue-i18n": "^4.5.1",
|
|
72
|
-
"@nuxt/eslint": "
|
|
80
|
+
"@nuxt/eslint": "^1.16.0",
|
|
73
81
|
"@nuxt/icon": "1.15.0",
|
|
74
82
|
"@nuxt/test-utils": "^3.23.0",
|
|
75
83
|
"@nuxtjs/i18n": "9.5.6",
|
|
76
84
|
"@types/node": "^20.19.19",
|
|
77
|
-
"@vue/test-utils": "^2.4.
|
|
78
|
-
"eslint": "^9.
|
|
85
|
+
"@vue/test-utils": "^2.4.11",
|
|
86
|
+
"eslint": "^9.39.5",
|
|
79
87
|
"happy-dom": "^18.0.1",
|
|
80
88
|
"husky": "^9.1.7",
|
|
81
89
|
"lint-staged": "^17.0.7",
|
|
82
90
|
"nuxt": "^3.21.8",
|
|
83
91
|
"postcss-html": "^1.8.1",
|
|
92
|
+
"sass": "^1.102.0",
|
|
84
93
|
"stylelint": "^17.13.0",
|
|
85
94
|
"stylelint-config-standard-scss": "^17.0.0",
|
|
86
95
|
"typescript": "^5.9.3",
|
|
87
|
-
"vitest": "^3.2.
|
|
96
|
+
"vitest": "^3.2.7",
|
|
88
97
|
"vue": "3.5.17"
|
|
89
98
|
},
|
|
90
99
|
"dependencies": {
|
|
91
|
-
"@sentry/nuxt": "^10.
|
|
100
|
+
"@sentry/nuxt": "^10.69.0",
|
|
92
101
|
"@vueform/slider": "2.1.10",
|
|
93
102
|
"@vueuse/core": "12.8.2"
|
|
94
103
|
}
|
package/pages/videos/[slug].vue
CHANGED
|
@@ -28,7 +28,7 @@ import { SearchApiService } from '../../services/api/search.service';
|
|
|
28
28
|
import { VideosApiService } from '../../services/api/videos.service';
|
|
29
29
|
import { ModelsApiService } from '../../services/api/models.service';
|
|
30
30
|
import { AsyncData, ThumbSize } from '../../runtime';
|
|
31
|
-
import { CSS_BREAKPOINTS } from '../../
|
|
31
|
+
import { CSS_BREAKPOINTS } from '../../config';
|
|
32
32
|
|
|
33
33
|
const featureFlags = useRuntimeConfig().public.featureFlags;
|
|
34
34
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useBreakpoints } from '@vueuse/core';
|
|
2
|
-
import type {
|
|
2
|
+
import type { CssBreakpointName } from '../../config/css-breakpoints';
|
|
3
3
|
|
|
4
|
-
function breakpoints(breakpoints: Record<
|
|
4
|
+
function breakpoints(breakpoints: Record<CssBreakpointName, number>) {
|
|
5
5
|
return useBreakpoints(
|
|
6
6
|
{
|
|
7
7
|
xs: breakpoints.xs,
|
|
@@ -17,7 +17,7 @@ function breakpoints(breakpoints: Record<CssBreakpoints, number>) {
|
|
|
17
17
|
* Возвращает реактивные флаги isMobile и isTablet на основе переданных breakpoints.
|
|
18
18
|
* @param projectBreakpoints - набор брейкпоинтов проекта (xs, sm, md, lg, xl) в пикселях
|
|
19
19
|
*/
|
|
20
|
-
export const checkDeviceWidth = (projectBreakpoints: Record<
|
|
20
|
+
export const checkDeviceWidth = (projectBreakpoints: Record<CssBreakpointName, number>) => {
|
|
21
21
|
const isMobile = breakpoints(projectBreakpoints).smaller('sm');
|
|
22
22
|
const isTablet = breakpoints(projectBreakpoints).smaller('md');
|
|
23
23
|
|
|
@@ -17,7 +17,7 @@ export class ServerApiHelper {
|
|
|
17
17
|
});
|
|
18
18
|
return response.data;
|
|
19
19
|
} catch (error: any) {
|
|
20
|
-
throw new Error(`Cannot fetch ${url}: ${error?.data ?? error?.message ?? error}
|
|
20
|
+
throw new Error(`Cannot fetch ${url}: ${error?.data ?? error?.message ?? error}`, { cause: error });
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -57,7 +57,6 @@ export * from './search-top-models.d.ts';
|
|
|
57
57
|
export * from './select-item.d.ts';
|
|
58
58
|
export * from './model-group.d.ts';
|
|
59
59
|
export * from './change-email-form.d.ts';
|
|
60
|
-
export * from './css-breakpoints.d.ts';
|
|
61
60
|
export * from './button-sizes.d.ts';
|
|
62
61
|
export * from './button-themes.d.ts';
|
|
63
62
|
export * from './report-request.d.ts';
|
package/lib/css-breakpoints.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export type CssBreakpointName = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Брейкпоинты на проекте,
|
|
5
|
-
* должны совпадать с тем что в CSS assets/scss/_breakpoints.scss
|
|
6
|
-
*
|
|
7
|
-
* Используется для свайпера, для установки брейкпоинтов у него.
|
|
8
|
-
*/
|
|
9
|
-
export const CSS_BREAKPOINTS: Record<CssBreakpointName, number> = {
|
|
10
|
-
xs: 475,
|
|
11
|
-
sm: 960,
|
|
12
|
-
md: 1350,
|
|
13
|
-
lg: 1600,
|
|
14
|
-
xl: 2560,
|
|
15
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type CssBreakpoints = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|