itube-specs 0.0.892 → 0.0.895
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/assets/scss/themes/dark/_theme.scss +18 -1
- package/assets/scss/themes/light/_theme.scss +18 -1
- package/components/card/dropdown/trigger.vue +9 -5
- package/components/card/history.vue +4 -3
- package/components/card/video/index.vue +21 -8
- package/components/library/feed.vue +340 -0
- package/components/library/follows.vue +147 -0
- package/components/ui/expand-row.vue +21 -2
- package/components/ui/video-preview.vue +62 -0
- package/package.json +1 -1
- package/pages/library/categories.vue +61 -0
- package/pages/library/channels.vue +62 -0
- package/pages/library/index.vue +366 -0
- package/pages/library/models.vue +63 -0
- package/pages/library.vue +1 -361
- package/stubs/history.ts +17 -14
- package/stubs/library-follows.ts +135 -0
- package/stubs/videos.ts +29 -0
- package/types/index.d.ts +1 -0
- package/types/library-feed.d.ts +34 -0
- package/components/card/preview.vue +0 -139
|
@@ -204,7 +204,6 @@ $video-card-mini-title: $color-zinc-300;
|
|
|
204
204
|
$video-card-mini-weight: 400;
|
|
205
205
|
$video-card-user-text: $color-zinc-400;
|
|
206
206
|
$video-card-user-bg: $color-zinc-700;
|
|
207
|
-
$card-preview-loader-bg: linear-gradient(to right, $color-indigo-muted, $color-indigo-deep);
|
|
208
207
|
|
|
209
208
|
// ─── History card ───
|
|
210
209
|
$history-card-bg: $color-zinc-900-40;
|
|
@@ -965,11 +964,29 @@ $library-item-badge-text: $color-white;
|
|
|
965
964
|
$library-item-badge-bordered-border: $color-zinc-600;
|
|
966
965
|
$library-item-badge-bordered-text: $color-zinc-400;
|
|
967
966
|
|
|
967
|
+
// ─── Library feed (блок подписки: модель / канал / категория) ───
|
|
968
|
+
$library-feed-bg: $color-zinc-900-40;
|
|
969
|
+
$library-feed-border: $color-zinc-800;
|
|
970
|
+
$library-feed-fade: $color-zinc-950;
|
|
971
|
+
$library-feed-avatar-border: $color-zinc-700;
|
|
972
|
+
$library-feed-avatar-border--hover: $color-zinc-500;
|
|
973
|
+
$library-feed-initials: $color-zinc-400;
|
|
974
|
+
$library-feed-initials-gradient-from: $color-zinc-700;
|
|
975
|
+
$library-feed-initials-gradient-to: $color-zinc-800;
|
|
976
|
+
$library-feed-name: $color-white;
|
|
977
|
+
$library-feed-name--hover: $color-indigo-400;
|
|
978
|
+
$library-feed-badge-bg: $color-indigo-600;
|
|
979
|
+
$library-feed-badge-text: $color-white;
|
|
980
|
+
$library-feed-meta: $color-zinc-500;
|
|
981
|
+
$library-feed-meta-dot: $color-zinc-600;
|
|
982
|
+
$library-feed-title: $color-zinc-500;
|
|
983
|
+
|
|
968
984
|
// ─── Page: library ───
|
|
969
985
|
$page-library-heading: $color-white;
|
|
970
986
|
$page-library-heading-icon: $color-white;
|
|
971
987
|
$page-library-heading-icon-bg: $mono-white-10;
|
|
972
988
|
$page-library-toggle-text: $color-zinc-300;
|
|
989
|
+
$page-library-confirm-text: $color-zinc-300;
|
|
973
990
|
|
|
974
991
|
// ─── Page: history ───
|
|
975
992
|
$page-history-group-title: $color-zinc-300;
|
|
@@ -261,7 +261,6 @@ $video-card-mini-title: $color-gray-900;
|
|
|
261
261
|
$video-card-mini-weight: 500;
|
|
262
262
|
$video-card-user-text: $color-gray-700;
|
|
263
263
|
$video-card-user-bg: $color-gray-300;
|
|
264
|
-
$card-preview-loader-bg: linear-gradient(to right, $color-indigo-muted, $color-indigo-deep);
|
|
265
264
|
$video-card-dropdown-size--hover: 1.25;
|
|
266
265
|
|
|
267
266
|
// ─── History card ───
|
|
@@ -995,11 +994,29 @@ $library-item-badge-text: $color-white;
|
|
|
995
994
|
$library-item-badge-bordered-border: $color-gray-300;
|
|
996
995
|
$library-item-badge-bordered-text: $color-gray-600;
|
|
997
996
|
|
|
997
|
+
// ─── Library feed (блок подписки: модель / канал / категория) ───
|
|
998
|
+
$library-feed-bg: $color-gray-100;
|
|
999
|
+
$library-feed-border: transparent;
|
|
1000
|
+
$library-feed-fade: $color-gray-100;
|
|
1001
|
+
$library-feed-avatar-border: $color-gray-300;
|
|
1002
|
+
$library-feed-avatar-border--hover: $color-indigo-500-50;
|
|
1003
|
+
$library-feed-initials: $color-gray-600;
|
|
1004
|
+
$library-feed-initials-gradient-from: $color-gray-200;
|
|
1005
|
+
$library-feed-initials-gradient-to: $color-gray-300;
|
|
1006
|
+
$library-feed-name: $color-gray-900;
|
|
1007
|
+
$library-feed-name--hover: $color-indigo-600;
|
|
1008
|
+
$library-feed-badge-bg: $color-indigo-600;
|
|
1009
|
+
$library-feed-badge-text: $color-white;
|
|
1010
|
+
$library-feed-meta: $color-gray-500;
|
|
1011
|
+
$library-feed-meta-dot: $color-gray-400;
|
|
1012
|
+
$library-feed-title: $color-gray-500;
|
|
1013
|
+
|
|
998
1014
|
// ─── Page: library ───
|
|
999
1015
|
$page-library-heading: $color-gray-900;
|
|
1000
1016
|
$page-library-heading-icon: $color-gray-900;
|
|
1001
1017
|
$page-library-heading-icon-bg: $color-gray-200;
|
|
1002
1018
|
$page-library-toggle-text: $color-gray-700;
|
|
1019
|
+
$page-library-confirm-text: $color-gray-700;
|
|
1003
1020
|
|
|
1004
1021
|
// ─── Page: history ───
|
|
1005
1022
|
$page-history-group-title: $color-gray-900;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<!-- Кнопка меню карточки: до первого клика в DOM только она, чанк самого меню грузится по требованию -->
|
|
2
2
|
<template>
|
|
3
|
-
<
|
|
4
|
-
v-if="
|
|
3
|
+
<component
|
|
4
|
+
v-if="dropdown"
|
|
5
|
+
:is="dropdown"
|
|
5
6
|
v-bind="{ ...$attrs, ...props }"
|
|
6
7
|
auto-open
|
|
7
8
|
/>
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
</template>
|
|
22
23
|
|
|
23
24
|
<script setup lang="ts">
|
|
25
|
+
import type { Component } from 'vue';
|
|
24
26
|
import type { IVideoCard } from '../../../types';
|
|
25
27
|
|
|
26
28
|
defineOptions({ inheritAttrs: false });
|
|
@@ -35,11 +37,13 @@ const props = defineProps<{
|
|
|
35
37
|
|
|
36
38
|
const { t } = useI18n();
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
// Не LazyCardDropdown: async-обёртка на первом рендере отдаёт коммент-заглушку вместо элемента,
|
|
41
|
+
// колонка грида схлопывается и текст карточки успевает дёрнуться. Кладём уже загруженный компонент —
|
|
42
|
+
// подмена кнопки на меню происходит одним патчем.
|
|
43
|
+
const dropdown = shallowRef<Component | null>(null);
|
|
39
44
|
|
|
40
45
|
async function mountDropdown() {
|
|
41
|
-
await import('./index.vue');
|
|
42
|
-
isMounted.value = true;
|
|
46
|
+
dropdown.value = (await import('./index.vue')).default;
|
|
43
47
|
}
|
|
44
48
|
</script>
|
|
45
49
|
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
height="270"
|
|
21
21
|
@error="posterError = true"
|
|
22
22
|
/>
|
|
23
|
-
<
|
|
23
|
+
<UiVideoPreview
|
|
24
24
|
v-if="isPreviewShow && card.previewUrl"
|
|
25
25
|
:url="card.previewUrl"
|
|
26
26
|
/>
|
|
@@ -179,6 +179,7 @@ const videoCard = computed<IVideoCard>(() => ({
|
|
|
179
179
|
<style lang="scss">
|
|
180
180
|
$inset-label: 8px;
|
|
181
181
|
$progress-height: 4px;
|
|
182
|
+
$dropdown-column: 18px;
|
|
182
183
|
|
|
183
184
|
.card-history {
|
|
184
185
|
@include video-card;
|
|
@@ -249,7 +250,7 @@ $progress-height: 4px;
|
|
|
249
250
|
.card-history__wrapper {
|
|
250
251
|
display: grid;
|
|
251
252
|
column-gap: 8px;
|
|
252
|
-
grid-template-columns: 32px 1fr
|
|
253
|
+
grid-template-columns: 32px 1fr $dropdown-column;
|
|
253
254
|
align-items: start;
|
|
254
255
|
padding: 12px;
|
|
255
256
|
color: $history-card-secondary;
|
|
@@ -343,7 +344,7 @@ $progress-height: 4px;
|
|
|
343
344
|
}
|
|
344
345
|
|
|
345
346
|
.card-history__wrapper {
|
|
346
|
-
grid-template-columns: 1fr
|
|
347
|
+
grid-template-columns: 1fr $dropdown-column;
|
|
347
348
|
}
|
|
348
349
|
|
|
349
350
|
.card-history__title,
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
<div
|
|
4
4
|
:class="[
|
|
5
5
|
{'--mini': mini},
|
|
6
|
+
{'--compact': compact},
|
|
6
7
|
{'--avatar': card.channelAvatar},
|
|
7
8
|
{'--no-channel': isChannelPage},
|
|
8
9
|
]"
|
|
@@ -27,7 +28,7 @@
|
|
|
27
28
|
height="270"
|
|
28
29
|
@error="onPosterError"
|
|
29
30
|
/>
|
|
30
|
-
<
|
|
31
|
+
<UiVideoPreview
|
|
31
32
|
v-if="isPreviewShow && card.previewUrl"
|
|
32
33
|
:url="card.previewUrl"
|
|
33
34
|
/>
|
|
@@ -81,7 +82,7 @@
|
|
|
81
82
|
>{{ card.title }}
|
|
82
83
|
</NuxtLink>
|
|
83
84
|
<component
|
|
84
|
-
v-if="!mini && card.channelName"
|
|
85
|
+
v-if="!mini && !compact && card.channelName"
|
|
85
86
|
:is="component"
|
|
86
87
|
:to="channelLink"
|
|
87
88
|
class="card-video__channel-wrapper"
|
|
@@ -96,7 +97,7 @@
|
|
|
96
97
|
</span>
|
|
97
98
|
</component>
|
|
98
99
|
<div
|
|
99
|
-
v-if="!mini && cardTags && cardTags.length > 0"
|
|
100
|
+
v-if="!mini && !compact && cardTags && cardTags.length > 0"
|
|
100
101
|
class="card-video__tags"
|
|
101
102
|
>
|
|
102
103
|
<div class="card-video__tags-wrapper">
|
|
@@ -130,6 +131,8 @@ const featureFlags = useRuntimeConfig().public.featureFlags;
|
|
|
130
131
|
const props = defineProps<{
|
|
131
132
|
card: IVideoCard
|
|
132
133
|
mini?: boolean
|
|
134
|
+
/** Аватар канала и тайтл, но без названия канала и тегов — лента подписок */
|
|
135
|
+
compact?: boolean
|
|
133
136
|
loading?: 'eager' | 'lazy'
|
|
134
137
|
topChips?: string[]
|
|
135
138
|
playlistId?: string
|
|
@@ -202,6 +205,10 @@ const cardTags = computed(() => {
|
|
|
202
205
|
$inset-label: 8px;
|
|
203
206
|
$layout-breakpoint: 250px;
|
|
204
207
|
|
|
208
|
+
// Колонка под меню карточки фиксирована, а не auto: иначе ширина зависит от того, отрисовано меню
|
|
209
|
+
// или нет, и в момент подмены кнопки заголовок дёргается
|
|
210
|
+
$dropdown-column: 18px;
|
|
211
|
+
|
|
205
212
|
.card-video {
|
|
206
213
|
@include video-card;
|
|
207
214
|
|
|
@@ -276,7 +283,7 @@ $layout-breakpoint: 250px;
|
|
|
276
283
|
|
|
277
284
|
.card-video__wrapper {
|
|
278
285
|
display: grid;
|
|
279
|
-
grid-template-columns: 1fr
|
|
286
|
+
grid-template-columns: 1fr $dropdown-column;
|
|
280
287
|
align-items: start;
|
|
281
288
|
align-content: center;
|
|
282
289
|
color: $video-card-secondary;
|
|
@@ -287,13 +294,13 @@ $layout-breakpoint: 250px;
|
|
|
287
294
|
|
|
288
295
|
@include from-cq($layout-breakpoint) {
|
|
289
296
|
column-gap: 8px;
|
|
290
|
-
grid-template-columns: 32px 1fr
|
|
297
|
+
grid-template-columns: 32px 1fr $dropdown-column;
|
|
291
298
|
}
|
|
292
299
|
}
|
|
293
300
|
|
|
294
301
|
.--avatar .card-video__wrapper {
|
|
295
302
|
column-gap: 8px;
|
|
296
|
-
grid-template-columns: 32px 1fr
|
|
303
|
+
grid-template-columns: 32px 1fr $dropdown-column;
|
|
297
304
|
}
|
|
298
305
|
|
|
299
306
|
.--avatar .card-video__title {
|
|
@@ -321,7 +328,7 @@ $layout-breakpoint: 250px;
|
|
|
321
328
|
}
|
|
322
329
|
|
|
323
330
|
.--no-channel .card-video__wrapper {
|
|
324
|
-
grid-template-columns: 1fr
|
|
331
|
+
grid-template-columns: 1fr $dropdown-column;
|
|
325
332
|
}
|
|
326
333
|
|
|
327
334
|
.--no-channel .card-video__title {
|
|
@@ -339,7 +346,13 @@ $layout-breakpoint: 250px;
|
|
|
339
346
|
}
|
|
340
347
|
|
|
341
348
|
.--mini .card-video__wrapper {
|
|
342
|
-
grid-template-columns: 1fr
|
|
349
|
+
grid-template-columns: 1fr $dropdown-column;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/* Без строки канала и тегов вторая строка грида не нужна — иначе аватар и «троеточие» растягиваются. */
|
|
353
|
+
.--compact .card-video__logo-wrapper,
|
|
354
|
+
.--compact .card-video__dropdown {
|
|
355
|
+
grid-row: 1;
|
|
343
356
|
}
|
|
344
357
|
|
|
345
358
|
.--mini .card-video__dropdown {
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
<!-- Блок подписки (модель / канал / категория): шапка с аватаром, тегами и счётчиками + лента роликов -->
|
|
2
|
+
<template>
|
|
3
|
+
<article class="library-feed">
|
|
4
|
+
<header class="library-feed__header">
|
|
5
|
+
<NuxtLink
|
|
6
|
+
:to="item.to"
|
|
7
|
+
:title="item.title"
|
|
8
|
+
class="library-feed__avatar-link"
|
|
9
|
+
>
|
|
10
|
+
<UiImg
|
|
11
|
+
v-if="currentAvatar"
|
|
12
|
+
:src="currentAvatar"
|
|
13
|
+
:alt="item.title"
|
|
14
|
+
:loading="priority ? 'eager' : 'lazy'"
|
|
15
|
+
:priority="priority"
|
|
16
|
+
class="library-feed__avatar"
|
|
17
|
+
width="96"
|
|
18
|
+
height="96"
|
|
19
|
+
sizes="96px"
|
|
20
|
+
@error="avatarError = true"
|
|
21
|
+
/>
|
|
22
|
+
<span
|
|
23
|
+
v-else
|
|
24
|
+
class="library-feed__avatar library-feed__initials"
|
|
25
|
+
>{{ initials }}</span>
|
|
26
|
+
</NuxtLink>
|
|
27
|
+
|
|
28
|
+
<div class="library-feed__info">
|
|
29
|
+
<div class="library-feed__heading">
|
|
30
|
+
<NuxtLink
|
|
31
|
+
:to="item.to"
|
|
32
|
+
class="library-feed__name"
|
|
33
|
+
>
|
|
34
|
+
{{ item.title }}
|
|
35
|
+
<img
|
|
36
|
+
v-if="item.country"
|
|
37
|
+
:alt="item.country.title"
|
|
38
|
+
:title="`${t('birthplace_country')}: ${item.country.title}`"
|
|
39
|
+
:src="`/icons/flags/${item.country.name}.svg`"
|
|
40
|
+
class="library-feed__flag"
|
|
41
|
+
width="20"
|
|
42
|
+
height="14"
|
|
43
|
+
>
|
|
44
|
+
</NuxtLink>
|
|
45
|
+
|
|
46
|
+
<span
|
|
47
|
+
v-if="item.newCount"
|
|
48
|
+
class="library-feed__badge"
|
|
49
|
+
>{{ t('library.new_count', { count: item.newCount }) }}</span>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<LazyUiExpandRow
|
|
53
|
+
v-if="item.tags && item.tags.length"
|
|
54
|
+
:items="item.tags"
|
|
55
|
+
class="library-feed__tags"
|
|
56
|
+
hydrate-on-visible
|
|
57
|
+
micro
|
|
58
|
+
/>
|
|
59
|
+
|
|
60
|
+
<p class="library-feed__meta">
|
|
61
|
+
<span
|
|
62
|
+
v-for="(entry, index) in item.meta"
|
|
63
|
+
:key="`meta-${index}`"
|
|
64
|
+
class="library-feed__meta-item"
|
|
65
|
+
>
|
|
66
|
+
<UiIcon
|
|
67
|
+
v-if="entry.icon"
|
|
68
|
+
:name="entry.icon"
|
|
69
|
+
size="14"
|
|
70
|
+
/>
|
|
71
|
+
{{ entry.text }}
|
|
72
|
+
</span>
|
|
73
|
+
</p>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<div class="library-feed__actions _from-sm">
|
|
77
|
+
<UiBtn
|
|
78
|
+
:theme="following ? 'secondary' : 'primary'"
|
|
79
|
+
class="library-feed__follow"
|
|
80
|
+
@click="emit('toggle-follow', item)"
|
|
81
|
+
>
|
|
82
|
+
<UiIcon
|
|
83
|
+
:name="following ? 'check' : 'plus'"
|
|
84
|
+
size="16"
|
|
85
|
+
/>
|
|
86
|
+
{{ following ? t('library.following_state') : t('follow') }}
|
|
87
|
+
</UiBtn>
|
|
88
|
+
|
|
89
|
+
<UiLink
|
|
90
|
+
:to="item.to"
|
|
91
|
+
theme="secondary"
|
|
92
|
+
>
|
|
93
|
+
{{ videosText }}
|
|
94
|
+
<UiIcon
|
|
95
|
+
name="arrow-right"
|
|
96
|
+
size="16"
|
|
97
|
+
/>
|
|
98
|
+
</UiLink>
|
|
99
|
+
</div>
|
|
100
|
+
</header>
|
|
101
|
+
|
|
102
|
+
<h3
|
|
103
|
+
v-if="item.feedTitle"
|
|
104
|
+
class="library-feed__feed-title"
|
|
105
|
+
>{{ item.feedTitle }}</h3>
|
|
106
|
+
|
|
107
|
+
<div class="library-feed__grid">
|
|
108
|
+
<CardVideo
|
|
109
|
+
v-for="(video, index) in item.videos"
|
|
110
|
+
:key="video.guid"
|
|
111
|
+
:card="video"
|
|
112
|
+
:loading="priority && index < 3 ? 'eager' : 'lazy'"
|
|
113
|
+
:priority="priority && index < 3"
|
|
114
|
+
compact
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<UiLink
|
|
119
|
+
:to="item.to"
|
|
120
|
+
theme="secondary"
|
|
121
|
+
class="library-feed__all _to-sm"
|
|
122
|
+
wide
|
|
123
|
+
>
|
|
124
|
+
{{ videosText }}
|
|
125
|
+
<UiIcon
|
|
126
|
+
name="arrow-right"
|
|
127
|
+
size="16"
|
|
128
|
+
/>
|
|
129
|
+
</UiLink>
|
|
130
|
+
</article>
|
|
131
|
+
</template>
|
|
132
|
+
|
|
133
|
+
<script setup lang="ts">
|
|
134
|
+
import type { ILibraryFeedItem } from '../../types';
|
|
135
|
+
|
|
136
|
+
const props = defineProps<{
|
|
137
|
+
item: ILibraryFeedItem
|
|
138
|
+
following?: boolean
|
|
139
|
+
priority?: boolean
|
|
140
|
+
}>();
|
|
141
|
+
|
|
142
|
+
const emit = defineEmits<{
|
|
143
|
+
(eventName: 'toggle-follow', item: ILibraryFeedItem): void,
|
|
144
|
+
}>();
|
|
145
|
+
|
|
146
|
+
const { t } = useI18n();
|
|
147
|
+
|
|
148
|
+
const avatarError = ref(false);
|
|
149
|
+
|
|
150
|
+
const currentAvatar = computed(() => avatarError.value ? undefined : props.item.avatarUrl);
|
|
151
|
+
|
|
152
|
+
/** Заглушка вместо аватара: «Top To Bottom» → TTB, «Bareback» → B. */
|
|
153
|
+
const initials = computed(() => props.item.title
|
|
154
|
+
.split(/\s+/)
|
|
155
|
+
.slice(0, 3)
|
|
156
|
+
.map(word => word.charAt(0))
|
|
157
|
+
.join('')
|
|
158
|
+
.toUpperCase());
|
|
159
|
+
|
|
160
|
+
const videosText = computed(() => t('plural.videos', props.item.videosCount));
|
|
161
|
+
</script>
|
|
162
|
+
|
|
163
|
+
<style lang="scss">
|
|
164
|
+
.library-feed {
|
|
165
|
+
/* Растушёвка «ещё» у тегов уходит в фон карточки, а не страницы */
|
|
166
|
+
--expand-row-fade-end: #{$library-feed-fade};
|
|
167
|
+
|
|
168
|
+
padding: 16px;
|
|
169
|
+
background-color: $library-feed-bg;
|
|
170
|
+
border: 1px solid $library-feed-border;
|
|
171
|
+
border-radius: $radius-xl;
|
|
172
|
+
|
|
173
|
+
@include from-br(sm) {
|
|
174
|
+
padding: 20px;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.library-feed__header {
|
|
179
|
+
display: grid;
|
|
180
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
181
|
+
column-gap: 16px;
|
|
182
|
+
row-gap: 12px;
|
|
183
|
+
align-items: start;
|
|
184
|
+
margin-bottom: 20px;
|
|
185
|
+
|
|
186
|
+
@include from-br(sm) {
|
|
187
|
+
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.library-feed__avatar {
|
|
192
|
+
width: 80px;
|
|
193
|
+
height: 80px;
|
|
194
|
+
object-fit: cover;
|
|
195
|
+
object-position: center 30%;
|
|
196
|
+
border-radius: $radius-full;
|
|
197
|
+
border: 2px solid $library-feed-avatar-border;
|
|
198
|
+
|
|
199
|
+
@include from-br(sm) {
|
|
200
|
+
width: 96px;
|
|
201
|
+
height: 96px;
|
|
202
|
+
transition: var(--transition) border-color;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
@include from-br(sm) {
|
|
207
|
+
.library-feed__avatar-link:is(:hover, :focus-visible) .library-feed__avatar {
|
|
208
|
+
border-color: $library-feed-avatar-border--hover;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.library-feed__initials {
|
|
213
|
+
@include font-lg;
|
|
214
|
+
|
|
215
|
+
display: grid;
|
|
216
|
+
place-content: center;
|
|
217
|
+
font-weight: 700;
|
|
218
|
+
text-transform: uppercase;
|
|
219
|
+
color: $library-feed-initials;
|
|
220
|
+
background: linear-gradient(to bottom right, $library-feed-initials-gradient-from, $library-feed-initials-gradient-to);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.library-feed__info {
|
|
224
|
+
min-width: 0;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.library-feed__heading {
|
|
228
|
+
display: flex;
|
|
229
|
+
flex-wrap: wrap;
|
|
230
|
+
align-items: center;
|
|
231
|
+
column-gap: 10px;
|
|
232
|
+
row-gap: 6px;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.library-feed__name {
|
|
236
|
+
@include font-lg;
|
|
237
|
+
|
|
238
|
+
display: flex;
|
|
239
|
+
align-items: center;
|
|
240
|
+
column-gap: 8px;
|
|
241
|
+
font-weight: 700;
|
|
242
|
+
text-transform: uppercase;
|
|
243
|
+
color: $library-feed-name;
|
|
244
|
+
|
|
245
|
+
@include from-br(sm) {
|
|
246
|
+
transition: var(--transition) color;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
@include hover(color) {
|
|
250
|
+
color: $library-feed-name--hover;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.library-feed__flag {
|
|
255
|
+
flex-shrink: 0;
|
|
256
|
+
border-radius: 2px;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.library-feed__badge {
|
|
260
|
+
@include font-xs;
|
|
261
|
+
|
|
262
|
+
flex-shrink: 0;
|
|
263
|
+
font-weight: 600;
|
|
264
|
+
white-space: nowrap;
|
|
265
|
+
padding-block: 4px;
|
|
266
|
+
padding-inline: 10px;
|
|
267
|
+
color: $library-feed-badge-text;
|
|
268
|
+
background-color: $library-feed-badge-bg;
|
|
269
|
+
border-radius: $radius-full;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.library-feed__tags {
|
|
273
|
+
margin-top: 8px;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.library-feed__meta {
|
|
277
|
+
@include font-sm;
|
|
278
|
+
|
|
279
|
+
display: flex;
|
|
280
|
+
flex-wrap: wrap;
|
|
281
|
+
align-items: center;
|
|
282
|
+
column-gap: 8px;
|
|
283
|
+
row-gap: 4px;
|
|
284
|
+
margin-top: 8px;
|
|
285
|
+
color: $library-feed-meta;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.library-feed__meta-item {
|
|
289
|
+
display: flex;
|
|
290
|
+
align-items: center;
|
|
291
|
+
column-gap: 6px;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.library-feed__meta-item:not(:last-child)::after {
|
|
295
|
+
content: '·';
|
|
296
|
+
margin-inline-start: 2px;
|
|
297
|
+
color: $library-feed-meta-dot;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.library-feed__actions {
|
|
301
|
+
display: flex;
|
|
302
|
+
align-items: center;
|
|
303
|
+
column-gap: 8px;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.library-feed__follow {
|
|
307
|
+
min-width: 124px;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.library-feed__feed-title {
|
|
311
|
+
@include font-sm;
|
|
312
|
+
|
|
313
|
+
margin: 0 0 12px;
|
|
314
|
+
font-weight: 400;
|
|
315
|
+
color: $library-feed-title;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.library-feed__grid {
|
|
319
|
+
display: grid;
|
|
320
|
+
gap: 16px;
|
|
321
|
+
grid-template-columns: repeat(2, 1fr);
|
|
322
|
+
|
|
323
|
+
@include from-br(xm) {
|
|
324
|
+
grid-template-columns: repeat(3, 1fr);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
@include from-br(sm) {
|
|
328
|
+
gap: 24px 16px;
|
|
329
|
+
grid-template-columns: repeat(4, 1fr);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
@include from-br(md) {
|
|
333
|
+
grid-template-columns: repeat(5, 1fr);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.library-feed__all {
|
|
338
|
+
margin-top: 16px;
|
|
339
|
+
}
|
|
340
|
+
</style>
|