mirror of
https://github.com/jiangrui1994/CloudSaver.git
synced 2026-01-11 23:58:46 +08:00
830 lines
19 KiB
Vue
830 lines
19 KiB
Vue
<template>
|
||
<div ref="containerRef" class="thanks-container">
|
||
<div ref="titleRef" class="title">感谢Ta们对项目的赞赏</div>
|
||
|
||
<!-- 添加说明文字 -->
|
||
<div class="description">
|
||
<p>感谢每一位支持者的信任与鼓励</p>
|
||
<p>正是你们的支持让这个项目能够持续发展</p>
|
||
</div>
|
||
|
||
<div ref="sponsorsContainer" class="sponsors-container">
|
||
<div
|
||
v-for="(sponsor, index) in randomizedSponsors"
|
||
:key="sponsor.name"
|
||
ref="avatarRefs"
|
||
class="sponsor-avatar"
|
||
@mouseenter="handleMouseEnter(index)"
|
||
@mouseleave="handleMouseLeave"
|
||
>
|
||
<div
|
||
ref="avatarWrapperRefs"
|
||
class="avatar-wrapper"
|
||
:class="{
|
||
active: activeIndex === index,
|
||
'has-link': sponsor.link,
|
||
}"
|
||
@click="handleAvatarClick(sponsor.link)"
|
||
>
|
||
<div class="avatar-inner">
|
||
<div class="avatar-overlay"></div>
|
||
<img :src="sponsor.avatar" :alt="sponsor.name" class="avatar-img" />
|
||
<div class="name-tag">
|
||
{{ sponsor.name }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="activeIndex === index && sponsor.message" class="dialog-box">
|
||
<div class="dialog-content">
|
||
<div :id="`typeIt-${index}`" class="type-it-container"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 添加赞赏按钮 -->
|
||
<a
|
||
:href="PROJECT_GITHUB + '?tab=readme-ov-file#支持项目'"
|
||
target="_blank"
|
||
class="sponsor-button"
|
||
@mouseenter="handleButtonHover"
|
||
@mouseleave="handleButtonLeave"
|
||
>
|
||
<div class="button-content">
|
||
<svg class="heart-icon" viewBox="0 0 24 24">
|
||
<path
|
||
d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"
|
||
/>
|
||
</svg>
|
||
<span>赞赏支持</span>
|
||
</div>
|
||
</a>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted, nextTick, computed, onBeforeUnmount } from "vue";
|
||
import TypeIt from "typeit";
|
||
import { userApi } from "@/api/user";
|
||
import gsap from "gsap";
|
||
import { PROJECT_GITHUB } from "@/constants/project";
|
||
// 赞助者数据
|
||
const sponsors = ref([]);
|
||
|
||
const getSponsors = async () => {
|
||
const res = await userApi.getSponsors();
|
||
sponsors.value = res.data;
|
||
};
|
||
|
||
// 随机排序赞助者
|
||
const randomizedSponsors = computed(() => {
|
||
// 有sort的按照sort排序并排在前面,没有的按照随机排序
|
||
const sortedSponsors = [...sponsors.value]
|
||
.filter((item) => item.sort)
|
||
.sort((a, b) => a.sort - b.sort);
|
||
const randomSponsors = [...sponsors.value]
|
||
.filter((item) => !item.sort)
|
||
.sort(() => Math.random() - 0.5);
|
||
return [...sortedSponsors, ...randomSponsors];
|
||
});
|
||
|
||
const containerRef = ref(null);
|
||
const sponsorsContainer = ref(null);
|
||
const activeIndex = ref(null);
|
||
const avatarRefs = ref([]);
|
||
const avatarWrapperRefs = ref([]);
|
||
let typeItInstance = null;
|
||
const activeCenter = ref({ x: 0, y: 0 });
|
||
const titleRef = ref(null);
|
||
|
||
// 添加头像动画时间轴的引用
|
||
const avatarTimelines = ref([]);
|
||
|
||
// 使用 requestAnimationFrame 优化动画更新
|
||
let rafId = null;
|
||
|
||
// 添加一个变量来跟踪当前激活的头像
|
||
let currentHoverIndex = null;
|
||
|
||
onMounted(async () => {
|
||
await getSponsors();
|
||
|
||
// 修改页面入场动画
|
||
const tl = gsap.timeline({
|
||
defaults: { ease: "power3.out" },
|
||
});
|
||
|
||
// 同时执行所有元素的动画
|
||
tl.from([titleRef.value, sponsorsContainer.value, ...avatarWrapperRefs.value], {
|
||
y: -20,
|
||
opacity: 0,
|
||
duration: 0.6,
|
||
stagger: {
|
||
amount: 0.3,
|
||
from: "start",
|
||
},
|
||
ease: "back.out(1.2)",
|
||
});
|
||
|
||
// 添加可见性变化监听
|
||
document.addEventListener("visibilitychange", handleVisibilityChange);
|
||
|
||
// 添加窗口失焦事件处理
|
||
window.addEventListener("blur", handleMouseLeave);
|
||
});
|
||
|
||
// 修改 handleVisibilityChange 函数
|
||
const handleVisibilityChange = () => {
|
||
if (document.hidden) {
|
||
// 页面不可见时清理资源
|
||
if (typeItInstance) {
|
||
typeItInstance.destroy();
|
||
typeItInstance = null;
|
||
}
|
||
}
|
||
};
|
||
|
||
// 修改鼠标移入处理函数
|
||
const handleMouseEnter = (() => {
|
||
let timeout;
|
||
return async (index) => {
|
||
if (timeout) {
|
||
clearTimeout(timeout);
|
||
}
|
||
currentHoverIndex = index;
|
||
activeIndex.value = index;
|
||
|
||
timeout = setTimeout(async () => {
|
||
// 确保这是最新的hover状态
|
||
if (currentHoverIndex !== index) return;
|
||
|
||
const activeAvatar = avatarWrapperRefs.value[index];
|
||
if (activeAvatar) {
|
||
const rect = activeAvatar.getBoundingClientRect();
|
||
activeCenter.value = {
|
||
x: rect.left + rect.width / 2,
|
||
y: rect.top + rect.height / 2,
|
||
};
|
||
}
|
||
|
||
// 暂停所有浮动动画
|
||
avatarTimelines.value.forEach((timeline) => {
|
||
if (timeline) {
|
||
timeline.pause();
|
||
}
|
||
});
|
||
|
||
updateAvatarsEffect(index);
|
||
|
||
await nextTick();
|
||
|
||
try {
|
||
// 初始化打字效果
|
||
if (typeItInstance) {
|
||
typeItInstance.destroy();
|
||
typeItInstance = null;
|
||
}
|
||
|
||
const typeItElement = document.getElementById(`typeIt-${index}`);
|
||
if (typeItElement) {
|
||
typeItInstance = new TypeIt(typeItElement, {
|
||
strings: randomizedSponsors.value[index].message,
|
||
speed: 20,
|
||
waitUntilVisible: true,
|
||
}).go();
|
||
}
|
||
} catch (error) {
|
||
console.error("TypeIt初始化错误:", error);
|
||
}
|
||
}, 16);
|
||
};
|
||
})();
|
||
|
||
// 更新所有头像效果
|
||
const updateAvatarsEffect = (activeIndex) => {
|
||
if (!avatarWrapperRefs.value || activeCenter.value.x === 0) return;
|
||
|
||
if (rafId) {
|
||
cancelAnimationFrame(rafId);
|
||
}
|
||
|
||
rafId = requestAnimationFrame(() => {
|
||
avatarWrapperRefs.value.forEach((wrapper, index) => {
|
||
const inner = wrapper.querySelector(".avatar-inner");
|
||
const avatarContainer = wrapper.closest(".sponsor-avatar");
|
||
|
||
if (index === activeIndex) {
|
||
gsap.to(inner, {
|
||
scale: 1.2,
|
||
y: -15,
|
||
zIndex: 10,
|
||
duration: 0.2,
|
||
ease: "back.out(1.5)",
|
||
force3D: true,
|
||
});
|
||
|
||
gsap.to(avatarContainer, {
|
||
filter: "drop-shadow(0 20px 30px rgba(0, 0, 0, 0.25))",
|
||
duration: 0.2,
|
||
});
|
||
|
||
const activeOverlay = wrapper.querySelector(".avatar-overlay");
|
||
gsap.to(activeOverlay, {
|
||
opacity: 0,
|
||
duration: 0.15,
|
||
});
|
||
return;
|
||
}
|
||
|
||
const rect = wrapper.getBoundingClientRect();
|
||
const centerX = rect.left + rect.width / 2;
|
||
const centerY = rect.top + rect.height / 2;
|
||
const deltaX = activeCenter.value.x - centerX;
|
||
const deltaY = activeCenter.value.y - centerY;
|
||
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||
|
||
if (distance < 0.1) return;
|
||
|
||
const maxDistance = 400;
|
||
const strength = Math.max(0, 1 - distance / maxDistance);
|
||
|
||
// 计算吸引力效果
|
||
const attractionStrength = Math.pow(strength, 1.5);
|
||
const moveX = (deltaX / distance) * 30 * attractionStrength;
|
||
const moveY = (deltaY / distance) * 30 * attractionStrength;
|
||
|
||
// 计算旋转角度
|
||
const rotateX = -Math.atan2(deltaY, distance) * (180 / Math.PI) * strength;
|
||
const rotateY = Math.atan2(deltaX, distance) * (180 / Math.PI) * strength;
|
||
|
||
// 应用变换效果
|
||
gsap.to(inner, {
|
||
scale: 1 + 0.05 * strength,
|
||
x: moveX,
|
||
y: moveY,
|
||
rotationX: rotateX,
|
||
rotationY: rotateY,
|
||
duration: 0.2,
|
||
ease: "power2.out",
|
||
force3D: true,
|
||
});
|
||
|
||
// 更新阴影效果
|
||
const shadowOffsetX = (deltaX / distance) * 15 * strength;
|
||
const shadowOffsetY = Math.max(6, (deltaY / distance) * 20 * strength + 6);
|
||
const shadowBlur = 12 + 18 * strength;
|
||
const shadowOpacity = 0.15 + 0.1 * strength;
|
||
|
||
gsap.to(avatarContainer, {
|
||
filter: `drop-shadow(${shadowOffsetX}px ${shadowOffsetY}px ${shadowBlur}px rgba(0, 0, 0, ${shadowOpacity}))`,
|
||
duration: 0.2,
|
||
});
|
||
});
|
||
});
|
||
};
|
||
|
||
// 修改鼠标移出处理函数
|
||
const handleMouseLeave = () => {
|
||
currentHoverIndex = null;
|
||
activeIndex.value = null;
|
||
activeCenter.value = { x: 0, y: 0 };
|
||
|
||
if (!avatarWrapperRefs.value) return;
|
||
|
||
avatarWrapperRefs.value.forEach((wrapper) => {
|
||
const inner = wrapper.querySelector(".avatar-inner");
|
||
if (inner) {
|
||
gsap.killTweensOf(inner);
|
||
|
||
gsap.to(inner, {
|
||
scale: 1,
|
||
y: 0,
|
||
x: 0,
|
||
rotation: 0,
|
||
rotationX: 0,
|
||
rotationY: 0,
|
||
duration: 0.2,
|
||
ease: "power2.out",
|
||
});
|
||
}
|
||
|
||
const avatarContainer = wrapper.closest(".sponsor-avatar");
|
||
if (avatarContainer) {
|
||
gsap.killTweensOf(avatarContainer);
|
||
|
||
gsap.to(avatarContainer, {
|
||
filter: "drop-shadow(0 6px 12px rgba(0, 0, 0, 0.15))",
|
||
duration: 0.2,
|
||
});
|
||
}
|
||
|
||
const overlayElement = wrapper.querySelector(".avatar-overlay");
|
||
if (overlayElement) {
|
||
gsap.to(overlayElement, {
|
||
opacity: 1,
|
||
duration: 0.15,
|
||
});
|
||
}
|
||
});
|
||
|
||
if (typeItInstance) {
|
||
typeItInstance.destroy();
|
||
typeItInstance = null;
|
||
}
|
||
};
|
||
|
||
// 添加点击处理函数
|
||
const handleAvatarClick = (link) => {
|
||
if (link) {
|
||
window.open(link, "_blank");
|
||
}
|
||
};
|
||
|
||
// 组件卸载时清理
|
||
onBeforeUnmount(() => {
|
||
window.removeEventListener("blur", handleMouseLeave);
|
||
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
||
|
||
// 清理打字实例
|
||
if (typeItInstance) {
|
||
typeItInstance.destroy();
|
||
typeItInstance = null;
|
||
}
|
||
});
|
||
|
||
// 添加按钮悬浮效果
|
||
const handleButtonHover = () => {
|
||
gsap.to(".sponsor-button", {
|
||
scale: 1.05,
|
||
duration: 0.3,
|
||
ease: "power2.out",
|
||
});
|
||
};
|
||
|
||
const handleButtonLeave = () => {
|
||
gsap.to(".sponsor-button", {
|
||
scale: 1,
|
||
duration: 0.3,
|
||
ease: "power2.out",
|
||
});
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.thanks-container {
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
height: calc(100vh - 100px);
|
||
overflow: auto;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 40px 20px;
|
||
background: linear-gradient(135deg, #f6f8fd 0%, #f1f4f9 100%);
|
||
position: relative;
|
||
z-index: 1;
|
||
transform: translateZ(0);
|
||
will-change: transform;
|
||
backface-visibility: hidden;
|
||
}
|
||
|
||
.gradient-circle {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
filter: blur(40px);
|
||
opacity: 0.5;
|
||
will-change: transform;
|
||
backface-visibility: hidden;
|
||
transform: translateZ(0);
|
||
}
|
||
|
||
.circle-1 {
|
||
width: 600px;
|
||
height: 600px;
|
||
background: linear-gradient(45deg, rgba(142, 68, 173, 0.2), rgba(91, 177, 235, 0.2));
|
||
top: -200px;
|
||
left: -200px;
|
||
}
|
||
|
||
.circle-2 {
|
||
width: 500px;
|
||
height: 500px;
|
||
background: linear-gradient(45deg, rgba(91, 177, 235, 0.2), rgba(142, 68, 173, 0.2));
|
||
bottom: -150px;
|
||
right: -150px;
|
||
}
|
||
|
||
.circle-3 {
|
||
width: 400px;
|
||
height: 400px;
|
||
background: linear-gradient(45deg, rgba(241, 196, 15, 0.1), rgba(142, 68, 173, 0.1));
|
||
top: 40%;
|
||
left: 30%;
|
||
}
|
||
|
||
/* 装饰层 */
|
||
.decoration-layer {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
pointer-events: none;
|
||
z-index: 0;
|
||
}
|
||
|
||
.floating-dot {
|
||
position: absolute;
|
||
width: 6px;
|
||
height: 6px;
|
||
background: rgba(142, 68, 173, 0.2);
|
||
border-radius: 50%;
|
||
animation: floatingDot 8s ease-in-out infinite;
|
||
animation-delay: var(--delay);
|
||
will-change: transform;
|
||
backface-visibility: hidden;
|
||
transform: translateZ(0);
|
||
}
|
||
|
||
@keyframes floatingDot {
|
||
0%,
|
||
100% {
|
||
transform: translate(0, 0);
|
||
}
|
||
25% {
|
||
transform: translate(100px, 50px);
|
||
}
|
||
50% {
|
||
transform: translate(50px, 100px);
|
||
}
|
||
75% {
|
||
transform: translate(-50px, 50px);
|
||
}
|
||
}
|
||
|
||
.title {
|
||
margin-bottom: 20px;
|
||
font-size: 50px;
|
||
color: #2c3e50;
|
||
text-align: center;
|
||
font-weight: 700;
|
||
background: linear-gradient(45deg, #8e44ad, #3498db);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
|
||
letter-spacing: 1px;
|
||
will-change: transform, opacity;
|
||
backface-visibility: hidden;
|
||
transform: translateZ(0);
|
||
}
|
||
|
||
.sponsors-container {
|
||
width: 70%;
|
||
max-width: 1200px;
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||
grid-gap: 40px;
|
||
justify-content: center;
|
||
padding: 20px;
|
||
will-change: transform, opacity;
|
||
backface-visibility: hidden;
|
||
transform: translateZ(0);
|
||
opacity: 1; /* 确保容器默认可见 */
|
||
}
|
||
|
||
.sponsor-avatar {
|
||
position: relative;
|
||
transform-style: preserve-3d;
|
||
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||
z-index: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding-bottom: 20px;
|
||
filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.15));
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.avatar-wrapper {
|
||
width: 80px;
|
||
height: 80px;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.avatar-inner {
|
||
width: 100% !important;
|
||
height: 100% !important;
|
||
border-radius: 50%;
|
||
border: 4px solid #ffffff;
|
||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||
transition:
|
||
transform 0.2s ease,
|
||
filter 0.2s ease;
|
||
cursor: pointer;
|
||
position: relative;
|
||
isolation: isolate;
|
||
transform-style: preserve-3d;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.avatar-overlay {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
border-radius: 50%;
|
||
overflow: hidden;
|
||
background: linear-gradient(
|
||
135deg,
|
||
rgba(255, 255, 255, 0.2) 0%,
|
||
rgba(255, 255, 255, 0) 50%,
|
||
rgba(0, 0, 0, 0.1) 100%
|
||
);
|
||
opacity: 1;
|
||
transition: all 0.3s ease;
|
||
pointer-events: none;
|
||
z-index: 3;
|
||
mix-blend-mode: overlay; /* 添加混合模式增强效果 */
|
||
}
|
||
|
||
.avatar-wrapper.active .avatar-inner {
|
||
transform: scale(1.2) translateY(-10px);
|
||
}
|
||
|
||
.avatar-wrapper.has-link {
|
||
position: relative;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.avatar-wrapper.has-link::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -4px;
|
||
border-radius: 50%;
|
||
background: linear-gradient(45deg, #ff3366, #ff6b6b, #4ecdc4, #45b7d1, #96e6a1);
|
||
opacity: 0;
|
||
transition: opacity 0.3s ease;
|
||
z-index: -1;
|
||
filter: blur(8px);
|
||
}
|
||
|
||
.avatar-wrapper.has-link:hover::before {
|
||
opacity: 0.8;
|
||
animation: borderGlow 2s linear infinite;
|
||
}
|
||
|
||
.glow-effect {
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: 50%;
|
||
background: transparent;
|
||
border: 2px solid transparent;
|
||
transition: all 0.3s ease;
|
||
z-index: 2;
|
||
}
|
||
|
||
.avatar-wrapper.has-link:hover .glow-effect {
|
||
border-color: rgba(255, 255, 255, 0.5);
|
||
box-shadow:
|
||
0 0 20px rgba(255, 255, 255, 0.3),
|
||
inset 0 0 20px rgba(255, 255, 255, 0.3);
|
||
}
|
||
|
||
@keyframes borderGlow {
|
||
0% {
|
||
transform: rotate(0deg);
|
||
}
|
||
100% {
|
||
transform: rotate(360deg);
|
||
}
|
||
}
|
||
|
||
/* 确保激活状态下的发光效果仍然可见 */
|
||
.avatar-wrapper.active.has-link::before {
|
||
z-index: -1;
|
||
}
|
||
|
||
.avatar-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: 50%;
|
||
overflow: hidden;
|
||
object-fit: cover;
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
|
||
.dialog-box {
|
||
position: absolute;
|
||
top: -120px; /* 稍微上调对话框位置 */
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
background: rgba(255, 255, 255, 0.95);
|
||
backdrop-filter: blur(8px);
|
||
padding: 16px 20px;
|
||
border-radius: 16px;
|
||
box-shadow:
|
||
0 4px 24px -1px rgba(0, 0, 0, 0.1),
|
||
0 2px 8px -1px rgba(0, 0, 0, 0.06),
|
||
inset 0 0 0 1px rgba(255, 255, 255, 0.5),
|
||
0 0 40px rgba(142, 68, 173, 0.05);
|
||
min-width: 180px;
|
||
z-index: 111;
|
||
opacity: 0;
|
||
animation: dialogFadeIn 0.25s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
||
border: 1px solid rgba(0, 0, 0, 0.05);
|
||
will-change: transform, opacity;
|
||
backface-visibility: hidden;
|
||
transform: translateZ(0);
|
||
}
|
||
|
||
.dialog-content {
|
||
position: relative;
|
||
font-size: 15px;
|
||
line-height: 1.6;
|
||
color: #2c3e50;
|
||
margin: 0;
|
||
text-align: center;
|
||
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
|
||
}
|
||
|
||
/* 修改引号装饰的样式 */
|
||
.dialog-content::before,
|
||
.dialog-content::after {
|
||
content: '"';
|
||
position: absolute;
|
||
font-size: 28px;
|
||
color: #8e44ad;
|
||
opacity: 0.15;
|
||
text-shadow: none;
|
||
}
|
||
|
||
.dialog-content::before {
|
||
left: -15px;
|
||
top: -12px;
|
||
}
|
||
|
||
.dialog-content::after {
|
||
right: -15px;
|
||
bottom: -24px;
|
||
}
|
||
|
||
/* 优化淡入动画,使其更加流畅 */
|
||
@keyframes dialogFadeIn {
|
||
0% {
|
||
opacity: 0;
|
||
transform: translateX(-50%) translateY(10px) scale(0.98);
|
||
filter: blur(1px);
|
||
}
|
||
100% {
|
||
opacity: 1;
|
||
transform: translateX(-50%) translateY(0) scale(1);
|
||
filter: blur(0);
|
||
}
|
||
}
|
||
|
||
/* 优化打字效果容器样式 */
|
||
.type-it-container {
|
||
min-height: 24px;
|
||
padding: 4px 8px;
|
||
position: relative;
|
||
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0));
|
||
border-radius: 8px;
|
||
}
|
||
|
||
/* 添加打字光标样式 */
|
||
.ti-cursor {
|
||
color: #8e44ad;
|
||
font-weight: 300;
|
||
}
|
||
|
||
.name-tag {
|
||
position: absolute;
|
||
bottom: -10px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
text-align: center;
|
||
color: #2c3e50;
|
||
opacity: 1;
|
||
font-weight: 500;
|
||
font-size: 12px;
|
||
z-index: 20;
|
||
background-color: #fff;
|
||
border-radius: 15px;
|
||
padding: 0px 10px;
|
||
white-space: nowrap; /* 防止文字换行 */
|
||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
/* 添加新的样式 */
|
||
.description {
|
||
text-align: center;
|
||
margin-bottom: 40px;
|
||
color: #666;
|
||
line-height: 1.6;
|
||
max-width: 600px;
|
||
margin-inline: auto;
|
||
}
|
||
|
||
.description p {
|
||
margin: 8px 0;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.bottom-text {
|
||
text-align: center;
|
||
margin-top: 60px;
|
||
color: #666;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.bottom-text p {
|
||
margin: 8px 0;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.sponsor-button {
|
||
position: fixed;
|
||
bottom: 40px;
|
||
right: 40px;
|
||
background: linear-gradient(45deg, #ff3366, #ff6b6b);
|
||
color: white;
|
||
padding: 12px 24px;
|
||
border-radius: 30px;
|
||
text-decoration: none;
|
||
font-weight: 500;
|
||
font-size: 16px;
|
||
box-shadow:
|
||
0 4px 15px rgba(255, 51, 102, 0.3),
|
||
0 2px 8px rgba(255, 51, 102, 0.2);
|
||
transition: all 0.3s ease;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.sponsor-button:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow:
|
||
0 6px 20px rgba(255, 51, 102, 0.4),
|
||
0 3px 10px rgba(255, 51, 102, 0.3);
|
||
}
|
||
|
||
.button-content {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.heart-icon {
|
||
width: 20px;
|
||
height: 20px;
|
||
fill: currentColor;
|
||
animation: heartBeat 1.2s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes heartBeat {
|
||
0% {
|
||
transform: scale(1);
|
||
}
|
||
14% {
|
||
transform: scale(1.3);
|
||
}
|
||
28% {
|
||
transform: scale(1);
|
||
}
|
||
42% {
|
||
transform: scale(1.3);
|
||
}
|
||
70% {
|
||
transform: scale(1);
|
||
}
|
||
}
|
||
|
||
/* 添加响应式样式 */
|
||
@media (max-width: 768px) {
|
||
.sponsor-button {
|
||
bottom: 20px;
|
||
right: 20px;
|
||
padding: 10px 20px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.description,
|
||
.bottom-text {
|
||
padding: 0 20px;
|
||
}
|
||
}
|
||
|
||
/* 添加悬浮状态的阴影效果 */
|
||
.sponsor-avatar:hover {
|
||
filter: drop-shadow(0 8px 12px rgba(0, 0, 0, 0.15));
|
||
}
|
||
|
||
/* 修改激活状态的阴影效果 */
|
||
.sponsor-avatar:has(.avatar-wrapper.active) {
|
||
filter: drop-shadow(0 15px 25px rgba(0, 0, 0, 0.2));
|
||
}
|
||
</style>
|