feat: 更新多个组件的背景样式为透明度背景

This commit is contained in:
jxxghp
2026-08-09 12:35:09 +08:00
parent 4b70b98ffc
commit f080da1ebb
7 changed files with 51 additions and 29 deletions
+1 -1
View File
@@ -593,7 +593,7 @@ onBeforeUnmount(() => {
.media-card-placeholder { .media-card-placeholder {
aspect-ratio: 2 / 3; aspect-ratio: 2 / 3;
background: rgb(var(--v-theme-surface-variant)); background: rgba(var(--v-theme-on-surface), 0.08);
block-size: 100%; block-size: 100%;
inline-size: 100%; inline-size: 100%;
} }
+5 -1
View File
@@ -37,7 +37,7 @@ function goArtistDetail() {
<div style="padding-block-end: 150%"> <div style="padding-block-end: 150%">
<div class="absolute inset-0 flex h-full w-full flex-col items-center p-2"> <div class="absolute inset-0 flex h-full w-full flex-col items-center p-2">
<div class="relative mt-2 mb-4 flex h-1/2 w-full justify-center"> <div class="relative mt-2 mb-4 flex h-1/2 w-full justify-center">
<VAvatar size="100" color="surface-variant"> <VAvatar size="100" class="music-artist-card-avatar">
<VImg v-if="showImage" :src="imageUrl" cover @error="imageLoadError = true" /> <VImg v-if="showImage" :src="imageUrl" cover @error="imageLoadError = true" />
<VIcon v-else icon="mdi-account-music" size="48" color="medium-emphasis" /> <VIcon v-else icon="mdi-account-music" size="48" color="medium-emphasis" />
</VAvatar> </VAvatar>
@@ -60,6 +60,10 @@ function goArtistDetail() {
inline-size: 100%; inline-size: 100%;
} }
.music-artist-card-avatar {
background: rgba(var(--v-theme-on-surface), 0.08);
}
.music-artist-card { .music-artist-card {
background-image: linear-gradient(45deg, rgba(var(--v-theme-background), 0.3), rgba(var(--v-theme-surface), 0.3) 60%); background-image: linear-gradient(45deg, rgba(var(--v-theme-background), 0.3), rgba(var(--v-theme-surface), 0.3) 60%);
} }
+6 -4
View File
@@ -540,9 +540,10 @@ function handleCardClick() {
<template #image v-if="display.smAndUp.value"> <template #image v-if="display.smAndUp.value">
<div <div
v-if="showPlaceholder" v-if="showPlaceholder"
class="subscribe-card-placeholder d-flex align-center justify-center" class="subscribe-card-placeholder d-flex align-center justify-center relative"
> >
<VIcon :icon="placeholderIcon" size="64" color="medium-emphasis" /> <VIcon :icon="placeholderIcon" size="64" color="medium-emphasis" />
<div class="absolute inset-0 outline-none subscribe-card-background"></div>
</div> </div>
<VImg <VImg
v-else v-else
@@ -568,9 +569,10 @@ function handleCardClick() {
<div class="subscribe-card-mobile-media"> <div class="subscribe-card-mobile-media">
<div <div
v-if="showPlaceholder" v-if="showPlaceholder"
class="subscribe-card-placeholder d-flex align-center justify-center" class="subscribe-card-placeholder d-flex align-center justify-center relative"
> >
<VIcon :icon="placeholderIcon" size="64" color="medium-emphasis" /> <VIcon :icon="placeholderIcon" size="64" color="medium-emphasis" />
<div class="absolute inset-0 outline-none subscribe-card-background"></div>
</div> </div>
<VImg <VImg
v-else v-else
@@ -697,7 +699,7 @@ function handleCardClick() {
</div> </div>
</div> </div>
</VCardText> </VCardText>
<VCardText class="flex min-w-0 justify-space-between align-center flex-wrap px-3"> <VCardText class="flex min-w-0 justify-space-between align-center flex-wrap px-3 mt-auto">
<div class="flex min-w-0 max-w-full align-center"> <div class="flex min-w-0 max-w-full align-center">
<VIcon <VIcon
v-if="props.media?.total_episode && props.sortable" v-if="props.media?.total_episode && props.sortable"
@@ -976,7 +978,7 @@ function handleCardClick() {
.subscribe-card-placeholder { .subscribe-card-placeholder {
block-size: 100%; block-size: 100%;
inline-size: 100%; inline-size: 100%;
background: rgb(var(--v-theme-surface-variant)); background: rgba(var(--v-theme-on-surface), 0.08);
} }
/** /**
+26 -9
View File
@@ -14,7 +14,7 @@ import { formatFileSize } from '@/@core/utils/formatters'
import { VCardTitle, VChip } from 'vuetify/lib/components/index.mjs' import { VCardTitle, VChip } from 'vuetify/lib/components/index.mjs'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import MediaIdSelector from '../misc/MediaIdSelector.vue' import MediaIdSelector from '../misc/MediaIdSelector.vue'
import { numberValidator } from '@/@validators' import { isValidMediaSourceId } from '@/utils/mediaId'
import { useGlobalSettingsStore } from '@/stores' import { useGlobalSettingsStore } from '@/stores'
// 多语言支持 // 多语言支持
@@ -25,19 +25,25 @@ const globalSettingsStore = useGlobalSettingsStore()
const globalSettings = globalSettingsStore.globalSettings const globalSettings = globalSettingsStore.globalSettings
// 当前识别类型 // 当前识别类型
const mediaSource = ref<MediaDataSource>(
['themoviedb', 'douban', 'bangumi', 'anilist'].includes(globalSettings.RECOGNIZE_SOURCE)
? globalSettings.RECOGNIZE_SOURCE
: 'themoviedb',
)
// 输入参数
const props = defineProps({ const props = defineProps({
title: String, title: String,
media: Object as PropType<MediaInfo>, media: Object as PropType<MediaInfo>,
torrent: Object as PropType<TorrentInfo>, torrent: Object as PropType<TorrentInfo>,
}) })
// 可选的媒体数据源
const SUPPORTED_MEDIA_SOURCES: MediaDataSource[] = ['themoviedb', 'douban', 'bangumi', 'anilist', 'musicbrainz']
// 当前识别类型:优先使用媒体自身的数据源,否则使用全局识别来源
const mediaSource = computed<MediaDataSource>(() => {
const source = props.media?.source as MediaDataSource | undefined
if (source && SUPPORTED_MEDIA_SOURCES.includes(source)) return source
if (SUPPORTED_MEDIA_SOURCES.includes(globalSettings.RECOGNIZE_SOURCE as MediaDataSource)) {
return globalSettings.RECOGNIZE_SOURCE as MediaDataSource
}
return 'themoviedb'
})
// 定义成功和失败事件 // 定义成功和失败事件
const emit = defineEmits(['done', 'error', 'close']) const emit = defineEmits(['done', 'error', 'close'])
@@ -65,6 +71,17 @@ const showAdvancedOptions = ref(false)
// 当前数据源的原生媒体ID // 当前数据源的原生媒体ID
const mediaId = ref<string | undefined>(undefined) const mediaId = ref<string | undefined>(undefined)
// 音乐媒体自带 MusicBrainz ID,打开对话框时预填到高级选项中辅助识别
watch(
() => props.media,
media => {
if (media && media.source === 'musicbrainz' && media.media_id) {
mediaId.value = media.media_id
}
},
{ immediate: true },
)
// 当前数据源对应的原生ID标签。 // 当前数据源对应的原生ID标签。
const mediaIdLabel = computed(() => { const mediaIdLabel = computed(() => {
const labels: Record<MediaDataSource, string> = { const labels: Record<MediaDataSource, string> = {
@@ -302,7 +319,7 @@ onMounted(() => {
v-model="mediaId" v-model="mediaId"
:label="mediaIdLabel" :label="mediaIdLabel"
:placeholder="t('dialog.reorganize.mediaIdPlaceholder')" :placeholder="t('dialog.reorganize.mediaIdPlaceholder')"
:rules="[numberValidator]" :rules="[(value: any) => isValidMediaSourceId(value, mediaSource.value) || t('dialog.reorganize.mediaIdInvalid')]"
append-inner-icon="mdi-magnify" append-inner-icon="mdi-magnify"
:hint="t('dialog.reorganize.mediaIdHint')" :hint="t('dialog.reorganize.mediaIdHint')"
persistent-hint persistent-hint
+7 -8
View File
@@ -98,18 +98,17 @@ watch(
<style lang="scss" scoped> <style lang="scss" scoped>
.vue-music-back { .vue-music-back {
z-index: 0; z-index: 0;
pointer-events: none;
background-image: background-image:
linear-gradient(180deg, rgba(var(--v-theme-background), 0) 50%, rgba(var(--v-theme-background), 1) 100%), linear-gradient(180deg, rgba(var(--v-theme-background), 0) 50%, rgba(var(--v-theme-background), 1) 100%),
linear-gradient(0deg, rgba(var(--v-theme-background), 0) 80%, rgba(var(--v-theme-background), 1) 100%), linear-gradient(0deg, rgba(var(--v-theme-background), 0) 80%, rgba(var(--v-theme-background), 1) 100%),
linear-gradient(90deg, rgba(var(--v-theme-background), 0) 50%, rgba(var(--v-theme-background), 1) 100%), linear-gradient(90deg, rgba(var(--v-theme-background), 0) 50%, rgba(var(--v-theme-background), 1) 100%),
linear-gradient(270deg, rgba(var(--v-theme-background), 0) 50%, rgba(var(--v-theme-background), 1) 100%); linear-gradient(270deg, rgba(var(--v-theme-background), 0) 50%, rgba(var(--v-theme-background), 1) 100%);
margin-block-start: calc(-70px - env(safe-area-inset-top)); margin-block-start: calc(-70px - env(safe-area-inset-top));
pointer-events: none;
} }
.vue-music-back-image { .vue-music-back-image {
background-image: none; background-image: none;
filter: blur(2px);
} }
.music-detail-transparent .vue-music-back-overlay, .music-detail-transparent .vue-music-back-overlay,
@@ -119,10 +118,10 @@ watch(
.music-detail-transparent .vue-music-back-image, .music-detail-transparent .vue-music-back-image,
.music-detail-glass .vue-music-back-image { .music-detail-glass .vue-music-back-image {
mask-composite: intersect;
mask-image: mask-image:
linear-gradient(to bottom, transparent 0%, #000 16%, #000 58%, transparent 100%), linear-gradient(to bottom, transparent 0%, #000 16%, #000 58%, transparent 100%),
linear-gradient(to right, transparent 0%, #000 10%, #000 90%, transparent 100%); linear-gradient(to right, transparent 0%, #000 10%, #000 90%, transparent 100%);
mask-composite: intersect;
opacity: 0.82; opacity: 0.82;
} }
@@ -144,9 +143,9 @@ watch(
.music-poster { .music-poster {
overflow: hidden; overflow: hidden;
flex: 0 0 auto;
border-radius: var(--app-surface-radius); border-radius: var(--app-surface-radius);
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 10%); box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 10%);
flex: 0 0 auto;
inline-size: 9rem; inline-size: 9rem;
} }
@@ -156,7 +155,7 @@ watch(
.music-poster-placeholder { .music-poster-placeholder {
aspect-ratio: 1; aspect-ratio: 1;
background: rgb(var(--v-theme-surface-variant)); background: rgba(var(--v-theme-on-surface), 0.08);
inline-size: 100%; inline-size: 100%;
} }
@@ -164,8 +163,8 @@ watch(
display: flex; display: flex;
flex: 1 1 0%; flex: 1 1 0%;
flex-direction: column; flex-direction: column;
min-inline-size: 0;
margin-block-start: 1rem; margin-block-start: 1rem;
min-inline-size: 0;
text-align: center; text-align: center;
} }
@@ -193,10 +192,10 @@ watch(
.music-actions { .music-actions {
display: flex; display: flex;
flex-wrap: wrap;
flex-shrink: 0; flex-shrink: 0;
gap: 0.5rem; flex-wrap: wrap;
justify-content: center; justify-content: center;
gap: 0.5rem;
margin-block-start: 1rem; margin-block-start: 1rem;
} }
+1 -1
View File
@@ -232,12 +232,12 @@ watch(() => [props.source, props.mediaid], loadMusicDetail, { immediate: true })
<span class="ms-1">MusicBrainz</span> <span class="ms-1">MusicBrainz</span>
</a> </a>
</div> </div>
</template>
<div v-if="albumTracks.length" class="music-section"> <div v-if="albumTracks.length" class="music-section">
<h2 class="music-section-heading">{{ t('music.albumTracks') }}</h2> <h2 class="music-section-heading">{{ t('music.albumTracks') }}</h2>
<MusicTrackList :tracks="albumTracks" :active-media-id="music.media_id" hide-artists /> <MusicTrackList :tracks="albumTracks" :active-media-id="music.media_id" hide-artists />
</div> </div>
</template>
<div v-if="primaryArtistId" class="music-section"> <div v-if="primaryArtistId" class="music-section">
<MusicArtistSlideView :apipath="`music/artist/${primaryArtistId}/related`" :title="t('music.relatedArtists')" /> <MusicArtistSlideView :apipath="`music/artist/${primaryArtistId}/related`" :title="t('music.relatedArtists')" />
+1 -1
View File
@@ -2072,7 +2072,7 @@ onUnmounted(() => {
justify-content: center; justify-content: center;
inline-size: 100%; inline-size: 100%;
block-size: 100%; block-size: 100%;
background: rgb(var(--v-theme-surface-variant)); background: rgba(var(--v-theme-on-surface), 0.08);
} }
.transfer-history-mobile-record__poster-type { .transfer-history-mobile-record__poster-type {