itube-specs 0.0.759 → 0.0.761

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 (61) hide show
  1. package/composables/use-meta.ts +15 -7
  2. package/composables/use-model-filter-chips.ts +50 -46
  3. package/package.json +1 -1
  4. package/components/auth/s-auth-icon.vue +0 -20
  5. package/components/auth/s-auth-login.vue +0 -120
  6. package/components/auth/s-auth-popup.vue +0 -69
  7. package/components/auth/s-auth-recovery.vue +0 -104
  8. package/components/auth/s-auth-register.vue +0 -176
  9. package/components/cards/s-video-mini-card.vue +0 -62
  10. package/components/grids/s-grid-categories.vue +0 -20
  11. package/components/grids/s-grid-channels.vue +0 -23
  12. package/components/grids/s-grid-models.vue +0 -25
  13. package/components/grids/s-grid-playlists.vue +0 -21
  14. package/components/grids/s-grid-videos.vue +0 -75
  15. package/components/page-components/s-breadcrumbs.vue +0 -44
  16. package/components/page-components/s-expand-row.vue +0 -113
  17. package/components/page-components/s-filter-button.vue +0 -41
  18. package/components/page-components/s-filter-chips.vue +0 -34
  19. package/components/page-components/s-filter-page.vue +0 -185
  20. package/components/page-components/s-filter-popup.vue +0 -155
  21. package/components/page-components/s-filter-slider.vue +0 -145
  22. package/components/page-components/s-filter-videos-chips.vue +0 -105
  23. package/components/page-components/s-filter.vue +0 -357
  24. package/components/page-components/s-footer-models.vue +0 -28
  25. package/components/page-components/s-info-grid.vue +0 -89
  26. package/components/page-components/s-info-socials.vue +0 -33
  27. package/components/page-components/s-like.vue +0 -121
  28. package/components/page-components/s-model-filters.vue +0 -235
  29. package/components/page-components/s-navigation-links.vue +0 -63
  30. package/components/page-components/s-pagination.vue +0 -214
  31. package/components/page-components/s-report.vue +0 -267
  32. package/components/page-components/s-section-title.vue +0 -35
  33. package/components/page-components/s-share.vue +0 -122
  34. package/components/playlist/s-playlist-add.vue +0 -299
  35. package/components/playlist/s-playlist-delete-video.vue +0 -79
  36. package/components/playlist/s-playlist-edit.vue +0 -215
  37. package/components/playlist/s-playlist-input.vue +0 -88
  38. package/components/playlist/s-playlist-like.vue.unused +0 -96
  39. package/components/playlist/s-playlist-new.vue.unused +0 -57
  40. package/components/playlist/s-playlist-private-toggle.vue +0 -20
  41. package/components/ui/s-avatar.vue +0 -33
  42. package/components/ui/s-button.vue +0 -51
  43. package/components/ui/s-checkbox.vue +0 -57
  44. package/components/ui/s-chips.vue +0 -142
  45. package/components/ui/s-count.vue +0 -17
  46. package/components/ui/s-dropdown.vue +0 -152
  47. package/components/ui/s-icon.vue +0 -19
  48. package/components/ui/s-img.vue +0 -59
  49. package/components/ui/s-input.vue +0 -181
  50. package/components/ui/s-label.vue +0 -20
  51. package/components/ui/s-link.vue +0 -46
  52. package/components/ui/s-notification.vue +0 -72
  53. package/components/ui/s-popup.vue +0 -119
  54. package/components/ui/s-radio.vue +0 -56
  55. package/components/ui/s-select.vue +0 -105
  56. package/components/ui/s-slider.vue +0 -67
  57. package/components/ui/s-snackbar.vue +0 -27
  58. package/components/ui/s-timestamp.vue +0 -59
  59. package/components/ui/s-toggle.vue +0 -30
  60. package/components/ui/s-tooltip.vue +0 -57
  61. package/components/video/s-video-autoplay.vue +0 -29
@@ -1,62 +0,0 @@
1
- <template>
2
- <component
3
- :is="component"
4
- class="s-video-mini-card"
5
- :title="card.title"
6
- :to="link ? generateLink(`/playlists/${prefix}/${card.id}`) : null"
7
- >
8
- <SImg
9
- class="s-video-mini-card__img"
10
- sizes="140px"
11
- :src="currentPoster"
12
- width="1600"
13
- height="900"
14
- :alt="card.title"
15
- @error="onPosterError"
16
- />
17
- <div class="s-video-mini-card__wrapper">
18
- <p class="s-video-mini-card__title _truncate">{{ card.title }}</p>
19
- <span v-if="card.channelName" class="s-video-mini-card__channel _truncate">{{ card.channelName }}</span>
20
- <span class="s-video-mini-card__duration">
21
- <SIcon name="time" size="12" />
22
- {{ duration }}</span>
23
- </div>
24
- </component>
25
- </template>
26
-
27
- <script setup lang="ts">
28
- import type { IVideoCard } from '../../types';
29
- import { getDuration, ThumbSize } from '../../runtime';
30
-
31
- const props = defineProps<{
32
- card: IVideoCard
33
- link?: boolean
34
- prefix?: string
35
- }>()
36
-
37
- const posterError = ref(false)
38
-
39
- const duration = computed(() => {
40
- return getDuration(props.card.duration)
41
- })
42
-
43
- const component = computed(() => {
44
- if (props.link) {
45
- return resolveComponent('NuxtLink');
46
- }
47
- return 'div';
48
- })
49
-
50
- const { generateLink } = useGenerateLink();
51
-
52
- const posterPlaceholder = '/img/placeholder.webp'
53
-
54
- const currentPoster = computed(() => {
55
- if (posterError.value) return posterPlaceholder
56
- return props.card.thumbUrls?.webp?.[ThumbSize.Small] || posterPlaceholder
57
- })
58
-
59
- function onPosterError() {
60
- posterError.value = true
61
- }
62
- </script>
@@ -1,20 +0,0 @@
1
- <template>
2
- <div class="s-grid-categories">
3
- <FCategoryCard
4
- v-for="(item, index) in categories"
5
- :key="item.guid"
6
- :card="item"
7
- :priority="priority && index === 0"
8
- />
9
- <slot/>
10
- </div>
11
- </template>
12
-
13
- <script setup lang="ts">
14
- import type { ICategoryCard } from '../../types';
15
-
16
- defineProps<{
17
- categories: Array<ICategoryCard>,
18
- priority?: boolean
19
- }>()
20
- </script>
@@ -1,23 +0,0 @@
1
- <template>
2
- <div
3
- id="anchor"
4
- class="s-grid-channels"
5
- >
6
- <FChannelCard
7
- v-for="(item, index) in items"
8
- :key="item.guid"
9
- class="s-grid-channels__card"
10
- :card="item"
11
- :priority="priority && index === 0"
12
- />
13
- </div>
14
- </template>
15
-
16
- <script setup lang="ts">
17
- import type { IChannelCard } from '../../types';
18
-
19
- defineProps<{
20
- items: IChannelCard[]
21
- priority?: boolean
22
- }>()
23
- </script>
@@ -1,25 +0,0 @@
1
- <template>
2
- <div
3
- class="s-grid-models"
4
- :class="{'--footer': footer}"
5
- >
6
- <FModelCard
7
- v-for="(item, index) in items"
8
- :key="`model-card-${item.guid}`"
9
- class="s-grid-models__item"
10
- :card="item"
11
- :loading="index > 5 ? 'lazy' : 'eager'"
12
- :priority="priority && index === 0"
13
- />
14
- </div>
15
- </template>
16
-
17
- <script setup lang="ts">
18
- import type { IModelCard } from '../../types';
19
-
20
- defineProps<{
21
- items: IModelCard[]
22
- footer?: boolean
23
- priority?: boolean
24
- }>()
25
- </script>
@@ -1,21 +0,0 @@
1
- <template>
2
- <div class="s-grid-playlists">
3
- <FPlaylistCard
4
- v-for="(item, index) in items"
5
- :key="`user-playlist-${index}`"
6
- :card="item"
7
- :top-playlists="topPlaylists"
8
- :priority="priority && index === 0"
9
- />
10
- </div>
11
- </template>
12
-
13
- <script setup lang="ts">
14
- import type { IPlaylistCard } from '../../types';
15
-
16
- defineProps<{
17
- items: IPlaylistCard[]
18
- topPlaylists?: boolean
19
- priority?: boolean
20
- }>()
21
- </script>
@@ -1,75 +0,0 @@
1
- <template>
2
- <div
3
- class="s-grid-videos"
4
- :class="[
5
- {'--first-hidden': hideFirstRow},
6
- ]"
7
- >
8
- <slot name="grid-start"/>
9
- <FVideoCard
10
- v-for="(item, index) in eagerItems"
11
- :key="`video-${item.guid}`"
12
- class="s-grid-videos__card"
13
- :card="item"
14
- :priority="priority && index < eagerCount"
15
- :loading="!related ? 'eager' : 'lazy'"
16
- :top-chips="topChips"
17
- :playlist-id="playlistId"
18
- :playlist="playlist"
19
- />
20
- <slot/>
21
- <NuxtLazyHydrate when-idle v-if="idleItems.length > 0" :key="`idle-${route.fullPath}`">
22
- <div class="s-grid-videos__idle">
23
- <FVideoCard
24
- v-for="item in idleItems"
25
- :key="`video-idle-${item.guid}`"
26
- class="s-grid-videos__card"
27
- :card="item"
28
- loading="lazy"
29
- :top-chips="topChips"
30
- :playlist-id="playlistId"
31
- :playlist="playlist"
32
- />
33
- </div>
34
- </NuxtLazyHydrate>
35
- <NuxtLazyHydrate when-visible v-if="lazyItems.length > 0" :key="`lazy-${route.fullPath}`">
36
- <div class="s-grid-videos__lazy">
37
- <FVideoCard
38
- v-for="item in lazyItems"
39
- :key="`video-lazy-${item.guid}`"
40
- class="s-grid-videos__card"
41
- :card="item"
42
- loading="lazy"
43
- :top-chips="topChips"
44
- :playlist-id="playlistId"
45
- :playlist="playlist"
46
- />
47
- </div>
48
- </NuxtLazyHydrate>
49
- <slot name="grid-end"/>
50
- </div>
51
- </template>
52
-
53
- <script setup lang="ts">
54
- import type { IVideoCard } from '../../types';
55
-
56
- const IDLE_COUNT = 4;
57
-
58
- const props = defineProps<{
59
- items: Array<IVideoCard>
60
- hideFirstRow?: boolean
61
- priority?: boolean
62
- related?: boolean
63
- playlist?: boolean
64
- playlistId?: string
65
- topChips?: string[]
66
- }>();
67
-
68
- const route = useRoute();
69
- const isMobile = useState<boolean>('isMobile');
70
- const eagerCount = computed(() => isMobile.value ? 4 : 12);
71
-
72
- const eagerItems = computed(() => props.items.slice(0, eagerCount.value));
73
- const idleItems = computed(() => props.items.slice(eagerCount.value, eagerCount.value + IDLE_COUNT));
74
- const lazyItems = computed(() => props.items.slice(eagerCount.value + IDLE_COUNT));
75
- </script>
@@ -1,44 +0,0 @@
1
- <template>
2
- <nav class="s-breadcrumbs" aria-label="Breadcrumb" role="navigation" itemscope itemtype="https://schema.org/BreadcrumbList">
3
- <ol>
4
- <li
5
- v-for="(item, index) in resultItems"
6
- :key="`breadcrumb-${index}`"
7
- itemscope
8
- itemprop="itemListElement"
9
- itemtype="https://schema.org/ListItem"
10
- >
11
- <NuxtLink
12
- :to="generateLink(item.to || '/')"
13
- class="s-breadcrumbs__item"
14
- itemprop="item"
15
- >
16
- <span itemprop="name" v-html="item.name" />
17
- </NuxtLink>
18
- <meta itemprop="position" :content="String(index + 1)" >
19
- </li>
20
- <li
21
- itemscope
22
- itemprop="itemListElement"
23
- itemtype="https://schema.org/ListItem"
24
- >
25
- <span class="s-breadcrumbs__item" aria-current="page" itemprop="name" v-html="items[items.length - 1].name" />
26
- <meta itemprop="position" :content="String(items.length)" >
27
- </li>
28
- </ol>
29
- </nav>
30
- </template>
31
-
32
- <script setup lang="ts">
33
- import type { IBreadcrumbItem } from '../../types';
34
-
35
- const props = defineProps<{
36
- items: IBreadcrumbItem[]
37
- }>()
38
-
39
- const { generateLink } = useGenerateLink();
40
-
41
- const resultItems = computed(() => {
42
- return props.items.slice(0, props.items.length - 1)
43
- })
44
- </script>
@@ -1,113 +0,0 @@
1
- <template>
2
- <div
3
- ref="containerRef"
4
- class="s-expand-row"
5
- :class="[
6
- { '--expand-show': isExpandOpened },
7
- { '--alphabet': alphabet },
8
- { '--mobile-expand': mobileExpand },
9
- ]"
10
- >
11
- <div
12
- class="s-expand-row__wrapper"
13
- :class="[{ '--more-show': isElementsOverflow }]"
14
- >
15
- <slot name="prepend">
16
- <span v-if="preText" class="s-expand-row__pre-text">{{ preText }}</span>
17
- </slot>
18
- <slot>
19
- <SChips
20
- v-for="item in itemsResult"
21
- :key="item.title"
22
- :item="item"
23
- :alphabet="alphabet"
24
- is-link
25
- :mini="mini"
26
- />
27
- </slot>
28
- <div
29
- v-if="!hideMore"
30
- v-show="isElementsOverflow"
31
- class="s-expand-row__more-wrapper"
32
- :class="{'--small': mini}"
33
- >
34
- <SChips
35
- class="s-expand-row__button --more"
36
- :item="{
37
- title: moreButtonName,
38
- icon: isExpandOpened ? 'minus' : 'plus',
39
- }"
40
- :mini="mini"
41
- @click="onMoreClick"
42
- />
43
- </div>
44
- </div>
45
- </div>
46
- </template>
47
-
48
- <script setup lang="ts">
49
- import type { IChipsItem } from '../../types';
50
-
51
- const props = withDefaults(
52
- defineProps<{
53
- items?: IChipsItem[];
54
- alphabet?: boolean;
55
- hideMore?: boolean;
56
- mini?: boolean;
57
- mobileExpand?: boolean;
58
- maximumButtons?: number;
59
- preText?: string;
60
- }>(), {
61
- maximumButtons: 20, // вычислено на глаз, приблизительно
62
- }
63
- );
64
-
65
- const { t } = useI18n()
66
-
67
- const emit = defineEmits<{
68
- (eventName: 'more', eventValue: boolean): void
69
- }>()
70
-
71
- const containerRef = ref();
72
-
73
- const isExpandOpened = ref(false);
74
-
75
- const itemsResult = computed(() => {
76
- return props.items?.slice(
77
- 0,
78
- !props.alphabet && !isExpandOpened.value
79
- ? props.maximumButtons
80
- : props.items.length,
81
- );
82
- });
83
-
84
- const moreButtonName = computed(() => isExpandOpened.value ? t('less') : t('more'));
85
-
86
- const isElementsOverflow = ref(false);
87
-
88
- function checkIsElementOverflow() {
89
- isElementsOverflow.value = !!(
90
- containerRef.value &&
91
- containerRef.value.scrollHeight > containerRef.value.clientHeight
92
- );
93
- }
94
-
95
- function onMoreClick() {
96
- isExpandOpened.value = !isExpandOpened.value
97
- emit('more', isExpandOpened.value)
98
- }
99
-
100
- onMounted(() => {
101
- requestAnimationFrame(() => checkIsElementOverflow());
102
- });
103
-
104
- let checkTimer: ReturnType<typeof setTimeout> | null = null;
105
-
106
- watch(() => useRoute().query, () => {
107
- checkTimer = setTimeout(() => checkIsElementOverflow(), 100);
108
- });
109
-
110
- onBeforeUnmount(() => {
111
- if (checkTimer) clearTimeout(checkTimer);
112
- });
113
- </script>
@@ -1,41 +0,0 @@
1
- <template>
2
- <SButton
3
- class="s-filter-button"
4
- :size="size"
5
- :theme="theme"
6
- aria-label="Filter"
7
- :title="t('filter')"
8
- @click="emit('update:modelValue', true)"
9
- >
10
- <SIcon name="adjustments-horizontal" size="16"/>
11
- <span class="_from-sm"
12
- >{{ t('filter') }}
13
- </span>
14
- <span
15
- v-if="count > 0"
16
- class="s-filter-button__count"
17
- >{{ mobileCount }}</span>
18
- </SButton>
19
- </template>
20
-
21
- <script setup lang="ts">
22
- import type { ButtonSizes, ButtonThemes } from '../../types';
23
-
24
- const props = defineProps<{
25
- count: number
26
- modelValue: boolean
27
- size?: ButtonSizes
28
- theme?: ButtonThemes
29
- }>()
30
-
31
- const emit = defineEmits<{
32
- (eventName: 'update:modelValue', value: boolean): void
33
- }>()
34
-
35
- const { t } = useI18n()
36
-
37
- const mobileCount = computed(() => props.count > 9 ? '9+' : props.count);
38
- </script>
39
-
40
- <style scoped lang="scss">
41
- </style>
@@ -1,34 +0,0 @@
1
- <template>
2
- <SExpandRow v-if="items.length > 0">
3
- <template #prepend>
4
- <slot/>
5
- </template>
6
- <SChips
7
- v-for="(item, index) in items"
8
- class="s-filter-chips"
9
- with-close
10
- :index="`s-filter-page-chips${index}`"
11
- :item="item"
12
- @click="onChipsClick(item)"
13
- />
14
- </SExpandRow>
15
- </template>
16
-
17
- <script setup lang="ts">
18
- import type { IChipsItem } from '../../types';
19
-
20
- defineProps<{
21
- items: IChipsItem[]
22
- }>();
23
-
24
- const emit = defineEmits<{
25
- (eventName: 'click', eventValue: IChipsItem): void
26
- }>()
27
-
28
- function onChipsClick(item: IChipsItem) {
29
- emit('click', item)
30
- }
31
- </script>
32
-
33
- <style scoped lang="scss">
34
- </style>
@@ -1,185 +0,0 @@
1
- <template>
2
- <div class="s-filter-page">
3
- <div class="s-filter-page__items-wrapper">
4
- <h2
5
- v-if="title"
6
- class="s-filter-page__title"
7
- >{{ title }}
8
- </h2>
9
- <div
10
- v-for="(group, index) in groups"
11
- :key="`filter-group-${index}`"
12
- class="s-filter-page__group"
13
- :class="{'--short': group.name === 'tags'}"
14
- >
15
- <div
16
- v-if="filters.length > 0"
17
- class="s-filter-page__group-header"
18
- >
19
- <span class="s-filter-page__group-title">
20
- {{ group?.title }}
21
- </span>
22
- <FSegmentedControl
23
- v-if="group?.name === 'physical'"
24
- :items="unitItems"
25
- :model-value="units"
26
- small
27
- @update:model-value="units = $event"
28
- />
29
- </div>
30
- <div
31
- v-if="getGroupSliders(group?.name).length > 1"
32
- class="s-filter-page__sliders"
33
- :style="{ '--slider-count': getGroupSliders(group?.name).length }"
34
- >
35
- <SFilterSlider
36
- v-for="(item, subIndex) in getGroupSliders(group?.name)"
37
- :key="`slider-${subIndex}`"
38
- :item="item"
39
- :group-name="item.group.name"
40
- :index="subIndex"
41
- />
42
- </div>
43
- <div class="s-filter-page__items">
44
- <template v-for="(item, subIndex) in filters">
45
- <SFilterSlider
46
- v-if="(item.kind === 'range') && (item.group.name === group?.name) && !hiddenByUnits.has(item.name) && getGroupSliders(group?.name).length === 1"
47
- class="s-filter-page__slider"
48
- :item="item"
49
- :group-name="item.group.name"
50
- :index="subIndex"
51
- />
52
- <SSelect
53
- v-if="(item.kind === 'select') && (item.group.name === group?.name) && !hiddenByUnits.has(item.name)"
54
- class="s-filter-page__select"
55
- :key="`model-filter-select-${subIndex}`"
56
- :name="item.name"
57
- :model-value="getValue(item.name)"
58
- :items="selectItems(item)"
59
- size="s"
60
- :active="isActiveSelect(item.name)"
61
- :label="item.title"
62
- @update:model-value="val => updateFilter(item.name, val)"
63
- />
64
- <FSegmentedControl
65
- v-if="(item.kind === 'radio') && (item.group.name === group?.name)"
66
- class="s-filter-page__radio"
67
- :items="getRadioItems(item.options)"
68
- :title="item.title"
69
- :model-value="getValue(item.name)"
70
- @update:model-value="val => updateFilter(item.name, val)"
71
- />
72
- <FFilterByChips
73
- v-if="(item.kind === 'chips') && (item.group.name === group?.name)"
74
- class="f-filters-main__chips"
75
- :items="item.options"
76
- :title="item.title"
77
- :filter-name="item.name"
78
- />
79
- </template>
80
- </div>
81
- </div>
82
- </div>
83
- </div>
84
- </template>
85
-
86
- <script setup lang="ts">
87
- import type { IModelFilter, IModelFilterOptions } from '../../types';
88
-
89
- import { useRoute, useRouter } from 'vue-router';
90
-
91
- const props = defineProps<{
92
- filters: IModelFilter[]
93
- count: number
94
- title?: string
95
- }>();
96
-
97
- const route = useRoute();
98
- const router = useRouter();
99
-
100
- const { t } = useI18n();
101
-
102
- const { units, hiddenByUnits } = useUnits();
103
-
104
- watch(units, () => {
105
- const query = { ...route.query };
106
- const unitFields = ['height_cm', 'height_in', 'weight_kg', 'weight_lb'];
107
- for (const field of unitFields) {
108
- delete query[`filter_${field}_from`];
109
- delete query[`filter_${field}_to`];
110
- }
111
- router.replace({ query });
112
- });
113
-
114
- const unitItems = computed(() => [
115
- { name: 'imperial', title: t('units_imperial'), quantity: 0 },
116
- { name: 'metric', title: t('units_metric'), quantity: 0 },
117
- ]);
118
-
119
- const groups = computed(() => {
120
- const uniqueNames = [...new Set(props.filters.map(item => item.group.title))];
121
- return uniqueNames.map(name => {
122
- return props.filters.find(filter => filter.group.title === name)?.group;
123
- }).sort((a, b) => a?.order - b?.order)
124
- });
125
-
126
- function getGroupSliders(groupName: string) {
127
- return props.filters.filter(
128
- (item) => item.kind === 'range' && item.group.name === groupName && !hiddenByUnits.value.has(item.name)
129
- );
130
- }
131
-
132
- function selectItems(item: IModelFilter) {
133
- return [
134
- ...item.options.map(item => ({
135
- value: item.name,
136
- title: `${item.title} (${item.quantity})`,
137
- }))
138
- ]
139
- }
140
-
141
- function updateFilter(name: string, val: any) {
142
- const query = { ...route.query };
143
-
144
- if (!val || val === 'all') {
145
- delete query[ `filter_${name}` ];
146
- } else {
147
- query[ `filter_${name}` ] = val;
148
- }
149
-
150
- router.replace({ query });
151
- }
152
-
153
- function isActiveSelect(name: string) {
154
- const baseName = name.replace(/_(from|to)$/, '');
155
- return Object.keys(route.query).some(key => key.startsWith(`filter_${baseName}`));
156
- }
157
-
158
- function getValue(name: string) {
159
- const value = route.query[ `filter_${name}` ];
160
- if (value) {
161
- return value;
162
- }
163
- const filter = props.filters.find(f => f.name === name);
164
- if (filter && filter.options.length > 0) {
165
- return filter.options[ 0 ].name;
166
- }
167
- return null;
168
- }
169
-
170
- function getRadioItems(items: IModelFilterOptions[]) {
171
- const filteredItems = items.filter((item) => item.name !== 'unspecified');
172
- const order = ['all', 'yes'];
173
- return filteredItems.sort((a, b) => {
174
- const aIndex = order.indexOf(a.name);
175
- const bIndex = order.indexOf(b.name);
176
- if (aIndex !== -1 && bIndex !== -1) return aIndex - bIndex;
177
- if (aIndex !== -1) return -1;
178
- if (bIndex !== -1) return 1;
179
- return 0;
180
- });
181
- }
182
- </script>
183
-
184
- <style scoped lang="scss">
185
- </style>