itube-specs 0.0.720 → 0.0.722

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.
Files changed (51) hide show
  1. package/composables/use-antiadblock-domains.ts +1 -0
  2. package/composables/use-api-action.ts +5 -0
  3. package/composables/use-api-fetcher-no-cache.ts +7 -0
  4. package/composables/use-api-fetcher.ts +6 -0
  5. package/composables/use-auth-popup.ts +1 -0
  6. package/composables/use-favorites.ts +1 -0
  7. package/composables/use-filter-scheme.ts +5 -0
  8. package/composables/use-format-time-ago.ts +5 -0
  9. package/composables/use-generate-link.ts +1 -0
  10. package/composables/use-get-pure-route-name.ts +1 -0
  11. package/composables/use-get-videos-filter-request.ts +6 -0
  12. package/composables/use-global-scroll-lock.ts +1 -0
  13. package/composables/use-lang.ts +1 -0
  14. package/composables/use-meta.ts +11 -0
  15. package/composables/use-model-filter-chips.ts +6 -0
  16. package/composables/use-playlist-add.ts +1 -0
  17. package/composables/use-playlist-edit.ts +1 -0
  18. package/composables/use-recaptcha.ts +1 -0
  19. package/composables/use-report-popup.ts +1 -0
  20. package/composables/use-seo-links.ts +7 -0
  21. package/composables/use-slug.ts +4 -0
  22. package/composables/use-snackbar.ts +1 -0
  23. package/composables/use-units.ts +1 -0
  24. package/composables/use-user.ts +4 -0
  25. package/package.json +1 -1
  26. package/runtime/utils/cleaners/clean-category-card.ts +1 -0
  27. package/runtime/utils/cleaners/clean-category-info.ts +1 -0
  28. package/runtime/utils/cleaners/clean-channel-card.ts +1 -0
  29. package/runtime/utils/cleaners/clean-channel-info.ts +1 -0
  30. package/runtime/utils/cleaners/clean-mini-category-card.ts +1 -0
  31. package/runtime/utils/cleaners/clean-model-card.ts +1 -0
  32. package/runtime/utils/cleaners/clean-model-info.ts +1 -0
  33. package/runtime/utils/cleaners/clean-playlist-card.ts +1 -0
  34. package/runtime/utils/cleaners/clean-playlist-data.ts +1 -0
  35. package/runtime/utils/cleaners/clean-playlist-video.ts +1 -0
  36. package/runtime/utils/cleaners/clean-profile-data.ts +1 -0
  37. package/runtime/utils/cleaners/clean-user-playlists-card.ts +1 -0
  38. package/runtime/utils/cleaners/clean-video-card.ts +1 -0
  39. package/runtime/utils/cleaners/clean-video-data.ts +1 -0
  40. package/runtime/utils/converters/convert-categories-to-chips.ts +1 -1
  41. package/runtime/utils/converters/convert-categories-to-footer.ts +1 -1
  42. package/runtime/utils/converters/convert-channel-to-round-card.ts +1 -0
  43. package/runtime/utils/converters/convert-date-to-timestamp.ts +1 -7
  44. package/runtime/utils/converters/convert-model-card-to-chips.ts +1 -1
  45. package/runtime/utils/converters/convert-model-to-round-card.ts +1 -0
  46. package/runtime/utils/converters/convert-query-categories.ts +1 -3
  47. package/runtime/utils/converters/convert-snake-keys-to-camel.ts +1 -0
  48. package/runtime/utils/converters/convert-string-array-to-chips.ts +1 -0
  49. package/runtime/utils/converters/convert-string.ts +7 -0
  50. package/runtime/utils/converters/group-categories-by-first-letter.ts +7 -1
  51. package/runtime/utils/converters/group-objects-by-first-letter.ts +6 -1
@@ -1,3 +1,4 @@
1
+ /** Управляет состоянием антиадблок-доменов; предоставляет метод update для обновления данных через BFF. */
1
2
  export const useAntiadBlockDomains = () => {
2
3
  const state = useState('antiadblock-domains', () => ({
3
4
  data: null,
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Оборачивает API-метод в реактивные состояния loading, error, data.
3
+ * @param apiMethod - асинхронная функция API
4
+ * @param isGet - если true, результат сохраняется в data и опционально в useState по ключу key
5
+ */
1
6
  export function useApiAction<T extends any[], R>(
2
7
  apiMethod: (...args: T) => Promise<R>,
3
8
  isGet = false,
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Возвращает функцию fetchData, вызывающую apiMethod и сохраняющую результат в useState по ключу key.
3
+ * В отличие от useApiFetcher, не кеширует данные — подходит для запросов, требующих свежего состояния.
4
+ * @param key - ключ для useState (null — не сохранять)
5
+ * @param apiMethod - асинхронная функция API
6
+ * @param apiArgs - аргументы для apiMethod
7
+ */
1
8
  export function useApiFetcherNoCache<T>(
2
9
  key: string | null,
3
10
  apiMethod: (...args: any[]) => Promise<T>,
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Возвращает функцию fetchData, вызывающую apiMethod с переданными аргументами и оборачивающую ошибки в createError.
3
+ * @param key - ключ для идентификации запроса в сообщении об ошибке
4
+ * @param apiMethod - асинхронная функция API
5
+ * @param apiArgs - аргументы для apiMethod
6
+ */
1
7
  export function useApiFetcher<T>(
2
8
  key: string | null,
3
9
  apiMethod: (...args: any[]) => Promise<T>,
@@ -1,5 +1,6 @@
1
1
  import { EAuthSteps } from '../runtime';
2
2
 
3
+ /** Управляет состоянием попапа авторизации: открытие на нужном шаге EAuthSteps, закрытие, дополнительный текст. */
3
4
  export const useAuthPopup = () => {
4
5
  const isAuthPopupOpen = useState('auth-popup-open', () => false);
5
6
  const currentStep = useState<EAuthSteps>('auth-popup-step', () => EAuthSteps.Registration);
@@ -1,5 +1,6 @@
1
1
  export const FAVORITES_KEY = 'favorites';
2
2
 
3
+ /** Управляет состоянием плейлиста избранного: id, первое видео и вычисляемая ссылка на плейлист. */
3
4
  export const useFavorites = () => {
4
5
  const favoritesId = useState<string | null>('favorites-playlist-id', () => null);
5
6
  const favoritesFirstVideoId = useState<string | null>('favorites-first-video-id', () => null);
@@ -1,6 +1,11 @@
1
1
  import type { IFilterScheme, IGroupCategories } from '../types';
2
2
  import { convertString } from '../runtime';
3
3
 
4
+ /**
5
+ * Строит вычисляемую схему фильтров из группированных категорий.
6
+ * @param t - функция перевода (i18n)
7
+ * @param groupsCategories - массив групп категорий
8
+ */
4
9
  export const useFilterScheme = (t, groupsCategories: IGroupCategories[] | null) => {
5
10
  const getFilterSchemeCategories = (): IFilterScheme[] => {
6
11
  return groupsCategories?.map((item) => ({
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Форматирует Unix timestamp (в секундах) в относительную строку: «сегодня», «вчера», «3 дня назад» и т.д.
3
+ * @param t - функция перевода (i18n)
4
+ * @param time - Unix timestamp в секундах
5
+ */
1
6
  export const useFormatTimeAgo = (t, time: number) => {
2
7
  const pastDate = new Date(time * 1000);
3
8
  const now = new Date();
@@ -1,5 +1,6 @@
1
1
  import type { ELanguage, ENiche } from '~/runtime';
2
2
 
3
+ /** Возвращает generateLink — генерирует путь с учётом текущей ниши и локали. */
3
4
  export const useGenerateLink = () => {
4
5
  const niche = useState<string>('niche');
5
6
  const localePath = useLocalePath();
@@ -1,5 +1,6 @@
1
1
  import { useRoute } from 'vue-router';
2
2
 
3
+ /** Возвращает имя текущего маршрута без суффикса локали (___en, ___ru и т.д.). */
3
4
  export function useGetPureRouteName() {
4
5
  return String(useRoute()?.name)?.replace(/___[a-zA-Z-]+$/, '') || '';
5
6
  }
@@ -2,6 +2,12 @@ import { getMultipleQuery } from '../runtime';
2
2
  import type { ISelectItem } from '../types';
3
3
  import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from 'vue-router';
4
4
 
5
+ /**
6
+ * Формирует объект параметров запроса фильтра видео из query текущего маршрута.
7
+ * @param route - текущий маршрут
8
+ * @param selectDurationItems - элементы выбора длительности
9
+ * @param selectAddedItems - элементы выбора даты добавления
10
+ */
5
11
  export function useGetVideosFilterRequest(route: RouteLocationNormalized | RouteLocationNormalizedLoaded, selectDurationItems: ISelectItem[], selectAddedItems: ISelectItem[]) {
6
12
  // Распарсим categories из query, если есть
7
13
  const rawCategories = route.query.categories
@@ -16,6 +16,7 @@ function preventTouchScroll(e: TouchEvent) {
16
16
  }
17
17
  }
18
18
 
19
+ /** Управляет глобальной блокировкой прокрутки с счётчиком вложенности; корректно блокирует тач-скролл на мобильных. */
19
20
  export function useGlobalScrollLock() {
20
21
  const lockCount = useState('global-scroll-lock-count', () => 0);
21
22
 
@@ -1,3 +1,4 @@
1
+ /** Возвращает код текущей локали с учётом алиасов (zh → ch). */
1
2
  export const useLang = () => {
2
3
  const lang = useI18n().locale.value;
3
4
  const anotherCode: Record<string, string> = {
@@ -3,6 +3,17 @@ import type { Ref } from 'vue';
3
3
  import { useRoute } from 'vue-router';
4
4
  import type { IChipsItem } from '../types';
5
5
 
6
+ /**
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
+ */
6
17
  export function useMeta(t, page: string, brandName: string, sortOptions?: IChipsItem[], text?: Ref<string>, secondText?: Ref<string>, thirdText?: Ref<string>, fourthText?: Ref<string>) {
7
18
  const route = useRoute();
8
19
 
@@ -3,6 +3,12 @@ import type { LocationQuery } from '#vue-router'
3
3
  import { getMonth } from '../runtime'
4
4
  import type { Ref } from 'vue';
5
5
 
6
+ /**
7
+ * Формирует вычисляемый список чипсов из активных filter_* параметров в query маршрута.
8
+ * @param filters - список схем фильтров модели
9
+ * @param route - текущий маршрут с query
10
+ * @param t - функция перевода (i18n)
11
+ */
6
12
  export function useFilterChipsItems(
7
13
  filters: Ref<IModelFilter[]>,
8
14
  route: { query: LocationQuery },
@@ -2,6 +2,7 @@ import type { Ref } from 'vue';
2
2
  import type { IVideoData, IVideoCard } from '../types';
3
3
  import { EAuthSteps } from '../runtime';
4
4
 
5
+ /** Управляет состоянием попапа добавления видео в плейлист; при неавторизованном пользователе открывает попап авторизации. */
5
6
  export const usePlaylistAdd = () => {
6
7
  const videoCard = useState<IVideoCard | IVideoData | null>('playlist-add-card', () => null);
7
8
  const isPlaylistAdd = useState('playlist-add-open', () => false);
@@ -1,6 +1,7 @@
1
1
  import { EPlaylistStep } from '../runtime';
2
2
  import type { IVideoCard, IPlaylistCard } from '../types';
3
3
 
4
+ /** Управляет состоянием попапа редактирования плейлиста: шаги EPlaylistStep, выбранный плейлист, возврат назад. */
4
5
  export const usePlaylistEdit = () => {
5
6
  const deletedVideo = useState<IVideoCard | null | undefined>('playlist-edit-deleted-video', () => null);
6
7
  const selectedPlaylist = useState<IPlaylistCard | undefined>('playlist-edit-selected', () => undefined);
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { useRuntimeConfig } from '#imports';
4
4
 
5
+ /** Управляет загрузкой reCAPTCHA v3 и получением токенов; загружает скрипт лениво при первом вызове initRecaptcha. */
5
6
  export function useRecaptcha() {
6
7
  let recaptchaLoaded = false;
7
8
  let siteKey: string | null = null;
@@ -1,5 +1,6 @@
1
1
  import type { IVideoCard } from '../types';
2
2
 
3
+ /** Управляет состоянием попапа жалобы на видео. */
3
4
  export const useReportPopup = () => {
4
5
  const isReportPopupOpen = useState('report-popup-open', () => false);
5
6
  const reportedVideoCard = useState<IVideoCard>('report-popup-card', () => ({} as IVideoCard));
@@ -5,6 +5,13 @@ type I18nMock = {
5
5
 
6
6
  type LocalePathMock = (path: string, localeCode: string) => string;
7
7
 
8
+ /**
9
+ * Генерирует canonical URL и hreflang alternate-ссылки для всех локалей с сохранением допустимых query-параметров.
10
+ * @param baseDomain - базовый домен (например 'https://example.com')
11
+ * @param alonePage - если true, параметр sort исключается из URL
12
+ * @param i18n - объект i18n с locale и locales
13
+ * @param localePath - функция для генерации пути с локалью
14
+ */
8
15
  export const useSeoLinks = (baseDomain: string, alonePage: boolean = false, i18n: I18nMock, localePath: LocalePathMock) => {
9
16
  const route = useRoute();
10
17
 
@@ -1,6 +1,10 @@
1
1
  import { useRoute } from 'vue-router';
2
2
  import { convertString } from '../runtime';
3
3
 
4
+ /**
5
+ * Возвращает вычисляемый slug из параметров маршрута, декодированный через fromSlug.
6
+ * @param value - имя параметра маршрута (по умолчанию 'slug')
7
+ */
4
8
  export function useSlug(value = 'slug') {
5
9
  const route = useRoute();
6
10
 
@@ -5,6 +5,7 @@ const ERROR_TIME = 4000;
5
5
 
6
6
  let _timeoutClosure: null | ReturnType<typeof setTimeout> = null;
7
7
 
8
+ /** Управляет состоянием snackbar-уведомления: показ ошибки, сброс, тема, иконка и таймер. */
8
9
  export const useSnackbar = () => {
9
10
  const snackbarIcon = useState('snackbar-icon', () => 'check');
10
11
  const snackbarText = useState('snackbar-text', () => '');
@@ -1,5 +1,6 @@
1
1
  const imperialCountries = new Set(['us', 'lr', 'mm']);
2
2
 
3
+ /** Возвращает текущую систему мер (metric/imperial) и список скрытых параметров; сохраняет выбор в localStorage. */
3
4
  export function useUnits() {
4
5
  const clientCountryCode = useState<string>('clientCountryCode', () => '');
5
6
  const savedUnits = import.meta.client ? localStorage.getItem('units') : null;
@@ -18,6 +18,10 @@ function omit<T extends object, K extends keyof T>(obj: T, keys: K[]): Omit<T, K
18
18
  return result;
19
19
  }
20
20
 
21
+ /**
22
+ * Управляет авторизацией и профилем пользователя: регистрация, вход, выход, смена пароля/email, обновление профиля.
23
+ * @param apiService - сервис для API-запросов
24
+ */
21
25
  export const useUser = (apiService) => {
22
26
  const { snackbarText, snackbarTheme, showErrorSnack } = useSnackbar();
23
27
  const register = async (form: IRegistrateForm) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "itube-specs",
3
3
  "type": "module",
4
- "version": "0.0.720",
4
+ "version": "0.0.722",
5
5
  "main": "./nuxt.config.ts",
6
6
  "types": "./types/index.d.ts",
7
7
  "scripts": {
@@ -1,6 +1,7 @@
1
1
  import type { IRawCategoryCard, ICategoryCard } from '../../../types';
2
2
  import { ThumbSize } from '../../enums/thumb-size';
3
3
 
4
+ /** Нормализует сырую карточку категории к типу ICategoryCard. */
4
5
  export const cleanCategoryCard = (card: IRawCategoryCard): ICategoryCard => ({
5
6
  name: card.name || '',
6
7
  title: card.title || '',
@@ -2,6 +2,7 @@ import type { IRawCategoryInfo, ICardInfo } from '../../../types';
2
2
  import { ThumbSize } from '../../enums/thumb-size';
3
3
  import { convertCategoriesToChips } from '../converters/convert-categories-to-chips';
4
4
 
5
+ /** Нормализует сырые данные страницы категории к типу ICardInfo. */
5
6
  export const cleanCategoryInfo = (card: IRawCategoryInfo): ICardInfo => ({
6
7
  guid: card.guid || '',
7
8
  title: card.title || '',
@@ -1,6 +1,7 @@
1
1
  import type { IChannelCard, IRawChannelCard } from '../../../types';
2
2
  import { ThumbSize } from '../../enums/thumb-size';
3
3
 
4
+ /** Нормализует сырую карточку канала к типу IChannelCard. */
4
5
  export const cleanChannelCard = (card: IRawChannelCard): IChannelCard => ({
5
6
  guid: card.guid || '',
6
7
  name: card.name || '',
@@ -1,6 +1,7 @@
1
1
  import type { IRawChannelInfo, ICardInfo } from '../../../types';
2
2
  import { ThumbSize } from '../../enums/thumb-size';
3
3
 
4
+ /** Нормализует сырые данные страницы канала к типу ICardInfo. */
4
5
  export const cleanChannelInfo = (card: IRawChannelInfo): ICardInfo => ({
5
6
  guid: card.guid || '',
6
7
  title: card.name || '',
@@ -1,5 +1,6 @@
1
1
  import type { IRawCategoryCard, IMiniCategoryCard } from '../../../types';
2
2
 
3
+ /** Нормализует сырую карточку категории к компактному типу IMiniCategoryCard. */
3
4
  export const cleanMiniCategoryCard = (card: IRawCategoryCard): IMiniCategoryCard => ({
4
5
  name: card.name || '',
5
6
  title: card.title || '',
@@ -4,6 +4,7 @@ import { ThumbSize } from '../../enums/thumb-size';
4
4
  const parameterNames = ['height_cm', 'weight_kg'];
5
5
  const age = (card: IRawModelCard) => card.parameters.find(item => item.name === 'age')?.values[0].title;
6
6
 
7
+ /** Нормализует сырую карточку модели к типу IModelCard, включая параметры (возраст, рост, вес) и страну. */
7
8
  export const cleanModelCard = (card: IRawModelCard): IModelCard => ({
8
9
  title: card.title || '',
9
10
  videosCount: card.videos_count || 0,
@@ -1,6 +1,7 @@
1
1
  import type { IRawModelInfo, ICardInfo } from '../../../types';
2
2
  import { ThumbSize } from '../../enums/thumb-size';
3
3
 
4
+ /** Нормализует сырые данные страницы модели к типу ICardInfo. */
4
5
  export const cleanModelInfo = (card: IRawModelInfo): ICardInfo => ({
5
6
  title: card.title || '',
6
7
  description: card.description || '',
@@ -1,6 +1,7 @@
1
1
  import type { IRawPlaylistCard, IPlaylistCard } from '../../../types';
2
2
  import { ThumbSize } from '../../enums/thumb-size';
3
3
 
4
+ /** Нормализует сырую карточку плейлиста к типу IPlaylistCard. */
4
5
  export const cleanPlaylistCard = (card: IRawPlaylistCard): IPlaylistCard => ({
5
6
  created: card.created || 0,
6
7
  id: card.id || '',
@@ -1,5 +1,6 @@
1
1
  import type { IRawPlaylistData, IPlaylistData } from '../../../types';
2
2
 
3
+ /** Нормализует сырые данные плейлиста к типу IPlaylistData. */
3
4
  export const cleanPlaylistData = (card: IRawPlaylistData): IPlaylistData => ({
4
5
  updated: card.updated || 0,
5
6
  id: card.id || '',
@@ -1,6 +1,7 @@
1
1
  import type { IRawPlaylistVideo, IVideoCard } from '../../../types';
2
2
  import { ThumbSize } from '../../../runtime';
3
3
 
4
+ /** Нормализует сырое видео из плейлиста к типу IVideoCard. */
4
5
  export const cleanPlaylistVideo = (card: IRawPlaylistVideo): IVideoCard => ({
5
6
  guid: card.guid || '',
6
7
  duration: card.duration || 0,
@@ -1,5 +1,6 @@
1
1
  import type { IRawProfileData, IProfileData } from '../../../types';
2
2
 
3
+ /** Нормализует сырые данные профиля пользователя к типу IProfileData. */
3
4
  export const cleanProfileData = (data: IRawProfileData): IProfileData => ({
4
5
  username: data.username || '',
5
6
  email: data.email || '',
@@ -1,6 +1,7 @@
1
1
  import type { IRawPlaylistsUser, IPlaylistCard } from '../../../types';
2
2
  import { ThumbSize } from '../../enums/thumb-size';
3
3
 
4
+ /** Нормализует сырую карточку плейлиста пользователя к типу IPlaylistCard. */
4
5
  export const cleanUserPlaylistCard = (card: IRawPlaylistsUser): IPlaylistCard => ({
5
6
  created: card.created || 0,
6
7
  id: card.id || '',
@@ -1,6 +1,7 @@
1
1
  import type { IRawVideoCard, IVideoCard } from '../../../types';
2
2
  import { ThumbSize } from '../../enums/thumb-size';
3
3
 
4
+ /** Нормализует сырую карточку видео к типу IVideoCard. */
4
5
  export const cleanVideoCard = (card: IRawVideoCard): IVideoCard => ({
5
6
  guid: card.guid || '',
6
7
  quality: card.quality || '',
@@ -1,5 +1,6 @@
1
1
  import type { IRawVideoData, IVideoData } from '../../../types';
2
2
 
3
+ /** Нормализует сырые данные видео к типу IVideoData. */
3
4
  export const cleanVideoData = (data: IRawVideoData): IVideoData => ({
4
5
  guid: data.guid || '',
5
6
  md5: data.md5 || '',
@@ -1,6 +1,6 @@
1
1
  import type { IRawCategoryCard, IChipsItem } from '../../../types';
2
2
 
3
- /** Конвертирует обьекты категорий в чипсы */
3
+ /** Конвертирует массив категорий в чипсы IChipsItem для фильтров. */
4
4
  export function convertCategoriesToChips(
5
5
  items: Array<IRawCategoryCard>,
6
6
  prefix: string
@@ -1,6 +1,6 @@
1
1
  import type { IRawCategoryCard, ILinkItem } from '../../../types';
2
2
 
3
- /** Конвертирует обьекты категорий в футер категории */
3
+ /** Конвертирует массив категорий в ссылки ILinkItem для футера. */
4
4
  export function convertCategoriesToFooter(
5
5
  items: Array<IRawCategoryCard>,
6
6
  ): Array<ILinkItem> {
@@ -1,6 +1,7 @@
1
1
  import type { IChannelCard, IRoundCard } from '../../../types';
2
2
  import { convertString } from './convert-string';
3
3
 
4
+ /** Конвертирует карточку канала к формату IRoundCard для отображения в круглой карточке. */
4
5
  export function convertChannelToRoundCard(channel: IChannelCard): IRoundCard {
5
6
  return {
6
7
  title: channel.name,
@@ -1,6 +1,4 @@
1
- /**
2
- * Преобразует строку вида "дд.мм.гггг" в Unix timestamp (в секундах)
3
- */
1
+ /** Возвращает функции для конвертации дат: toUnix ("yyyy-MM-dd" → timestamp) и fromUnix (timestamp → "yyyy-MM-dd"). */
4
2
  export const convertDateToTimestamp = () => {
5
3
  const toUnix = (dateStr: string): number | null => {
6
4
  const [year, month, day] = dateStr.split('-').map(Number);
@@ -16,10 +14,6 @@ export const convertDateToTimestamp = () => {
16
14
  return Math.floor(date.getTime() / 1000);
17
15
  };
18
16
 
19
- /**
20
- * Преобразует Unix timestamp в строку "yyyy-MM-dd"
21
- * (то, что понимает input[type="date"])
22
- */
23
17
  const fromUnix = (timestamp: number): string => {
24
18
  const date = new Date(timestamp * 1000);
25
19
 
@@ -1,7 +1,7 @@
1
1
  import type { IRawModelCard, IChipsItem } from '../../../types';
2
2
  import { ThumbSize } from '../../enums/thumb-size';
3
3
 
4
- /** Конвертация карточки модели в chips */
4
+ /** Конвертирует массив карточек моделей в чипсы IChipsItem с иконкой превью. */
5
5
  export function convertModelCardToChips(
6
6
  items: Array<IRawModelCard>,
7
7
  ): Array<IChipsItem> {
@@ -1,6 +1,7 @@
1
1
  import type { IModelCard, IRoundCard } from '../../../types';
2
2
  import { convertString } from './convert-string';
3
3
 
4
+ /** Конвертирует карточку модели к формату IRoundCard для отображения в круглой карточке. */
4
5
  export function convertModelToRoundCard(model: IModelCard): IRoundCard {
5
6
  return {
6
7
  title: model.title,
@@ -1,7 +1,5 @@
1
1
  import type { RouteLocationNormalizedLoaded } from 'vue-router';
2
- /**
3
- * конвертирует список категорий из фильтра страниц с видео роликами из query в одну строку, все слова с заглавной буквы
4
- */
2
+ /** Конвертирует категории из query-параметра в читаемую строку с заглавными буквами (до 3 категорий). */
5
3
  export function convertQueryCategories(route: RouteLocationNormalizedLoaded) {
6
4
  const MAX_CATEGORIES = 3;
7
5
  return String(route.query[ 'categories' ])?.split(',').map(item => item.split('_')[ 1 ]).map(item => item?.charAt(0).toUpperCase() + item?.slice(1)).slice(0, MAX_CATEGORIES).join(', ');
@@ -2,6 +2,7 @@ function snakeToCamel(str: string): string {
2
2
  return str.replace(/_([a-z])/g, (_, char) => char.toUpperCase());
3
3
  }
4
4
 
5
+ /** Рекурсивно преобразует все ключи объекта из snake_case в camelCase. */
5
6
  export function convertSnakeKeysToCamel<T = any>(input: any): T {
6
7
  if (Array.isArray(input)) {
7
8
  return input.map(item => convertSnakeKeysToCamel(item)) as T;
@@ -1,5 +1,6 @@
1
1
  import type { IChipsItem } from '../../../types';
2
2
 
3
+ /** Конвертирует массив строк в чипсы IChipsItem; строку '#' заменяет на 'post'. */
3
4
  export function convertStringArrayToChips(array: string[], prefix: string, resetPath: string): IChipsItem[] {
4
5
  return array.map((item) => ({
5
6
  title: item.toLowerCase() === '#' ? 'post' : item,
@@ -1,6 +1,8 @@
1
1
  import type { IChipsItem } from '../../../types';
2
2
 
3
+ /** Утилиты для преобразования строк: slug, snake_case, kebab-case, chips, capitalize. */
3
4
  export const convertString = () => {
5
+ /** Преобразует строку в URL-slug: пробелы → дефисы, _ → ~, исходные дефисы сохраняются. */
4
6
  const toSlug = (input: string): string => {
5
7
  return input
6
8
  .toLowerCase()
@@ -10,6 +12,7 @@ export const convertString = () => {
10
12
  .replace(/\u0000/g, '_');
11
13
  };
12
14
 
15
+ /** Восстанавливает исходную строку из slug. */
13
16
  const fromSlug = (slug: string): string => {
14
17
  return slug
15
18
  .replace(/_/g, '\u0000') // временно убираем "_" (разделители)
@@ -18,6 +21,7 @@ export const convertString = () => {
18
21
  .replace(/~/g, '_'); // в конце восстанавливаем "_"
19
22
  };
20
23
 
24
+ /** Преобразует строку в snake_case. */
21
25
  const toSnakeCase = (slug: string): string => {
22
26
  return slug
23
27
  .replace(/([a-z])([A-Z])/g, '$1_$2')
@@ -26,6 +30,7 @@ export const convertString = () => {
26
30
  .toLowerCase();
27
31
  };
28
32
 
33
+ /** Преобразует строку в kebab-case. */
29
34
  const toKebabCase = (str: string): string => {
30
35
  return str
31
36
  .replace(/([a-z])([A-Z])/g, '$1-$2')
@@ -35,6 +40,7 @@ export const convertString = () => {
35
40
  .toLowerCase();
36
41
  };
37
42
 
43
+ /** Создаёт объект IChipsItem из строки и префикса. */
38
44
  const toChips = (string: string, prefix: string): IChipsItem => {
39
45
  return {
40
46
  title: string,
@@ -43,6 +49,7 @@ export const convertString = () => {
43
49
  }
44
50
  }
45
51
 
52
+ /** Делает первую букву каждого слова заглавной. */
46
53
  const toCapitalize = (string: string): string => {
47
54
  return string.split(' ').map(i => i.charAt(0).toUpperCase() + i.slice(1)).join(' ');
48
55
  }
@@ -1,6 +1,12 @@
1
1
  import type { IRawCategoryCard, ICategoryCard } from '../../../types';
2
2
 
3
- /** Метод для группировки мини категорий по первой букве свойства */
3
+ /**
4
+ * Группирует категории по первой букве указанного свойства, сортируя по локали; нелитерные значения — под ключом nonLetterKey.
5
+ * @param items - массив категорий
6
+ * @param prop - свойство для группировки (например 'title')
7
+ * @param locale - локаль для сортировки
8
+ * @param nonLetterKey - ключ для нелитерных значений (по умолчанию 'POST')
9
+ */
4
10
  export function groupCategoriesByFirstLetter(
5
11
  items: Array<IRawCategoryCard>,
6
12
  prop: string,
@@ -1,4 +1,9 @@
1
- /** Метод для группировки категорий по первой букве свойства */
1
+ /**
2
+ * Группирует объекты по первой букве указанного свойства; нелитерные значения — под ключом nonLetterKey.
3
+ * @param items - массив объектов
4
+ * @param prop - свойство для группировки
5
+ * @param nonLetterKey - ключ для нелитерных значений (по умолчанию 'POST')
6
+ */
2
7
  export function groupObjectsByFirstLetter<T>(
3
8
  items: Array<T>,
4
9
  prop: string,