itube-specs 0.0.959 → 0.0.961

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.
@@ -73,6 +73,7 @@ const currentImage = computed(() => {
73
73
  height: 48px;
74
74
  border-radius: $radius-full;
75
75
  object-fit: cover;
76
+ object-position: center 10%;
76
77
  }
77
78
 
78
79
  .card-model-mini__name {
@@ -103,15 +103,11 @@ function onImageError() {
103
103
  imageError.value = true;
104
104
  }
105
105
 
106
- /** В строку помещается только первый параметр из списка (тип парня) и возраст — остальные скрыты. */
107
- const visibleParameters = computed(() => {
108
- const isAge = (item: IModelCard['parameters'][number]) => item.title === 'age';
109
-
110
- return [
111
- props.card.parameters.find(item => !isAge(item)),
112
- props.card.parameters.find(isAge),
113
- ].filter(item => item !== undefined);
114
- });
106
+ /** В строке только телосложение и возраст: остальные параметры (этничность и прочее) в карточку не идут. */
107
+ const visibleParameters = computed(() => [
108
+ props.card.parameters.find(item => item.title === 'guy_type'),
109
+ props.card.parameters.find(item => item.title === 'age'),
110
+ ].filter(item => item !== undefined));
115
111
 
116
112
  function getValue(item: { title?: string; value?: string }) {
117
113
  if (item.title === 'age') {
@@ -118,7 +118,7 @@ $badge-inset--mobile: 1px;
118
118
  aspect-ratio: 1/1;
119
119
  border-radius: $radius-full;
120
120
  object-fit: cover;
121
- object-position: center 70%;
121
+ object-position: center 10%;
122
122
  border: 2px solid $card-round-border;
123
123
 
124
124
  @include from-br(sm) {
@@ -301,6 +301,7 @@ const socialItems = computed<ILinkItem[]>(() => {
301
301
  .info-main__img {
302
302
  border-radius: $radius-full;
303
303
  object-fit: cover;
304
+ object-position: center 10%;
304
305
  background-color: $info-img-bg;
305
306
  border: 2px solid $info-img-border;
306
307
 
@@ -215,7 +215,7 @@ const ageText = computed(() => {
215
215
  width: 64px;
216
216
  height: 64px;
217
217
  object-fit: cover;
218
- object-position: center 30%;
218
+ object-position: center 10%;
219
219
  border-radius: $radius-full;
220
220
 
221
221
  /* Кольцо рисуем тенью, а не бордером: при border-box рамка съедала бы 4px картинки */
@@ -159,7 +159,7 @@ const failedAvatars = ref<number[]>([]);
159
159
  width: 100%;
160
160
  height: 100%;
161
161
  object-fit: cover;
162
- object-position: center 30%;
162
+ object-position: center 10%;
163
163
  }
164
164
 
165
165
  .library-item__initials {
@@ -255,7 +255,7 @@ const name = computed(() => {
255
255
  width: var(--chips-height);
256
256
  height: var(--chips-height);
257
257
  object-fit: cover;
258
- object-position: center 70%;
258
+ object-position: center 10%;
259
259
  border-radius: 0 $radius-small $radius-small 0;
260
260
  }
261
261
 
@@ -203,17 +203,7 @@ const topChips = computed(() => {
203
203
 
204
204
  const topChipsStrings = computed(() => topChips.value?.map(item => item.value));
205
205
 
206
- const testModelImages = [
207
- '/img/models/Austin_Young.png',
208
- '/img/models/Dakota_Lovell.png',
209
- '/img/models/Devin_Franco.png',
210
- '/img/models/Falcon_Al.png',
211
- '/img/models/Jax_Thirio.png',
212
- '/img/models/LeGrand_Wolf.png',
213
- '/img/models/Oliver_Strelly.png',
214
- '/img/models/Roman_Todd.png',
215
- '/img/models/Sebastian _Kane.png',
216
- ];
206
+ const testModelImages = Array.from({ length: 16 }, (_, index) => `/img/models/portrait-${index + 1}.png`);
217
207
 
218
208
  function getModelChips(model: IVideoData['models'][number], index: number): IChipsItem {
219
209
  return {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "itube-specs",
3
3
  "type": "module",
4
- "version": "0.0.959",
4
+ "version": "0.0.961",
5
5
  "main": "./nuxt.config.ts",
6
6
  "types": "./types/index.d.ts",
7
7
  "scripts": {
@@ -47,17 +47,7 @@ const [
47
47
  useRouteQueryCategories(),
48
48
  ]);
49
49
 
50
- const testModelImages = [
51
- '/img/models/Austin_Young.png',
52
- '/img/models/Dakota_Lovell.png',
53
- '/img/models/Devin_Franco.png',
54
- '/img/models/Falcon_Al.png',
55
- '/img/models/Jax_Thirio.png',
56
- '/img/models/LeGrand_Wolf.png',
57
- '/img/models/Oliver_Strelly.png',
58
- '/img/models/Roman_Todd.png',
59
- '/img/models/Sebastian _Kane.png',
60
- ];
50
+ const testModelImages = Array.from({ length: 16 }, (_, index) => `/img/models/portrait-${index + 1}.png`);
61
51
 
62
52
  if (cardInfo.value) {
63
53
  cardInfo.value.img = testModelImages[Math.floor(Math.random() * testModelImages.length)];
@@ -34,17 +34,7 @@ const { t } = useI18n();
34
34
  const pageName = useRoute().name;
35
35
  const pagePureName = useGetPureRouteName();
36
36
 
37
- const testModelImages = [
38
- '/img/models/Austin_Young.png',
39
- '/img/models/Dakota_Lovell.png',
40
- '/img/models/Devin_Franco.png',
41
- '/img/models/Falcon_Al.png',
42
- '/img/models/Jax_Thirio.png',
43
- '/img/models/LeGrand_Wolf.png',
44
- '/img/models/Oliver_Strelly.png',
45
- '/img/models/Roman_Todd.png',
46
- '/img/models/Sebastian _Kane.png',
47
- ];
37
+ const testModelImages = Array.from({ length: 16 }, (_, index) => `/img/models/portrait-${index + 1}.png`);
48
38
 
49
39
  /** Портреты 3:4 — только под карточку модели, круглым аватарам топа они не подходят. */
50
40
  const testModelPortraits = Array.from({ length: 16 }, (_, index) => `/img/models/portrait-${index + 1}.png`);
@@ -8,7 +8,7 @@ const makeRaw = (overrides = {}) => ({
8
8
  primary_image_url: 'https://img.com/primary.jpg',
9
9
  guid: 'model-1',
10
10
  parameters: [
11
- { name: 'birthplace_country', values: [{ title: 'USA', name: 'usa' }] },
11
+ { name: 'nationality_iso_codes', values: [{ title: 'United States of America', name: 'US' }] },
12
12
  { name: 'guy_type', values: [{ title: 'Twink' }] },
13
13
  { name: 'ethnicity', values: [{ title: 'Asian' }] },
14
14
  { name: 'age', values: [{ title: '25' }] },
@@ -23,7 +23,7 @@ describe('cleanModelCard', () => {
23
23
  expect(result.videosCount).toBe(10);
24
24
  expect(result.thumbUrl).toBe('https://img.com/s.webp');
25
25
  expect(result.guid).toBe('model-1');
26
- expect(result.country).toEqual({ title: 'USA', name: 'usa' });
26
+ expect(result.country).toEqual({ title: 'United States of America', name: 'us' });
27
27
  });
28
28
 
29
29
  it('параметры: guy_type, ethnicity, age', () => {
@@ -38,7 +38,7 @@ describe('cleanModelCard', () => {
38
38
  it('без age → параметры без age', () => {
39
39
  const raw = makeRaw({
40
40
  parameters: [
41
- { name: 'birthplace_country', values: [{ title: 'USA', name: 'usa' }] },
41
+ { name: 'nationality_iso_codes', values: [{ title: 'United States of America', name: 'US' }] },
42
42
  { name: 'guy_type', values: [{ title: 'Twink' }] },
43
43
  { name: 'ethnicity', values: [{ title: 'Asian' }] },
44
44
  ],
@@ -2,7 +2,8 @@ import type { IRawModelCard, IModelCard, IModelParameter } from '../../../types'
2
2
  import { ThumbSize } from '../../constants/thumb-size';
3
3
 
4
4
  const parameterNames = ['guy_type', 'ethnicity'];
5
- const age = (card: IRawModelCard) => card.parameters?.find(item => item.name === 'age')?.values?.[0]?.title;
5
+ const firstValue = (card: IRawModelCard, name: string) => card.parameters?.find(item => item.name === name)?.values?.[0];
6
+ const age = (card: IRawModelCard) => firstValue(card, 'age')?.title;
6
7
 
7
8
  /** Нормализует сырую карточку модели к типу IModelCard, включая параметры (возраст, рост, вес) и страну. */
8
9
  export const cleanModelCard = (card: IRawModelCard): IModelCard => ({
@@ -11,9 +12,12 @@ export const cleanModelCard = (card: IRawModelCard): IModelCard => ({
11
12
  thumbUrl: card.video_thumb_urls?.webp?.[ThumbSize.Small] || '',
12
13
  primaryImageUrl: card.primary_image_url || '',
13
14
  guid: card.guid || '',
15
+ // Страна лежит в parameters под именем nationality_iso_codes: `name` — код ISO-2 (`us`),
16
+ // он же имя файла флага, `title` — читаемое название. Одноимённое поле верхнего уровня
17
+ // в ответе списка всегда null, параметра `birthplace_country` там нет вовсе.
14
18
  country: {
15
- title: card.parameters?.find(item => item.name === 'birthplace_country')?.values?.[0]?.title || '',
16
- name: card.parameters?.find(item => item.name === 'birthplace_country')?.values?.[0]?.name || '',
19
+ title: firstValue(card, 'nationality_iso_codes')?.title || '',
20
+ name: firstValue(card, 'nationality_iso_codes')?.name?.toLowerCase() || '',
17
21
  },
18
22
  parameters: [
19
23
  ...(card.parameters?.filter(item => parameterNames.includes(item.name) && item.values?.length).map((item: IModelParameter) => ({
@@ -68,21 +68,21 @@ function buildVideos(slug: string, offset: number, newCount: number): LibraryFol
68
68
 
69
69
  /** Порядок по числу новинок намеренно не совпадает с алфавитным — иначе обе сортировки дают одно и то же. */
70
70
  const MODELS = [
71
- { title: 'Dakota Lovell', image: 'Dakota_Lovell.png', country: { name: 'us', title: 'USA' }, age: 22, videosCount: 41, newCount: 3, guyType: 'Twink', bodyBuild: 'Slim', ethnicity: 'Caucasian', updatedAgo: 6 * HOUR, videoOffset: 3 },
72
- { title: 'Jax Thirio', image: 'Jax_Thirio.png', country: { name: 'ca', title: 'Canada' }, age: 38, videosCount: 17, newCount: 2, guyType: 'Daddy', bodyBuild: 'Muscular', ethnicity: 'Latino', updatedAgo: 2 * DAY, videoOffset: 9 },
73
- { title: 'Austin Young', image: 'Austin_Young.png', country: { name: 'us', title: 'USA' }, age: 24, videosCount: 75, newCount: 1, guyType: 'Twink', bodyBuild: 'Athletic', ethnicity: 'Caucasian', updatedAgo: 9 * DAY, videoOffset: 0 },
74
- { title: 'Devin Franco', image: 'Devin_Franco.png', country: { name: 'us', title: 'USA' }, age: 33, videosCount: 24, newCount: 0, guyType: 'Jock', bodyBuild: 'Muscular', ethnicity: 'Black', updatedAgo: 21 * DAY, videoOffset: 6 },
75
- { title: 'Dakota Lovell', image: 'Dakota_Lovell.png', country: { name: 'us', title: 'USA' }, age: 22, videosCount: 41, newCount: 3, guyType: 'Twink', bodyBuild: 'Slim', ethnicity: 'Caucasian', updatedAgo: 6 * HOUR, videoOffset: 3 },
76
- { title: 'Jax Thirio', image: 'Jax_Thirio.png', country: { name: 'ca', title: 'Canada' }, age: 38, videosCount: 17, newCount: 2, guyType: 'Daddy', bodyBuild: 'Muscular', ethnicity: 'Latino', updatedAgo: 2 * DAY, videoOffset: 9 },
77
- { title: 'Austin Young', image: 'Austin_Young.png', country: { name: 'us', title: 'USA' }, age: 24, videosCount: 75, newCount: 1, guyType: 'Twink', bodyBuild: 'Athletic', ethnicity: 'Caucasian', updatedAgo: 9 * DAY, videoOffset: 0 },
78
- { title: 'Devin Franco', image: 'Devin_Franco.png', country: { name: 'us', title: 'USA' }, age: 33, videosCount: 24, newCount: 0, guyType: 'Jock', bodyBuild: 'Muscular', ethnicity: 'Black', updatedAgo: 21 * DAY, videoOffset: 6 },
79
- { title: 'Dakota Lovell', image: 'Dakota_Lovell.png', country: { name: 'us', title: 'USA' }, age: 22, videosCount: 41, newCount: 3, guyType: 'Twink', bodyBuild: 'Slim', ethnicity: 'Caucasian', updatedAgo: 6 * HOUR, videoOffset: 3 },
80
- { title: 'Dakota Lovell', image: 'Dakota_Lovell.png', country: { name: 'us', title: 'USA' }, age: 22, videosCount: 41, newCount: 3, guyType: 'Twink', bodyBuild: 'Slim', ethnicity: 'Caucasian', updatedAgo: 6 * HOUR, videoOffset: 3 },
81
- { title: 'Dakota Lovell', image: 'Dakota_Lovell.png', country: { name: 'us', title: 'USA' }, age: 22, videosCount: 41, newCount: 3, guyType: 'Twink', bodyBuild: 'Slim', ethnicity: 'Caucasian', updatedAgo: 6 * HOUR, videoOffset: 3 },
82
- { title: 'Dakota Lovell', image: 'Dakota_Lovell.png', country: { name: 'us', title: 'USA' }, age: 22, videosCount: 41, newCount: 3, guyType: 'Twink', bodyBuild: 'Slim', ethnicity: 'Caucasian', updatedAgo: 6 * HOUR, videoOffset: 3 },
83
- { title: 'Jax Thirio', image: 'Jax_Thirio.png', country: { name: 'ca', title: 'Canada' }, age: 38, videosCount: 17, newCount: 2, guyType: 'Daddy', bodyBuild: 'Muscular', ethnicity: 'Latino', updatedAgo: 2 * DAY, videoOffset: 9 },
84
- { title: 'Austin Young', image: 'Austin_Young.png', country: { name: 'us', title: 'USA' }, age: 24, videosCount: 75, newCount: 1, guyType: 'Twink', bodyBuild: 'Athletic', ethnicity: 'Caucasian', updatedAgo: 9 * DAY, videoOffset: 0 },
85
- { title: 'Devin Franco', image: 'Devin_Franco.png', country: { name: 'us', title: 'USA' }, age: 33, videosCount: 24, newCount: 0, guyType: 'Jock', bodyBuild: 'Muscular', ethnicity: 'Black', updatedAgo: 21 * DAY, videoOffset: 6 },
71
+ { title: 'Dakota Lovell', image: 'portrait-1.png', country: { name: 'us', title: 'USA' }, age: 22, videosCount: 41, newCount: 3, guyType: 'Twink', bodyBuild: 'Slim', ethnicity: 'Caucasian', updatedAgo: 6 * HOUR, videoOffset: 3 },
72
+ { title: 'Jax Thirio', image: 'portrait-2.png', country: { name: 'ca', title: 'Canada' }, age: 38, videosCount: 17, newCount: 2, guyType: 'Daddy', bodyBuild: 'Muscular', ethnicity: 'Latino', updatedAgo: 2 * DAY, videoOffset: 9 },
73
+ { title: 'Austin Young', image: 'portrait-3.png', country: { name: 'us', title: 'USA' }, age: 24, videosCount: 75, newCount: 1, guyType: 'Twink', bodyBuild: 'Athletic', ethnicity: 'Caucasian', updatedAgo: 9 * DAY, videoOffset: 0 },
74
+ { title: 'Devin Franco', image: 'portrait-4.png', country: { name: 'us', title: 'USA' }, age: 33, videosCount: 24, newCount: 0, guyType: 'Jock', bodyBuild: 'Muscular', ethnicity: 'Black', updatedAgo: 21 * DAY, videoOffset: 6 },
75
+ { title: 'Dakota Lovell', image: 'portrait-1.png', country: { name: 'us', title: 'USA' }, age: 22, videosCount: 41, newCount: 3, guyType: 'Twink', bodyBuild: 'Slim', ethnicity: 'Caucasian', updatedAgo: 6 * HOUR, videoOffset: 3 },
76
+ { title: 'Jax Thirio', image: 'portrait-2.png', country: { name: 'ca', title: 'Canada' }, age: 38, videosCount: 17, newCount: 2, guyType: 'Daddy', bodyBuild: 'Muscular', ethnicity: 'Latino', updatedAgo: 2 * DAY, videoOffset: 9 },
77
+ { title: 'Austin Young', image: 'portrait-3.png', country: { name: 'us', title: 'USA' }, age: 24, videosCount: 75, newCount: 1, guyType: 'Twink', bodyBuild: 'Athletic', ethnicity: 'Caucasian', updatedAgo: 9 * DAY, videoOffset: 0 },
78
+ { title: 'Devin Franco', image: 'portrait-4.png', country: { name: 'us', title: 'USA' }, age: 33, videosCount: 24, newCount: 0, guyType: 'Jock', bodyBuild: 'Muscular', ethnicity: 'Black', updatedAgo: 21 * DAY, videoOffset: 6 },
79
+ { title: 'Dakota Lovell', image: 'portrait-1.png', country: { name: 'us', title: 'USA' }, age: 22, videosCount: 41, newCount: 3, guyType: 'Twink', bodyBuild: 'Slim', ethnicity: 'Caucasian', updatedAgo: 6 * HOUR, videoOffset: 3 },
80
+ { title: 'Dakota Lovell', image: 'portrait-1.png', country: { name: 'us', title: 'USA' }, age: 22, videosCount: 41, newCount: 3, guyType: 'Twink', bodyBuild: 'Slim', ethnicity: 'Caucasian', updatedAgo: 6 * HOUR, videoOffset: 3 },
81
+ { title: 'Dakota Lovell', image: 'portrait-1.png', country: { name: 'us', title: 'USA' }, age: 22, videosCount: 41, newCount: 3, guyType: 'Twink', bodyBuild: 'Slim', ethnicity: 'Caucasian', updatedAgo: 6 * HOUR, videoOffset: 3 },
82
+ { title: 'Dakota Lovell', image: 'portrait-1.png', country: { name: 'us', title: 'USA' }, age: 22, videosCount: 41, newCount: 3, guyType: 'Twink', bodyBuild: 'Slim', ethnicity: 'Caucasian', updatedAgo: 6 * HOUR, videoOffset: 3 },
83
+ { title: 'Jax Thirio', image: 'portrait-2.png', country: { name: 'ca', title: 'Canada' }, age: 38, videosCount: 17, newCount: 2, guyType: 'Daddy', bodyBuild: 'Muscular', ethnicity: 'Latino', updatedAgo: 2 * DAY, videoOffset: 9 },
84
+ { title: 'Austin Young', image: 'portrait-3.png', country: { name: 'us', title: 'USA' }, age: 24, videosCount: 75, newCount: 1, guyType: 'Twink', bodyBuild: 'Athletic', ethnicity: 'Caucasian', updatedAgo: 9 * DAY, videoOffset: 0 },
85
+ { title: 'Devin Franco', image: 'portrait-4.png', country: { name: 'us', title: 'USA' }, age: 33, videosCount: 24, newCount: 0, guyType: 'Jock', bodyBuild: 'Muscular', ethnicity: 'Black', updatedAgo: 21 * DAY, videoOffset: 6 },
86
86
  ];
87
87
 
88
88
  const CHANNELS = [