itube-specs 0.0.795 → 0.0.796
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/composables/fetch/use-fetch-categories-by-letter.ts +15 -15
- package/composables/fetch/use-fetch-categories-by-phrase.ts +18 -18
- package/composables/fetch/use-fetch-categories-group-by-letter.ts +13 -13
- package/composables/fetch/use-fetch-channels-by-model.ts +18 -18
- package/composables/fetch/use-fetch-channels-by-name.ts +15 -15
- package/composables/fetch/use-fetch-channels-by-network-name.ts +30 -30
- package/composables/fetch/use-fetch-channels.ts +31 -31
- package/composables/fetch/use-fetch-dictionaries-countries.ts +13 -13
- package/composables/fetch/use-fetch-dictionaries-genders.ts +13 -13
- package/composables/fetch/use-fetch-groups-categories-lazy.ts +15 -15
- package/composables/fetch/use-fetch-groups-categories.ts +13 -13
- package/composables/fetch/use-fetch-model-by-name.ts +15 -15
- package/composables/fetch/use-fetch-models-by-category.ts +17 -17
- package/composables/fetch/use-fetch-models-by-channel.ts +17 -17
- package/composables/fetch/use-fetch-models-by-letter.ts +40 -40
- package/composables/fetch/use-fetch-models-by-phrases.ts +32 -32
- package/composables/fetch/use-fetch-models-by-tag.ts +1 -1
- package/composables/fetch/use-fetch-models-related.ts +24 -24
- package/composables/fetch/use-fetch-models.ts +38 -38
- package/composables/fetch/use-fetch-multi-suggest.ts +27 -27
- package/composables/fetch/use-fetch-playlists-by-id.ts +15 -15
- package/composables/fetch/use-fetch-playlists-by-niche.ts +30 -30
- package/composables/fetch/use-fetch-playlists-get-videos-by-id.ts +29 -29
- package/composables/fetch/use-fetch-related-searches.ts +11 -11
- package/composables/fetch/use-fetch-related-videos.ts +27 -27
- package/composables/fetch/use-fetch-top-chips-models.ts +15 -15
- package/composables/fetch/use-fetch-top-models.ts +19 -19
- package/composables/fetch/use-fetch-top-random-categories.ts +13 -13
- package/composables/fetch/use-fetch-top-random-full.ts +17 -17
- package/composables/fetch/use-fetch-video-referer-phrases.ts +34 -34
- package/composables/fetch/use-fetch-videos-by-categories.ts +34 -34
- package/composables/fetch/use-fetch-videos-by-channel.ts +34 -34
- package/composables/fetch/use-fetch-videos-by-model-and-channel.ts +40 -40
- package/composables/fetch/use-fetch-videos-by-model-and-tag.ts +40 -40
- package/composables/fetch/use-fetch-videos-by-model.ts +34 -34
- package/composables/fetch/use-fetch-videos-by-tag.ts +34 -34
- package/composables/fetch/use-fetch-videos-search-by-niche.ts +32 -32
- package/composables/use-api-fetcher-no-cache.ts +24 -24
- package/composables/use-api-fetcher.ts +19 -19
- package/composables/use-get-videos-filter-request.ts +28 -28
- package/composables/use-lang.ts +8 -8
- package/composables/use-meta.ts +54 -54
- package/composables/use-noindex.ts +8 -8
- package/composables/use-report-popup.ts +19 -19
- package/lib/contact-forms-scheme.ts +92 -92
- package/lib/contacts/report-issue-items.ts +3 -3
- package/lib/contacts/report-malware-items.ts +4 -4
- package/lib/contacts/report-reasons-items.ts +10 -10
- package/lib/contacts/report-wrong-items.ts +4 -4
- package/lib/report-forms-scheme.ts +259 -259
- package/lib/scheme/categories-navigation.ts +8 -8
- package/lib/scheme/select-added-items.ts +41 -41
- package/lib/scheme/select-duration-items.ts +35 -35
- package/nuxt.config.ts +18 -18
- package/package.json +1 -1
- package/runtime/constants/adverts.ts +5 -5
- package/runtime/constants/async-data.ts +57 -57
- package/runtime/constants/languages.ts +12 -12
- package/runtime/constants/niche.ts +3 -3
- package/runtime/constants/playlist-type.ts +2 -2
- package/runtime/utils/check-device-width.ts +18 -18
- package/runtime/utils/cleaners/clean-mini-category-card.ts +5 -5
- package/runtime/utils/cleaners/clean-model-card.ts +20 -20
- package/runtime/utils/cleaners/clean-video-data.ts +50 -50
- package/runtime/utils/converters/convert-date-to-timestamp.ts +22 -22
- package/runtime/utils/converters/convert-query-categories.ts +2 -2
- package/runtime/utils/converters/convert-string-array-to-chips.ts +6 -6
- package/runtime/utils/converters/convert-string.ts +0 -0
- package/runtime/utils/server/age.ts +55 -55
- package/runtime/utils/server/api-helper.ts +26 -26
- package/runtime/utils/server/get-url-with-proxied-params.ts +3 -3
- package/runtime/utils/server/server-api-helper.ts +15 -15
- package/runtime/utils/validate-email.ts +2 -2
- package/services/api/categories.service.ts +222 -222
- package/services/api/dictionaries.service.ts +28 -28
- package/services/api/models.service.ts +297 -297
- package/types/authorization-forms.d.ts +8 -8
- package/types/burger-menu-item.d.ts +5 -5
- package/types/change-email-form.d.ts +1 -1
- package/types/change-password-form.d.ts +2 -2
- package/types/chips-item.d.ts +8 -8
- package/types/contacts-scheme.d.ts +9 -9
- package/types/country.d.ts +5 -5
- package/types/fluid-player.d.ts +176 -176
- package/types/gender.d.ts +4 -4
- package/types/group-categories.d.ts +10 -10
- package/types/info-chips.d.ts +2 -2
- package/types/model-card.d.ts +15 -15
- package/types/model-filter-payload.d.ts +2 -2
- package/types/model-filter.d.ts +10 -10
- package/types/model-group.d.ts +4 -4
- package/types/model-tag.d.ts +3 -3
- package/types/playlist-short.d.ts +2 -2
- package/types/playlist-video-form.d.ts +7 -7
- package/types/popular-tags.d.ts +2 -2
- package/types/raw/raw-playlist-user.d.ts +20 -20
- package/types/raw/raw-thumbs-urls.d.ts +2 -2
- package/types/raw/raw-video-card.d.ts +70 -70
- package/types/raw/raw-video-data.d.ts +50 -50
- package/types/recovery-password-form.d.ts +2 -2
- package/types/report-request.d.ts +2 -2
- package/types/report-scheme.d.ts +18 -18
- package/types/request-filters.d.ts +10 -10
- package/types/request-pagination.d.ts +2 -2
- package/types/search-top-models.d.ts +4 -4
- package/types/site.d.ts +15 -15
- package/types/thumbs-urls.d.ts +1 -1
|
@@ -5,40 +5,40 @@ import { useRoute } from 'vue-router';
|
|
|
5
5
|
import type { IVideoCard, PaginatedResponse } from '../../types';
|
|
6
6
|
|
|
7
7
|
export const useFetchVideosByTag = async (apiMethod: (...args: any[]) => Promise<PaginatedResponse<IVideoCard>>) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
const route = useRoute();
|
|
9
|
+
const lang = useLang() as Language;
|
|
10
|
+
const mobile = !!useState<boolean>('isMobile').value;
|
|
11
|
+
const perPage = mobile ? 12 : 48;
|
|
12
|
+
const slug = useSlug('tag');
|
|
13
|
+
const filters = computed(() => useGetVideosFilterRequest(route, selectDurationItems, selectAddedItems));
|
|
14
|
+
const key = AsyncData.VideosByTag;
|
|
15
|
+
const stateKey = computed(() => `data-${key}-${slug.value}-${JSON.stringify(route.query)}-${lang}`);
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
17
|
+
const { data, status, error } = await useAsyncData<PaginatedResponse<IVideoCard>>(
|
|
18
|
+
stateKey.value,
|
|
19
|
+
() => useApiFetcher<PaginatedResponse<IVideoCard>>(
|
|
20
|
+
stateKey.value,
|
|
21
|
+
apiMethod,
|
|
22
|
+
{
|
|
23
|
+
page: Number(route.query['page']) || 1,
|
|
24
|
+
'per-page': perPage,
|
|
25
|
+
},
|
|
26
|
+
filters.value,
|
|
27
|
+
slug.value,
|
|
28
|
+
lang,
|
|
29
|
+
getSelectedQuery(route, sortItemsDefault) || '-popularity'
|
|
30
|
+
)(),
|
|
31
|
+
{
|
|
32
|
+
watch: [
|
|
33
|
+
() => {
|
|
34
|
+
if (route.query) {
|
|
35
|
+
const currentQuery = route.query;
|
|
36
|
+
return JSON.stringify(currentQuery);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
return { data, status, error };
|
|
44
44
|
};
|
|
@@ -4,38 +4,38 @@ import type { IVideoCard, PaginatedResponse } from '../../types';
|
|
|
4
4
|
import { useRoute } from 'vue-router';
|
|
5
5
|
|
|
6
6
|
export const useFetchVideosSearchByNiche = async (apiMethod: (...args: any[]) => Promise<PaginatedResponse<IVideoCard>>) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
const lang = useLang() as Language;
|
|
8
|
+
const mobile = !!useState<boolean>('isMobile').value;
|
|
9
|
+
const perPage = mobile ? 12 : 48;
|
|
10
|
+
const route = useRoute();
|
|
11
|
+
const slug = useSlug();
|
|
12
|
+
const key = AsyncData.VideosBySearch;
|
|
13
|
+
const stateKey = computed(() => `data-${key}-${slug.value}-${JSON.stringify(route.query)}-${lang}`);
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
15
|
+
const { data, status, error } = await useAsyncData<PaginatedResponse<IVideoCard>>(
|
|
16
|
+
stateKey.value,
|
|
17
|
+
() => useApiFetcher<PaginatedResponse<IVideoCard>>(
|
|
18
|
+
stateKey.value,
|
|
19
|
+
apiMethod,
|
|
20
|
+
{
|
|
21
|
+
page: Number(route.query['page']) || 1,
|
|
22
|
+
'per-page': perPage,
|
|
23
|
+
},
|
|
24
|
+
lang,
|
|
25
|
+
slug.value,
|
|
26
|
+
'-_score'
|
|
27
|
+
)(),
|
|
28
|
+
{
|
|
29
|
+
watch: [
|
|
30
|
+
() => {
|
|
31
|
+
if (route.query) {
|
|
32
|
+
const currentQuery = route.query;
|
|
33
|
+
return JSON.stringify(currentQuery);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
return { data, status, error };
|
|
41
41
|
};
|
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
* Возвращает функцию fetchData, вызывающую apiMethod и сохраняющую результат в useState по ключу key.
|
|
3
|
+
* В отличие от useApiFetcher, не кеширует данные — подходит для запросов, требующих свежего состояния.
|
|
4
|
+
* @param key - ключ для useState (null — не сохранять)
|
|
5
|
+
* @param apiMethod - асинхронная функция API
|
|
6
|
+
* @param apiArgs - аргументы для apiMethod
|
|
7
|
+
*/
|
|
8
8
|
export function useApiFetcherNoCache<T>(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
key: string | null,
|
|
10
|
+
apiMethod: (...args: any[]) => Promise<T>,
|
|
11
|
+
...apiArgs: any[]
|
|
12
12
|
) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
return async function fetchData() {
|
|
14
|
+
const hasKey = key?.trim();
|
|
15
|
+
const state = hasKey ? useState<T | null>(key!, () => null) : null;
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
try {
|
|
18
|
+
const result = await apiMethod(...apiArgs);
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
if (state) state.value = result;
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
return result;
|
|
23
|
+
} catch (err) {
|
|
24
|
+
throw createError({
|
|
25
|
+
statusCode: 500,
|
|
26
|
+
statusMessage: `Error fetching ${key}`,
|
|
27
|
+
message: err instanceof Error ? err.message : 'An unknown error occurred',
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
31
|
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
* Возвращает функцию fetchData, вызывающую apiMethod с переданными аргументами и оборачивающую ошибки в createError.
|
|
3
|
+
* @param key - ключ для идентификации запроса в сообщении об ошибке
|
|
4
|
+
* @param apiMethod - асинхронная функция API
|
|
5
|
+
* @param apiArgs - аргументы для apiMethod
|
|
6
|
+
*/
|
|
7
7
|
export function useApiFetcher<T>(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
key: string | null,
|
|
9
|
+
apiMethod: (...args: any[]) => Promise<T>,
|
|
10
|
+
...apiArgs: any[]
|
|
11
11
|
) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
return async function fetchData() {
|
|
13
|
+
try {
|
|
14
|
+
return await apiMethod(...apiArgs);
|
|
15
|
+
} catch (err) {
|
|
16
|
+
throw createError({
|
|
17
|
+
statusCode: 500,
|
|
18
|
+
statusMessage: `Error fetching ${key}`,
|
|
19
|
+
message: err instanceof Error ? err.message : 'An unknown error occurred',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
23
|
}
|
|
@@ -3,35 +3,35 @@ import type { ISelectItem } from '../types';
|
|
|
3
3
|
import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from 'vue-router';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
* Формирует объект параметров запроса фильтра видео из query текущего маршрута.
|
|
7
|
+
* @param route - текущий маршрут
|
|
8
|
+
* @param selectDurationItems - элементы выбора длительности
|
|
9
|
+
* @param selectAddedItems - элементы выбора даты добавления
|
|
10
|
+
*/
|
|
11
11
|
export function useGetVideosFilterRequest(route: RouteLocationNormalized | RouteLocationNormalizedLoaded, selectDurationItems: ISelectItem[], selectAddedItems: ISelectItem[]) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
// Распарсим categories из query, если есть
|
|
13
|
+
const rawCategories = route.query.categories
|
|
14
|
+
? (typeof route.query.categories === 'string'
|
|
15
|
+
? route.query.categories.split(',')
|
|
16
|
+
: route.query.categories.flatMap(cat => cat?.split(',')))
|
|
17
|
+
: [];
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
// Преобразуем из формата 'key_value' в просто 'value'
|
|
20
|
+
const parsedCategories = rawCategories
|
|
21
|
+
.map(cat => {
|
|
22
|
+
const parts = cat?.split('_');
|
|
23
|
+
if (parts && parts?.length > 1) {
|
|
24
|
+
return parts?.slice(1).join('_');
|
|
25
|
+
}
|
|
26
|
+
return cat;
|
|
27
|
+
});
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
const durationQuery = getMultipleQuery(route, selectDurationItems, 'min_duration', 'max_duration');
|
|
30
|
+
const addedQuery = getMultipleQuery(route, selectAddedItems, 'min_added', 'max_added');
|
|
31
|
+
return {
|
|
32
|
+
...(parsedCategories.length > 0 ? { categories: parsedCategories } : {}),
|
|
33
|
+
'categories_filter_use_and': true,
|
|
34
|
+
...durationQuery,
|
|
35
|
+
...addedQuery,
|
|
36
|
+
};
|
|
37
37
|
}
|
package/composables/use-lang.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/** Возвращает код текущей локали с учётом алиасов (zh → ch).
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
* Локаль берётся из глобального инстанса i18n (`useNuxtApp().$i18n`), а не из `useI18n()`,
|
|
3
|
+
* чтобы функцию можно было безопасно вызывать вне setup-контекста (watch/async-колбэки):
|
|
4
|
+
* `useI18n()` вне setup кидает MUST_BE_CALL_SETUP_TOP. */
|
|
5
5
|
export const useLang = () => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
const lang = useNuxtApp().$i18n.locale.value;
|
|
7
|
+
const anotherCode: Record<string, string> = {
|
|
8
|
+
zh: 'ch',
|
|
9
|
+
};
|
|
10
|
+
return anotherCode[lang] || lang;
|
|
11
11
|
};
|
package/composables/use-meta.ts
CHANGED
|
@@ -4,67 +4,67 @@ import { useRoute } from 'vue-router';
|
|
|
4
4
|
import type { IChipsItem } from '../types';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
* Генерирует реактивные meta (title, description) и h1 с учётом сортировки, страницы и i18n-ключей.
|
|
8
|
+
* @param t - функция перевода (i18n)
|
|
9
|
+
* @param page - ключ страницы для i18n (например 'videos', 'models')
|
|
10
|
+
* @param brandName - название бренда для подстановки в мета
|
|
11
|
+
* @param sortOptions - опции сортировки (если есть)
|
|
12
|
+
* @param text - основной текст (slug, имя и т.д.)
|
|
13
|
+
* @param secondText - второй подставляемый текст
|
|
14
|
+
* @param thirdText - третий подставляемый текст
|
|
15
|
+
* @param fourthText - четвёртый подставляемый текст
|
|
16
|
+
*/
|
|
17
17
|
export function useMeta(t: (key: string, params?: Record<string, unknown>) => string, page: string, brandName: string, sortOptions?: IChipsItem[], text?: Ref<string>, secondText?: Ref<string>, thirdText?: Ref<string>, fourthText?: Ref<string>) {
|
|
18
|
-
|
|
18
|
+
const route = useRoute();
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
const sortType = computed(() => {
|
|
21
|
+
const values = sortOptions?.map(item => item.value);
|
|
22
|
+
const queryValue = String(route?.query?.['sort']);
|
|
23
|
+
const DEFAULT_VALUE = 'trending';
|
|
24
|
+
return queryValue && values?.includes(queryValue) ? queryValue : DEFAULT_VALUE;
|
|
25
|
+
});
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
function getPath(key: string) {
|
|
28
|
+
const plainSlug = unref(text);
|
|
29
|
+
const secondTextValue = unref(secondText);
|
|
30
|
+
const thirdTextValue = unref(thirdText);
|
|
31
|
+
const fourTextValue = unref(fourthText);
|
|
32
|
+
const pageNumber = computed(() => route.query?.['page'] ? Number(route.query['page']) : 1);
|
|
33
|
+
const pageText = unref(pageNumber) === 1 ? null : ` ${t('page')} ${unref(pageNumber)}`;
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
35
|
+
return t(
|
|
36
|
+
`meta.${page}.${sortOptions && sortOptions.length > 0 ? `${sortType.value}.` : ''}${key}`,
|
|
37
|
+
{
|
|
38
|
+
text: plainSlug,
|
|
39
|
+
secondText: secondTextValue,
|
|
40
|
+
thirdText: thirdTextValue,
|
|
41
|
+
fourText: fourTextValue,
|
|
42
|
+
brandName: `| ${brandName}`, //черточка '|' нужна обязательно
|
|
43
|
+
page: pageText,
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
const metaTitle = computed(() => getPath('title'));
|
|
49
|
+
const h1 = computed(() => getPath('h1'));
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
title: metaTitle.value,
|
|
56
|
-
meta: [
|
|
57
|
-
{ name: 'description', content: description },
|
|
58
|
-
{ property: 'og:title', content: metaTitle.value },
|
|
59
|
-
{ property: 'og:description', content: description },
|
|
60
|
-
{ name: 'twitter:title', content: metaTitle.value },
|
|
61
|
-
{ name: 'twitter:description', content: description },
|
|
62
|
-
],
|
|
63
|
-
};
|
|
64
|
-
});
|
|
51
|
+
const meta = computed(() => {
|
|
52
|
+
const description = getPath('meta_description');
|
|
65
53
|
|
|
66
54
|
return {
|
|
67
|
-
|
|
68
|
-
|
|
55
|
+
title: metaTitle.value,
|
|
56
|
+
meta: [
|
|
57
|
+
{ name: 'description', content: description },
|
|
58
|
+
{ property: 'og:title', content: metaTitle.value },
|
|
59
|
+
{ property: 'og:description', content: description },
|
|
60
|
+
{ name: 'twitter:title', content: metaTitle.value },
|
|
61
|
+
{ name: 'twitter:description', content: description },
|
|
62
|
+
],
|
|
69
63
|
};
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
meta,
|
|
68
|
+
h1,
|
|
69
|
+
};
|
|
70
70
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
* Помечает страницу как noindex для поисковиков (ссылки при этом проходятся — follow).
|
|
3
|
+
* Для приватных/служебных страниц и результатов внутреннего поиска.
|
|
4
|
+
*/
|
|
5
5
|
export function useNoindex() {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
useHead({
|
|
7
|
+
meta: [
|
|
8
|
+
{ name: 'robots', content: 'noindex, follow' },
|
|
9
|
+
],
|
|
10
|
+
});
|
|
11
11
|
}
|
|
@@ -2,26 +2,26 @@ import type { IVideoCard } from '../types';
|
|
|
2
2
|
|
|
3
3
|
/** Управляет состоянием попапа жалобы на видео. */
|
|
4
4
|
export const useReportPopup = () => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const isReportPopupOpen = useState('report-popup-open', () => false);
|
|
6
|
+
const reportedVideoCard = useState<IVideoCard>('report-popup-card', () => ({} as IVideoCard));
|
|
7
|
+
const onBack = useState<(() => void) | null>('report-popup-on-back', () => null);
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
const openReportPopup = (card: IVideoCard, onBackCallback?: () => void) => {
|
|
10
|
+
isReportPopupOpen.value = true;
|
|
11
|
+
reportedVideoCard.value = card;
|
|
12
|
+
onBack.value = onBackCallback ?? null;
|
|
13
|
+
};
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
const closeReportPopup = () => {
|
|
16
|
+
isReportPopupOpen.value = false;
|
|
17
|
+
onBack.value = null;
|
|
18
|
+
};
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
return {
|
|
21
|
+
isReportPopupOpen,
|
|
22
|
+
openReportPopup,
|
|
23
|
+
closeReportPopup,
|
|
24
|
+
reportedVideoCard,
|
|
25
|
+
onBack,
|
|
26
|
+
};
|
|
27
27
|
};
|