Files
AlgerMusicPlayer/src/renderer/components/lyric/MusicFull.vue
T
alger 5ba9e6591a refactor(lyric): 抽取全屏背景/文字颜色逻辑为 useLyricBackground composable
MusicFull.vue 与 MusicFullMobile.vue 各自持有的 setTextColors /
currentBackground / animationFrame / isDark 合并到共享 composable,
消除两份几乎一致的包装逻辑。Mobile 的 --bg-color 差异通过 writeBgColor
option 注入,行为等价。
2026-05-10 12:34:53 +08:00

1004 lines
26 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<n-drawer
v-model:show="isVisible"
height="100%"
placement="bottom"
:style="drawerBaseStyle"
:to="`#layout-main`"
:z-index="9998"
>
<!-- 背景层用于图片模糊和明暗效果 -->
<div
v-if="
config.useCustomBackground && config.backgroundMode === 'image' && config.backgroundImage
"
class="background-layer"
:style="backgroundImageStyle"
></div>
<div id="drawer-target" :class="[config.theme]" class="relative z-10">
<!-- 左侧关闭按钮 -->
<div
class="control-left absolute top-8 left-8 z-[9999]"
:class="{ 'pure-mode': config.pureModeEnabled }"
>
<div class="control-btn" @click="closeMusicFull">
<i class="ri-arrow-down-s-line"></i>
</div>
</div>
<!-- 右侧功能按钮组 -->
<div
class="control-right absolute top-8 right-8 z-[9999]"
:class="{ 'pure-mode': config.pureModeEnabled }"
>
<n-popover trigger="click" placement="bottom" raw>
<template #trigger>
<div class="control-btn">
<i class="ri-settings-3-line"></i>
</div>
</template>
<lyric-settings ref="lyricSettingsRef" />
</n-popover>
<div class="control-btn" @click="toggleFullScreen">
<i :class="isFullScreen ? 'ri-fullscreen-exit-line' : 'ri-fullscreen-line'"></i>
</div>
</div>
<div class="content-wrapper" :style="{ width: `${config.contentWidth}%` }">
<!-- 左侧:封面区域 -->
<div
v-if="!config.hideCover"
class="left-side"
:class="{ 'only-cover': config.hideLyrics }"
>
<div class="img-container">
<cover3-d
ref="PicImgRef"
:src="getImgUrl(playMusic?.picUrl, '500y500')"
:loading="playMusic?.playLoading"
:max-tilt="12"
:scale="1.03"
:shine-intensity="0.25"
/>
</div>
<div class="music-info">
<div class="music-content-name" v-html="playMusic.name"></div>
<div class="music-content-singer">
<n-ellipsis
class="text-ellipsis"
line-clamp="2"
:tooltip="{
contentStyle: { maxWidth: '600px' },
zIndex: 99999
}"
>
<span
v-for="(item, index) in artistList"
:key="index"
class="cursor-pointer hover:text-green-500"
@click="handleArtistClick(item.id)"
>
{{ item.name }}
{{ index < artistList.length - 1 ? ' / ' : '' }}
</span>
</n-ellipsis>
</div>
<simple-play-bar
v-if="!config.hideMiniPlayBar"
class="mt-4"
:pure-mode-enabled="config.pureModeEnabled"
:isDark="textColors.theme === 'dark'"
/>
</div>
</div>
<!-- 右侧:歌词区域 -->
<div
class="right-side"
:class="{
center: config.centerLyrics,
hide: config.hideLyrics,
'full-width': config.hideCover
}"
>
<n-layout
ref="lrcSider"
class="music-lrc"
:native-scrollbar="false"
@mouseover="mouseOverLayout"
@mouseleave="mouseLeaveLayout"
>
<!-- 歌曲信息 -->
<div class="music-lrc-container">
<div
v-if="config.hideCover"
class="music-info-header"
:style="{ textAlign: config.centerLyrics ? 'center' : 'left' }"
>
<div class="music-info-name" v-html="playMusic.name"></div>
<div class="music-info-singer">
<span
v-for="(item, index) in artistList"
:key="index"
class="cursor-pointer hover:text-green-500"
@click="handleArtistClick(item.id)"
>
{{ item.name }}
{{ index < artistList.length - 1 ? ' / ' : '' }}
</span>
</div>
</div>
<!-- 无时间戳歌词提示 -->
<div v-if="!supportAutoScroll" class="music-lrc-text no-scroll-tip">
<span>{{ t('player.lrc.noAutoScroll') }}</span>
</div>
<div
v-for="(item, index) in lrcArray"
:id="`music-lrc-text-${index}`"
:key="index"
class="music-lrc-text"
:class="{
'now-text': index === nowIndex,
'hover-text': item.text && item.startTime !== -1
}"
@click="item.startTime !== -1 ? setAudioTime(index) : null"
>
<!-- 逐字歌词显示 -->
<div
v-if="item.hasWordByWord && item.words && item.words.length > 0"
class="word-by-word-lyric"
>
<template v-for="(word, wordIndex) in item.words" :key="wordIndex">
<span class="lyric-word" :style="getWordStyle(index, wordIndex, word)">
{{ word.text }} </span
><span class="lyric-word" v-if="word.space">&nbsp;</span></template
>
</div>
<!-- 普通歌词显示 -->
<span v-else :style="getLrcStyle(index)">{{ item.text }}</span>
<div v-show="config.showTranslation" class="music-lrc-text-tr">
{{ item.trText }}
</div>
</div>
<!-- 无歌词 -->
<div v-if="!lrcArray.length" class="music-lrc-text">
<span>{{ t('player.lrc.noLrc') }}</span>
</div>
</div>
<!-- 歌词右下角矫正按钮组件 -->
<lyric-correction-control
v-if="!isMobile"
:correction-time="correctionTime"
@adjust="adjustCorrectionTime"
/>
</n-layout>
</div>
</div>
</div>
</n-drawer>
</template>
<script setup lang="ts">
import { useDebounceFn } from '@vueuse/core';
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import Cover3D from '@/components/cover/Cover3D.vue';
import LyricCorrectionControl from '@/components/lyric/LyricCorrectionControl.vue';
import LyricSettings from '@/components/lyric/LyricSettings.vue';
import SimplePlayBar from '@/components/player/SimplePlayBar.vue';
import {
adjustCorrectionTime,
artistList,
correctionTime,
lrcArray,
nowIndex,
nowTime,
playMusic,
setAudioTime,
textColors,
useLyricProgress
} from '@/hooks/MusicHook';
import { useArtist } from '@/hooks/useArtist';
import { useLyricBackground } from '@/hooks/useLyricBackground';
import { usePlayerStore } from '@/store/modules/player';
import { useSettingsStore } from '@/store/modules/settings';
import { DEFAULT_LYRIC_CONFIG, LyricConfig } from '@/types/lyric';
import { getImgUrl, isMobile } from '@/utils';
import { getTextColors } from '@/utils/linearColor';
const { t } = useI18n();
// 定义 refs
const lrcSider = ref<any>(null);
const isMouse = ref(false);
const { currentBackground, applyBackground } = useLyricBackground();
// 计算自定义背景样式
const customBackgroundStyle = computed(() => {
if (!config.value.useCustomBackground) {
return null;
}
switch (config.value.backgroundMode) {
case 'solid':
return config.value.solidColor;
case 'gradient': {
const { colors, direction } = config.value.gradientColors;
return `linear-gradient(${direction}, ${colors.join(', ')})`;
}
case 'image':
if (!config.value.backgroundImage) return null;
// 构建完整的背景样式,包括滤镜效果
return config.value.backgroundImage;
case 'css':
return config.value.customCss || null;
default:
return null;
}
});
// drawer 基础样式(非图片模式)
const drawerBaseStyle = computed(() => {
// 图片模式时不设置背景,使用单独的背景层
if (config.value.useCustomBackground && config.value.backgroundMode === 'image') {
return { background: 'transparent' };
}
// 其他模式正常设置背景
if (config.value.useCustomBackground && customBackgroundStyle.value) {
return { background: customBackgroundStyle.value };
}
return { background: currentBackground.value || props.background };
});
// 背景图片层样式(只在图片模式下使用)
const backgroundImageStyle = computed(() => {
const blur = config.value.imageBlur || 0;
const brightness = config.value.imageBrightness || 100;
return {
backgroundImage: `url(${config.value.backgroundImage})`,
filter: `blur(${blur}px) brightness(${brightness}%)`
};
});
const showStickyHeader = ref(false);
const lyricSettingsRef = ref<InstanceType<typeof LyricSettings>>();
const isSongChanging = ref(false);
const isFullScreen = ref(false);
const config = ref<LyricConfig>({ ...DEFAULT_LYRIC_CONFIG });
watch(
() => lyricSettingsRef.value?.config,
(newConfig) => {
if (newConfig) {
config.value = newConfig;
}
},
{ deep: true, immediate: true }
);
// 监听本地配置变化,保存到 localStorage
watch(
() => config.value,
(newConfig) => {
localStorage.setItem('music-full-config', JSON.stringify(newConfig));
if (lyricSettingsRef.value) {
lyricSettingsRef.value.config = newConfig;
}
},
{ deep: true }
);
const supportAutoScroll = computed(() => {
return lrcArray.value.length > 0 && lrcArray.value[0].startTime !== -1;
});
const props = defineProps({
modelValue: {
type: Boolean,
default: false
},
background: {
type: String,
default: ''
}
});
const themeMusic = {
light: 'linear-gradient(to bottom, #ffffff, #f5f5f5)',
dark: 'linear-gradient(to bottom, #1a1a1a, #000000)'
};
const emit = defineEmits(['update:modelValue']);
const isVisible = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value)
});
// 歌词滚动方法
const lrcScroll = (behavior: ScrollBehavior = 'smooth', forceTop: boolean = false) => {
if (!isVisible.value || !lrcSider.value || !supportAutoScroll.value) return;
if (forceTop) {
lrcSider.value.scrollTo({
top: 0,
behavior
});
return;
}
if (isMouse.value) return;
const nowEl = document.querySelector(`#music-lrc-text-${nowIndex.value}`) as HTMLElement;
if (nowEl) {
const containerHeight = lrcSider.value.$el.clientHeight;
const elementTop = nowEl.offsetTop;
const scrollTop = elementTop - containerHeight / 2 + nowEl.clientHeight / 2;
lrcSider.value.scrollTo({
top: scrollTop,
behavior
});
}
};
const debouncedLrcScroll = useDebounceFn(lrcScroll, 200);
const mouseOverLayout = () => {
if (isMobile.value) {
return;
}
isMouse.value = true;
};
const mouseLeaveLayout = () => {
if (isMobile.value) {
return;
}
setTimeout(() => {
isMouse.value = false;
lrcScroll();
}, 2000);
};
watch(nowIndex, () => {
// 歌曲切换时不自动滚动
if (isSongChanging.value) return;
debouncedLrcScroll();
});
watch(
() => isVisible.value,
() => {
if (isVisible.value) {
nextTick(() => {
lrcScroll('instant');
});
}
}
);
const targetBackground = computed(() => {
if (config.value.useCustomBackground && customBackgroundStyle.value) {
if (typeof customBackgroundStyle.value === 'string') {
return customBackgroundStyle.value;
}
}
if (config.value.theme !== 'default') {
return themeMusic[config.value.theme] || props.background;
}
return props.background;
});
// 监听目标背景变化并更新文字颜色
watch(
targetBackground,
(newBg) => {
if (newBg) {
applyBackground(newBg);
}
},
{ immediate: true }
);
const { getLrcStyle: originalLrcStyle } = useLyricProgress();
const getLrcStyle = (index: number) => {
const colors = textColors.value || getTextColors();
const originalStyle = originalLrcStyle(index);
if (index === nowIndex.value) {
// 当前播放的歌词
if (originalStyle.backgroundImage) {
// 有渐变进度时,使用渐变效果
return {
...originalStyle,
backgroundImage: originalStyle.backgroundImage
.replace(/#ffffff/g, colors.active)
.replace(/#ffffff8a/g, `${colors.primary}`),
backgroundClip: 'text',
WebkitBackgroundClip: 'text',
color: 'transparent'
};
} else {
return {
color: colors.primary
};
}
}
// 非当前播放的歌词,使用普通颜色
return {
color: colors.primary
};
};
// 逐字歌词样式函数
const getWordStyle = (lineIndex: number, _wordIndex: number, word: any) => {
const colors = textColors.value || getTextColors();
// 如果不是当前行,返回普通样式
if (lineIndex !== nowIndex.value) {
return {
color: colors.primary,
transition: 'color 0.3s ease',
// 重置背景相关属性
backgroundImage: 'none',
WebkitTextFillColor: 'initial'
};
}
// 当前行的逐字效果,应用歌词矫正时间
const currentTime = (nowTime.value + correctionTime.value) * 1000; // 转换为毫秒,确保与word时间单位一致
// 直接使用绝对时间比较
const wordStartTime = word.startTime; // 单词开始的绝对时间(毫秒)
const wordEndTime = word.startTime + word.duration;
if (currentTime >= wordStartTime && currentTime < wordEndTime) {
// 当前正在播放的单词 - 使用渐变进度效果
const progress = Math.min((currentTime - wordStartTime) / word.duration, 1);
const progressPercent = Math.round(progress * 100);
return {
backgroundImage: `linear-gradient(to right, ${colors.active} 0%, ${colors.active} ${progressPercent}%, ${colors.primary} ${progressPercent}%, ${colors.primary} 100%)`,
backgroundClip: 'text',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
textShadow: `0 0 8px ${colors.active}40`,
transition: 'all 0.1s ease'
};
} else if (currentTime >= wordEndTime) {
// 已经播放过的单词 - 纯色显示
return {
color: colors.active,
WebkitTextFillColor: 'initial',
transition: 'none'
};
} else {
// 还未播放的单词 - 普通状态
return {
color: colors.primary,
WebkitTextFillColor: 'initial',
transition: 'none'
};
}
};
const settingsStore = useSettingsStore();
const { navigateToArtist } = useArtist();
const handleArtistClick = (id: number) => {
isVisible.value = false;
navigateToArtist(id);
};
const setData = computed(() => settingsStore.setData);
// 监听字体变化并更新 CSS 变量
watch(
() => [setData.value.fontFamily, setData.value.fontScope],
([newFont, fontScope]) => {
const defaultFonts =
'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
// 如果不是歌词模式或全局模式,使用默认字体
if (fontScope !== 'lyric' && fontScope !== 'global') {
document.documentElement.style.setProperty('--current-font-family', defaultFonts);
return;
}
if (newFont === 'system-ui') {
document.documentElement.style.setProperty('--current-font-family', defaultFonts);
} else {
// 处理多个字体,确保每个字体名都被正确引用
const fontList = newFont.split(',').map((font) => {
const trimmedFont = font.trim();
// 如果字体名包含空格或特殊字符,添加引号(如果还没有引号的话)
return /[\s'"()]/.test(trimmedFont) && !/^['"].*['"]$/.test(trimmedFont)
? `"${trimmedFont}"`
: trimmedFont;
});
// 将选择的字体和默认字体组合
document.documentElement.style.setProperty(
'--current-font-family',
`${fontList.join(', ')}, ${defaultFonts}`
);
}
},
{ immediate: true }
);
// 监听滚动事件
const handleScroll = () => {
if (!lrcSider.value || !config.value.hideCover) return;
const { scrollTop } = lrcSider.value.$el;
showStickyHeader.value = scrollTop > 100;
};
const playerStore = usePlayerStore();
const closeMusicFull = () => {
// 退出全屏模式
if (isFullScreen.value && document.fullscreenElement) {
document.exitFullscreen();
}
isVisible.value = false;
playerStore.setMusicFull(false);
};
// 全屏切换方法
const toggleFullScreen = async () => {
try {
if (!document.fullscreenElement) {
// 进入全屏
await document.documentElement.requestFullscreen();
isFullScreen.value = true;
} else {
// 退出全屏
await document.exitFullscreen();
isFullScreen.value = false;
}
} catch (error) {
console.error('全屏切换失败:', error);
}
};
// 监听全屏状态变化
const handleFullScreenChange = () => {
isFullScreen.value = !!document.fullscreenElement;
};
// 添加滚动监听和全屏状态监听
onMounted(() => {
if (lrcSider.value?.$el) {
lrcSider.value.$el.addEventListener('scroll', handleScroll);
}
document.addEventListener('fullscreenchange', handleFullScreenChange);
});
// 移除滚动监听和全屏状态监听
onBeforeUnmount(() => {
if (lrcSider.value?.$el) {
lrcSider.value.$el.removeEventListener('scroll', handleScroll);
}
document.removeEventListener('fullscreenchange', handleFullScreenChange);
// 退出全屏模式
if (document.fullscreenElement) {
document.exitFullscreen();
}
});
// 监听字体大小变化
watch(
() => config.value.fontSize,
(newSize) => {
document.documentElement.style.setProperty('--lyric-font-size', `${newSize}px`);
}
);
// 监听字体粗细变化
watch(
() => config.value.fontWeight,
(newWeight) => {
document.documentElement.style.setProperty('--lyric-font-weight', newWeight.toString());
}
);
// 添加文字间距监听
watch(
() => config.value.letterSpacing,
(newSpacing) => {
document.documentElement.style.setProperty('--lyric-letter-spacing', `${newSpacing}px`);
}
);
// 添加行高监听
watch(
() => config.value.lineHeight,
(newLineHeight) => {
document.documentElement.style.setProperty('--lyric-line-height', newLineHeight.toString());
}
);
// 加载保存的配置
onMounted(() => {
const savedConfig = localStorage.getItem('music-full-config');
if (savedConfig) {
config.value = { ...config.value, ...JSON.parse(savedConfig) };
}
if (lrcSider.value?.$el) {
lrcSider.value.$el.addEventListener('scroll', handleScroll);
}
});
// 添加对 playMusic.id 的监听,歌曲切换时滚动到顶部
watch(
() => playMusic.value.id,
(newId, oldId) => {
// 只在歌曲真正切换时滚动到顶部
if (newId !== oldId && newId) {
isSongChanging.value = true;
// 延迟滚动,确保 nowIndex 已重置
setTimeout(() => {
lrcScroll('instant', true);
// 延迟恢复自动滚动,等待歌词数据更新
setTimeout(() => {
isSongChanging.value = false;
}, 300);
}, 100);
}
}
);
defineExpose({
lrcScroll,
config
});
</script>
<style scoped lang="scss">
@keyframes round {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.background-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
z-index: 0;
}
.drawer-back {
@apply absolute bg-cover bg-center;
z-index: -1;
width: 200%;
height: 200%;
top: -50%;
left: -50%;
}
.drawer-back.paused {
animation-play-state: paused;
}
#drawer-target {
@apply top-0 left-0 absolute overflow-hidden rounded w-full h-full;
animation-duration: 300ms;
.content-wrapper {
@apply grid items-center mx-auto h-full;
grid-template-columns: minmax(300px, 40%) 1fr;
gap: 4rem;
max-width: 1600px;
padding: 2rem;
transition: width 0.3s ease;
@media (max-width: 1024px) {
grid-template-columns: 1fr;
grid-template-rows: auto 1fr;
gap: 2rem;
}
}
.left-side {
@apply flex flex-col items-center justify-center h-full;
transition: all 0.3s ease;
&.only-cover {
@apply col-span-2;
.img-container {
@apply w-[60vh] aspect-square;
}
.music-info {
@apply max-w-[800px];
}
}
.img-container {
@apply relative w-[45vh] mb-8 aspect-square;
max-width: 100%;
}
.music-info {
@apply w-full text-center max-w-[400px];
.music-content-name {
@apply text-3xl font-bold mb-2 line-clamp-2;
color: var(--text-color-active);
}
.music-content-singer {
@apply text-lg opacity-80;
color: var(--text-color-primary);
}
}
}
.right-side {
@apply flex flex-col justify-center h-full relative overflow-hidden;
&.full-width {
@apply col-span-2;
}
&.center {
.music-lrc {
@apply w-full mx-auto text-center;
}
.music-lrc-text {
@apply text-center;
transform-origin: center center;
}
.word-by-word-lyric {
@apply justify-center;
}
}
&.hide {
@apply hidden;
}
.music-lrc {
@apply w-full h-full bg-transparent;
mask-image: linear-gradient(
to bottom,
transparent 0%,
black 15%,
black 85%,
transparent 100%
);
-webkit-mask-image: linear-gradient(
to bottom,
transparent 0%,
black 15%,
black 85%,
transparent 100%
);
.music-info-header {
@apply mb-8;
.music-info-name {
@apply text-4xl font-bold mb-2 line-clamp-2;
color: var(--text-color-active);
}
.music-info-singer {
@apply text-xl opacity-80;
color: var(--text-color-primary);
}
}
}
.music-lrc-container {
padding: 50vh 0;
min-height: 100%;
}
.music-lrc-text {
@apply text-2xl cursor-pointer font-bold px-4 py-3;
font-family: var(--current-font-family);
font-weight: var(--lyric-font-weight, bold) !important;
transition: all 0.3s ease;
background-color: transparent;
font-size: var(--lyric-font-size, 22px) !important;
letter-spacing: var(--lyric-letter-spacing, 0) !important;
line-height: var(--lyric-line-height, 2) !important;
opacity: 0.6;
transform-origin: left center;
&.now-text {
opacity: 1;
transform: scale(1.05);
}
&.no-scroll-tip {
@apply text-base opacity-60 cursor-default py-2;
color: var(--text-color-primary);
font-weight: normal;
span {
padding-right: 0;
}
&:hover {
background-color: transparent;
}
}
span {
background-clip: text !important;
-webkit-background-clip: text !important;
padding-right: 30px;
}
&-tr {
@apply font-normal;
opacity: 0.7;
color: var(--text-color-primary);
}
// 逐字歌词样式
.word-by-word-lyric {
@apply flex flex-wrap;
.lyric-word {
@apply inline-block;
padding-right: 0;
font-weight: inherit;
font-size: inherit;
letter-spacing: inherit;
line-height: inherit;
cursor: inherit;
position: relative;
&:hover {
background-color: rgba(255, 255, 255, 0.1);
}
}
}
}
.hover-text {
&:hover {
@apply font-bold opacity-100 rounded-xl;
background-color: var(--hover-bg-color);
span {
color: var(--text-color-active) !important;
}
}
}
}
}
.mobile {
#drawer-target {
@apply p-4 pt-8;
.content-wrapper {
@apply flex-col justify-start p-0;
}
.music-img {
display: none;
}
.music-lrc {
height: calc(100vh - 260px) !important;
width: 100vw;
span {
padding-right: 0px !important;
}
.hover-text {
&:hover {
background-color: transparent;
}
}
.music-lrc-text {
@apply text-xl text-center;
}
}
.music-content {
@apply h-[calc(100vh-120px)];
width: 100vw !important;
}
}
}
.music-drawer {
transition: none; // 移除之前的过渡效果现在使用 JS 动画
}
// 添加全局字体样式
// 字体设置已移至上方或不再需要单独的 drawer-target
:root {
--current-font-family:
system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
sans-serif;
}
.close-btn {
opacity: 0.3;
transition: opacity 0.3s ease;
&:hover {
opacity: 1;
}
}
.control-left,
.control-right {
&.pure-mode {
@apply pointer-events-auto;
.control-btn {
@apply opacity-0 transition-all duration-300;
pointer-events: none;
}
&:hover .control-btn {
@apply opacity-100;
pointer-events: auto;
}
}
&:not(.pure-mode) .control-btn {
pointer-events: auto;
}
}
.control-right {
@apply flex items-center gap-2;
}
.control-btn {
@apply w-9 h-9 flex items-center justify-center rounded cursor-pointer transition-all duration-300;
background: rgba(142, 142, 142, 0.192);
backdrop-filter: blur(12px);
i {
@apply text-xl;
color: var(--text-color-active);
}
&:hover {
background: rgba(126, 121, 121, 0.2);
i {
opacity: 1;
}
}
}
.lyric-correction {
.music-lrc:hover & {
opacity: 1 !important;
pointer-events: auto !important;
}
}
</style>