mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-08-01 19:37:32 +08:00
Refine mobile subscribe cards and grouped list styling
This commit is contained in:
@@ -92,6 +92,17 @@ const rightBottomStateDisplay = computed(() => {
|
|||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 移动端紧凑卡片的状态展示,颜色统一映射到 Vuetify 全局主题 token。
|
||||||
|
const compactStateDisplay = computed(() => {
|
||||||
|
if (subscribeState.value === 'S') {
|
||||||
|
return { color: 'secondary', icon: 'mdi-pause-circle-outline', label: t('subscribe.cardStatePaused') }
|
||||||
|
}
|
||||||
|
if (subscribeState.value === 'P') {
|
||||||
|
return { color: 'info', icon: 'mdi-timer-sand', label: t('subscribe.cardStatePending') }
|
||||||
|
}
|
||||||
|
return { color: 'primary', icon: 'mdi-rss', label: t('subscribe.subscribing') }
|
||||||
|
})
|
||||||
|
|
||||||
// 洗版徽标:共用 mdi-shimmer 图标,分集 / 全集 由 full 标记区分背景
|
// 洗版徽标:共用 mdi-shimmer 图标,分集 / 全集 由 full 标记区分背景
|
||||||
const bestVersionBadge = computed(() => {
|
const bestVersionBadge = computed(() => {
|
||||||
if (!isEnabledFlag(props.media?.best_version)) return null
|
if (!isEnabledFlag(props.media?.best_version)) return null
|
||||||
@@ -423,45 +434,143 @@ function handleCardClick() {
|
|||||||
}"
|
}"
|
||||||
min-height="150"
|
min-height="150"
|
||||||
@click="handleCardClick"
|
@click="handleCardClick"
|
||||||
:ripple="!props.batchMode && !props.sortable"
|
:ripple="display.smAndUp.value && !props.batchMode && !props.sortable"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="bestVersionBadge && imageLoaded"
|
v-if="bestVersionBadge && imageLoaded"
|
||||||
class="best-version-badge"
|
class="best-version-badge"
|
||||||
:class="{ 'best-version-badge-full': bestVersionBadge.full }"
|
:class="{ 'best-version-badge-full': bestVersionBadge.full }"
|
||||||
>
|
>
|
||||||
<VIcon :icon="bestVersionBadge.icon" color="white" size="16" />
|
<VIcon :icon="bestVersionBadge.icon" color="white" size="16" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!props.sortable" class="me-n3 absolute top-1 right-4">
|
<div v-if="!props.sortable && display.smAndUp.value" class="me-n3 absolute top-1 right-4">
|
||||||
<IconBtn @click.stop>
|
<IconBtn @click.stop>
|
||||||
<VIcon icon="mdi-dots-vertical" color="white" />
|
<VIcon icon="mdi-dots-vertical" color="white" />
|
||||||
<VMenu activator="parent" close-on-content-click>
|
<VMenu activator="parent" close-on-content-click>
|
||||||
<VList>
|
<VList>
|
||||||
<template v-for="(item, i) in dropdownItems" :key="i">
|
<template v-for="(item, i) in dropdownItems" :key="i">
|
||||||
<VListItem v-if="item.show !== false" :base-color="item.props.color" @click="item.props.click">
|
<VListItem v-if="item.show !== false" :base-color="item.props.color" @click="item.props.click">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<VIcon :icon="item.props.prependIcon" />
|
<VIcon :icon="item.props.prependIcon" />
|
||||||
</template>
|
</template>
|
||||||
<VListItemTitle v-text="item.title" />
|
<VListItemTitle v-text="item.title" />
|
||||||
</VListItem>
|
</VListItem>
|
||||||
|
</template>
|
||||||
|
</VList>
|
||||||
|
</VMenu>
|
||||||
|
</IconBtn>
|
||||||
|
</div>
|
||||||
|
<template #image v-if="display.smAndUp.value">
|
||||||
|
<VImg :src="backdropUrl || posterUrl" aspect-ratio="3/2" cover @load="imageLoadHandler" position="top">
|
||||||
|
<template #placeholder>
|
||||||
|
<div class="w-full h-full">
|
||||||
|
<VSkeletonLoader class="object-cover aspect-w-3 aspect-h-2" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default>
|
||||||
|
<div class="absolute inset-0 outline-none subscribe-card-background"></div>
|
||||||
|
</template>
|
||||||
|
</VImg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="display.xs.value">
|
||||||
|
<div class="subscribe-card-mobile-media">
|
||||||
|
<VImg
|
||||||
|
:src="backdropUrl || posterUrl"
|
||||||
|
:aspect-ratio="2"
|
||||||
|
cover
|
||||||
|
position="top"
|
||||||
|
@load="imageLoadHandler"
|
||||||
|
>
|
||||||
|
<template #placeholder>
|
||||||
|
<VSkeletonLoader class="h-full w-full" />
|
||||||
</template>
|
</template>
|
||||||
</VList>
|
</VImg>
|
||||||
</VMenu>
|
|
||||||
</IconBtn>
|
<div
|
||||||
</div>
|
v-if="props.media?.username || lastUpdateText"
|
||||||
<template #image>
|
class="subscribe-card-mobile-image-meta"
|
||||||
<VImg :src="backdropUrl || posterUrl" aspect-ratio="3/2" cover @load="imageLoadHandler" position="top">
|
:class="{ 'subscribe-card-mobile-image-meta--with-badge': bestVersionBadge }"
|
||||||
<template #placeholder>
|
>
|
||||||
<div class="w-full h-full">
|
<div
|
||||||
<VSkeletonLoader class="object-cover aspect-w-3 aspect-h-2" />
|
v-if="props.media?.username"
|
||||||
|
class="subscribe-card-mobile-image-meta__item subscribe-card-mobile-image-meta__user"
|
||||||
|
:title="props.media?.username"
|
||||||
|
>
|
||||||
|
<VIcon icon="mdi-account" size="14" />
|
||||||
|
<span>{{ props.media?.username }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="lastUpdateText"
|
||||||
|
class="subscribe-card-mobile-image-meta__item subscribe-card-mobile-image-meta__updated"
|
||||||
|
>
|
||||||
|
<VIcon icon="mdi-download" size="14" />
|
||||||
|
<span>{{ lastUpdateText }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
<template #default>
|
|
||||||
<div class="absolute inset-0 outline-none subscribe-card-background"></div>
|
<div class="subscribe-card-mobile-body">
|
||||||
</template>
|
<div class="subscribe-card-mobile-title">
|
||||||
</VImg>
|
{{ props.media?.name }}
|
||||||
</template>
|
{{ formatSeasonLabel(props.media?.season, t('media.specials')) }}
|
||||||
<div>
|
</div>
|
||||||
|
|
||||||
|
<div class="subscribe-card-mobile-footer">
|
||||||
|
<div class="subscribe-card-mobile-meta">
|
||||||
|
<div
|
||||||
|
class="subscribe-card-mobile-state"
|
||||||
|
:style="{ color: `rgb(var(--v-theme-${compactStateDisplay.color}))` }"
|
||||||
|
:title="compactStateDisplay.label"
|
||||||
|
:aria-label="compactStateDisplay.label"
|
||||||
|
>
|
||||||
|
<VIcon :icon="compactStateDisplay.icon" size="18" />
|
||||||
|
<span v-if="subscribeProgressText" class="subscribe-card-mobile-progress-text">
|
||||||
|
{{ subscribeProgressText }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<IconBtn
|
||||||
|
v-if="!props.sortable"
|
||||||
|
class="subscribe-card-mobile-menu"
|
||||||
|
size="small"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<VIcon icon="mdi-dots-horizontal" size="20" />
|
||||||
|
<VMenu activator="parent" close-on-content-click>
|
||||||
|
<VList>
|
||||||
|
<template v-for="(item, i) in dropdownItems" :key="i">
|
||||||
|
<VListItem
|
||||||
|
v-if="item.show !== false"
|
||||||
|
:base-color="item.props.color"
|
||||||
|
@click="item.props.click"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon :icon="item.props.prependIcon" />
|
||||||
|
</template>
|
||||||
|
<VListItemTitle v-text="item.title" />
|
||||||
|
</VListItem>
|
||||||
|
</template>
|
||||||
|
</VList>
|
||||||
|
</VMenu>
|
||||||
|
</IconBtn>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="props.media?.total_episode" class="subscribe-card-mobile-progress">
|
||||||
|
<VProgressLinear
|
||||||
|
:model-value="getPercentage()"
|
||||||
|
:bg-color="compactStateDisplay.color"
|
||||||
|
:color="compactStateDisplay.color"
|
||||||
|
bg-opacity="0.18"
|
||||||
|
height="4"
|
||||||
|
rounded
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
<VCardText class="flex items-center pt-3 pb-2">
|
<VCardText class="flex items-center pt-3 pb-2">
|
||||||
<div
|
<div
|
||||||
class="h-auto w-12 flex-shrink-0 overflow-hidden rounded-md relative"
|
class="h-auto w-12 flex-shrink-0 overflow-hidden rounded-md relative"
|
||||||
@@ -568,7 +677,7 @@ function handleCardClick() {
|
|||||||
color="success"
|
color="success"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</VCard>
|
</VCard>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -592,6 +701,151 @@ function handleCardClick() {
|
|||||||
border: var(--app-card-light-border);
|
border: var(--app-card-light-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-media {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
aspect-ratio: 2 / 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
inline-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-media .v-img {
|
||||||
|
block-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-image-meta {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
inset: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-image-meta__item {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
min-inline-size: 0;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
color: rgba(255, 255, 255, 0.88);
|
||||||
|
isolation: isolate;
|
||||||
|
line-height: 1.2;
|
||||||
|
padding-block: 0.0625rem;
|
||||||
|
padding-inline: 0.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-image-meta__item::before {
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1;
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
background: rgba(0, 0, 0, 0.36);
|
||||||
|
content: '';
|
||||||
|
filter: blur(3px);
|
||||||
|
inset: -0.25rem -0.55rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-image-meta__user {
|
||||||
|
max-inline-size: calc(100% - 1rem);
|
||||||
|
inset-block-start: 0.5rem;
|
||||||
|
inset-inline-start: 0.5rem;
|
||||||
|
transition: inset-block-start 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-image-meta--with-badge .subscribe-card-mobile-image-meta__user {
|
||||||
|
max-inline-size: calc(100% - 4.25rem);
|
||||||
|
inset-block-start: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-image-meta__user span {
|
||||||
|
min-inline-size: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-image-meta__updated {
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: rgba(255, 255, 255, 0.76);
|
||||||
|
inset-block-end: 0.5rem;
|
||||||
|
inset-inline-end: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-body {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-title {
|
||||||
|
display: -webkit-box;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.35;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-footer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
margin-block-start: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-meta {
|
||||||
|
display: flex;
|
||||||
|
min-inline-size: 0;
|
||||||
|
min-block-size: 2rem;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-state {
|
||||||
|
display: flex;
|
||||||
|
min-inline-size: 0;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
gap: 0.35rem;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.25;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-state span {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-progress-text {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-menu {
|
||||||
|
block-size: 2rem;
|
||||||
|
min-block-size: 2rem;
|
||||||
|
inline-size: 2rem;
|
||||||
|
min-inline-size: 2rem;
|
||||||
|
flex: 0 0 2rem;
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-progress {
|
||||||
|
display: flex;
|
||||||
|
block-size: 4px;
|
||||||
|
inline-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-mobile-progress .v-progress-linear {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
.subscribe-card-shell--selected::after {
|
.subscribe-card-shell--selected::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
@@ -625,7 +879,7 @@ function handleCardClick() {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
border-radius: inherit;
|
border-radius: inherit;
|
||||||
box-shadow: inset 0 0 48px rgba(56, 189, 248, 40%); // sky-400
|
box-shadow: inset 0 0 48px rgba(var(--v-theme-info), 0.28);
|
||||||
content: '';
|
content: '';
|
||||||
inset: 0;
|
inset: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@@ -657,4 +911,30 @@ function handleCardClick() {
|
|||||||
background: rgba(255, 255, 255, 22%);
|
background: rgba(255, 255, 255, 22%);
|
||||||
box-shadow: 0 2px 8px rgba(255, 255, 255, 15%);
|
box-shadow: 0 2px 8px rgba(255, 255, 255, 15%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (width <= 599px) {
|
||||||
|
.subscribe-card {
|
||||||
|
min-block-size: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-paused {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-paused .subscribe-card-mobile-media {
|
||||||
|
filter: saturate(0.65);
|
||||||
|
opacity: 0.58;
|
||||||
|
}
|
||||||
|
|
||||||
|
.best-version-badge {
|
||||||
|
inset-inline-start: auto;
|
||||||
|
inset-inline-end: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-card-pending-tint::after {
|
||||||
|
box-shadow:
|
||||||
|
inset 0 0 0 1px rgba(var(--v-theme-info), 0.28),
|
||||||
|
inset 0 -4rem 5rem rgba(var(--v-theme-info), 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ onMounted(() => {
|
|||||||
background-color: var(--app-grouped-list-separator-color);
|
background-color: var(--app-grouped-list-separator-color);
|
||||||
block-size: 1px;
|
block-size: 1px;
|
||||||
inset-block-end: 0;
|
inset-block-end: 0;
|
||||||
inset-inline: 58px 0;
|
inset-inline: var(--app-grouped-list-content-offset) 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
@@ -221,6 +221,8 @@ onMounted(() => {
|
|||||||
.settings-list-icon {
|
.settings-list-icon {
|
||||||
--app-grouped-list-icon-rgb: var(--app-grouped-list-icon-primary-rgb);
|
--app-grouped-list-icon-rgb: var(--app-grouped-list-icon-primary-rgb);
|
||||||
|
|
||||||
|
block-size: var(--app-grouped-list-icon-size) !important;
|
||||||
|
inline-size: var(--app-grouped-list-icon-size) !important;
|
||||||
border-radius: max(var(--app-control-radius), 8px) !important;
|
border-radius: max(var(--app-control-radius), 8px) !important;
|
||||||
background: rgba(var(--app-grouped-list-icon-rgb), var(--app-grouped-list-icon-opacity)) !important;
|
background: rgba(var(--app-grouped-list-icon-rgb), var(--app-grouped-list-icon-opacity)) !important;
|
||||||
color: var(--app-grouped-list-icon-foreground) !important;
|
color: var(--app-grouped-list-icon-foreground) !important;
|
||||||
@@ -248,7 +250,7 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.settings-list-icon :deep(.v-icon) {
|
.settings-list-icon :deep(.v-icon) {
|
||||||
font-size: 1.375rem !important;
|
font-size: var(--app-grouped-list-icon-glyph-size) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-list-title {
|
.settings-list-title {
|
||||||
|
|||||||
@@ -108,6 +108,9 @@ html {
|
|||||||
--app-grouped-list-active-background: rgba(var(--v-theme-primary), 0.1);
|
--app-grouped-list-active-background: rgba(var(--v-theme-primary), 0.1);
|
||||||
--app-grouped-list-icon-foreground: rgb(var(--v-theme-on-primary));
|
--app-grouped-list-icon-foreground: rgb(var(--v-theme-on-primary));
|
||||||
--app-grouped-list-icon-opacity: 0.92;
|
--app-grouped-list-icon-opacity: 0.92;
|
||||||
|
--app-grouped-list-icon-size: 36px;
|
||||||
|
--app-grouped-list-icon-glyph-size: 1.25rem;
|
||||||
|
--app-grouped-list-content-offset: calc(24px + var(--app-grouped-list-icon-size));
|
||||||
--app-grouped-list-icon-primary-rgb: var(--v-theme-primary);
|
--app-grouped-list-icon-primary-rgb: var(--v-theme-primary);
|
||||||
--app-grouped-list-icon-info-rgb: var(--v-theme-info);
|
--app-grouped-list-icon-info-rgb: var(--v-theme-info);
|
||||||
--app-grouped-list-icon-success-rgb: var(--v-theme-success);
|
--app-grouped-list-icon-success-rgb: var(--v-theme-success);
|
||||||
@@ -1037,6 +1040,13 @@ html[data-theme="transparent"].transparent-glass-realtime .v-theme--transparent
|
|||||||
grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (width <= 599px) {
|
||||||
|
.grid-subscribe-card {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.grid-user-card {
|
.grid-user-card {
|
||||||
grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,16 @@ import { useToast } from 'vue-toastification'
|
|||||||
import { useConfirm } from '@/composables/useConfirm'
|
import { useConfirm } from '@/composables/useConfirm'
|
||||||
import { useKeepAliveRefresh, type KeepAliveRefreshContext } from '@/composables/useKeepAliveRefresh'
|
import { useKeepAliveRefresh, type KeepAliveRefreshContext } from '@/composables/useKeepAliveRefresh'
|
||||||
import { openSharedDialog } from '@/composables/useSharedDialog'
|
import { openSharedDialog } from '@/composables/useSharedDialog'
|
||||||
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
const SubscribeHistoryDialog = defineAsyncComponent(() => import('@/components/dialog/SubscribeHistoryDialog.vue'))
|
const SubscribeHistoryDialog = defineAsyncComponent(() => import('@/components/dialog/SubscribeHistoryDialog.vue'))
|
||||||
|
|
||||||
// 国际化
|
// 国际化
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
// 响应式断点用于切换订阅卡片网格密度。
|
||||||
|
const display = useDisplay()
|
||||||
|
|
||||||
// 用户 Store
|
// 用户 Store
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
@@ -117,6 +121,9 @@ const sortMode = computed({
|
|||||||
})
|
})
|
||||||
const canDragSort = computed(() => sortMode.value && canSortContext.value)
|
const canDragSort = computed(() => sortMode.value && canSortContext.value)
|
||||||
const shouldVirtualizeList = computed(() => !sortMode.value)
|
const shouldVirtualizeList = computed(() => !sortMode.value)
|
||||||
|
const subscribeGridMinItemWidth = computed(() => (display.xs.value ? 144 : 240))
|
||||||
|
const subscribeGridEstimatedItemHeight = computed(() => (display.xs.value ? 190 : 300))
|
||||||
|
const subscribeGridGap = computed(() => (display.xs.value ? 12 : 16))
|
||||||
const scrollToIndex = computed(() => {
|
const scrollToIndex = computed(() => {
|
||||||
if (!props.subid || sortMode.value) {
|
if (!props.subid || sortMode.value) {
|
||||||
return undefined
|
return undefined
|
||||||
@@ -581,8 +588,9 @@ defineExpose({
|
|||||||
v-else-if="displayList.length > 0 && shouldVirtualizeList"
|
v-else-if="displayList.length > 0 && shouldVirtualizeList"
|
||||||
:items="displayList"
|
:items="displayList"
|
||||||
:get-item-key="item => item.id"
|
:get-item-key="item => item.id"
|
||||||
:min-item-width="240"
|
:min-item-width="subscribeGridMinItemWidth"
|
||||||
:estimated-item-height="300"
|
:estimated-item-height="subscribeGridEstimatedItemHeight"
|
||||||
|
:gap="subscribeGridGap"
|
||||||
:scroll-to-index="scrollToIndex"
|
:scroll-to-index="scrollToIndex"
|
||||||
class="px-2"
|
class="px-2"
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user