feat: 迁移自定义功能至 1.5.9.9 版本

包含音乐源限制、CI 防 OOM 优化、数据库连接池优化、管理端权限及 UI 细节定制等功能
This commit is contained in:
2026-09-12 19:26:42 +08:00
parent 34f0679117
commit 1106aeea6c
161 changed files with 18963 additions and 27900 deletions
+13 -16
View File
@@ -6,29 +6,26 @@
<Transition name="entry" appear>
<div v-show="active" class="content">
<div class="label">{{ yearReview.favoriteArtist }}</div>
<div class="label">特别偏爱</div>
<p class="text-intro">{{ yearReview.topArtistIntro }}</p>
<p class="text-intro">你的年度歌手是</p>
<div class="artist-container">
<div class="artist-bg-blur" />
<h2 class="artist-name">{{ data.topArtist }}</h2>
</div>
<p class="text-desc">{{ yearReview.artistDesc }}</p>
<p class="text-desc">Ta 的声音似乎特别吸引你,<br >陪伴了你无数个日夜。</p>
</div>
</Transition>
</div>
</template>
<script setup>
import { useLocale } from '~/utils/locale'
defineProps({
data: Object,
active: Boolean
})
const { yearReview } = useLocale()
</script>
<style scoped>
@@ -40,13 +37,13 @@ const { yearReview } = useLocale()
align-items: center;
justify-content: center;
overflow: hidden;
background-color: var(--panel-bg-tertiary);
background-color: var(--surface-primary, var(--bg-primary, #1a0b2e));
}
.bg-overlay {
position: absolute;
inset: 0;
background: linear-gradient(to top, var(--bg-primary), transparent, transparent);
background: linear-gradient(to top, var(--bg-primary, #111111), transparent, transparent);
opacity: 0.8;
z-index: 10;
}
@@ -56,7 +53,7 @@ const { yearReview } = useLocale()
top: 0;
width: 100%;
height: 100%;
background: linear-gradient(to bottom, var(--color-collab-hover), var(--bg-primary));
background: linear-gradient(to bottom, #581c87, #000);
opacity: 0.5;
animation: pulse 8s infinite;
}
@@ -72,19 +69,19 @@ const { yearReview } = useLocale()
}
.label {
color: var(--color-collab-light); /* purple-300 */
color: #d8b4fe; /* purple-300 */
letter-spacing: 0.3em;
text-transform: uppercase;
margin-bottom: 1.5rem;
font-size: 0.875rem;
font-weight: 700;
border-bottom: 1px solid var(--year-review-artist-label-border);
border-bottom: 1px solid rgba(168, 85, 247, 0.3);
padding-bottom: 0.5rem;
}
.text-intro {
font-size: 1.5rem;
color: var(--text-primary-lighter);
color: #d1d5db;
font-weight: 300;
margin-bottom: 3rem;
}
@@ -101,7 +98,7 @@ const { yearReview } = useLocale()
transform: translate(-50%, -50%);
width: 120%;
height: 120%;
background: var(--year-review-artist-bg-blur);
background: rgba(168, 85, 247, 0.2);
filter: blur(60px);
border-radius: 50%;
}
@@ -112,18 +109,18 @@ const { yearReview } = useLocale()
font-weight: 900;
font-style: italic;
letter-spacing: -0.05em;
background-image: linear-gradient(to bottom right, var(--color-collab-light), var(--color-pink), var(--color-orange));
background-image: linear-gradient(to bottom right, #e9d5ff, #f472b6, #fb923c);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
filter: drop-shadow(0 25px 25px var(--mask-15));
filter: drop-shadow(0 25px 25px rgba(0, 0, 0, 0.15));
word-break: break-word;
padding: 0 0.5rem;
}
.text-desc {
margin-top: 3rem;
color: var(--text-muted);
color: #9ca3af;
max-width: 24rem;
margin-left: auto;
margin-right: auto;
+17 -20
View File
@@ -9,9 +9,9 @@
<Transition name="entry" appear>
<div v-show="active" class="content">
<span class="badge">{{ yearReview.firstSongBadge }}</span>
<span class="badge">初次相遇</span>
<p class="text-intro">{{ yearReview.firstSongIntro }}</p>
<p class="text-intro">这一年,你点的<span class="highlight">第一首歌</span>是</p>
<div class="vinyl-container">
<div class="vinyl-record">
@@ -53,17 +53,14 @@
</template>
<script setup>
import { useLocale } from '~/utils/locale'
defineProps({
data: Object,
active: Boolean
})
const { yearReview } = useLocale()
const formatDate = (dateStr) => {
const date = new Date(dateStr)
return yearReview.value.date(date.getMonth() + 1, date.getDate())
return `${date.getMonth() + 1}月${date.getDate()}日`
}
</script>
@@ -77,7 +74,7 @@ const formatDate = (dateStr) => {
align-items: center;
justify-content: center;
overflow: hidden;
background-color: var(--bg-primary);
background-color: var(--bg-primary, #111111);
}
.bg-blur {
@@ -105,25 +102,25 @@ const formatDate = (dateStr) => {
display: inline-block;
padding: 0.25rem 1rem;
border-radius: 9999px;
border: 1px solid var(--overlay-20);
background: var(--overlay-5);
border: 1px solid rgba(255, 255, 255, 0.2);
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(12px);
font-size: 0.875rem;
margin-bottom: 1.5rem;
letter-spacing: 0.1em;
color: var(--color-pink); /* brand-pink */
color: #f472b6; /* brand-pink */
font-weight: 600;
}
.text-intro {
font-size: 1.5rem;
color: var(--text-primary-lighter);
color: #d1d5db;
font-weight: 300;
margin-bottom: 2rem;
}
.highlight {
color: var(--text-primary);
color: var(--text-primary, #ffffff);
font-weight: 700;
margin: 0 0.5rem;
}
@@ -142,9 +139,9 @@ const formatDate = (dateStr) => {
height: 100%;
border-radius: 1rem;
overflow: hidden;
box-shadow: 0 25px 50px -12px var(--mask-50);
border: 1px solid var(--overlay-10);
background: var(--panel-bg-dark);
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
border: 1px solid rgba(255, 255, 255, 0.1);
background: var(--bg-secondary, #111827);
display: flex;
align-items: center;
justify-content: center;
@@ -162,13 +159,13 @@ const formatDate = (dateStr) => {
}
.placeholder-icon {
color: var(--text-muted);
color: #4b5563;
}
.glossy-overlay {
position: absolute;
inset: 0;
background: linear-gradient(to top right, var(--overlay-10), transparent);
background: linear-gradient(to top right, rgba(255, 255, 255, 0.1), transparent);
pointer-events: none;
}
@@ -184,12 +181,12 @@ const formatDate = (dateStr) => {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--text-primary);
color: var(--text-primary, #ffffff);
}
.song-artist {
font-size: 1.125rem;
color: var(--text-muted);
color: #9ca3af;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -198,7 +195,7 @@ const formatDate = (dateStr) => {
.date-text {
margin-top: 2rem;
font-size: 1.125rem;
color: var(--text-muted);
color: #9ca3af;
font-family:
'MiSans',
system-ui,
+8 -11
View File
@@ -7,7 +7,7 @@
<Transition name="entry" appear>
<div v-show="active" class="content">
<div class="year-bg">{{ data.year }}</div>
<div class="sub-title">{{ yearReview.reportTitle }}</div>
<div class="sub-title">年度点歌报告</div>
<h1 class="main-title">VoiceHub</h1>
</div>
</Transition>
@@ -15,13 +15,10 @@
</template>
<script setup>
import { useLocale } from '~/utils/locale'
defineProps({
data: Object,
active: Boolean
})
const { yearReview } = useLocale()
</script>
<style scoped>
@@ -34,7 +31,7 @@ const { yearReview } = useLocale()
align-items: center;
justify-content: center;
overflow: hidden;
background: radial-gradient(circle at center, var(--panel-bg-dark), var(--bg-primary));
background: radial-gradient(circle at center, var(--bg-secondary, #111827), #000000);
}
.blob {
@@ -49,7 +46,7 @@ const { yearReview } = useLocale()
left: -10%;
width: 500px;
height: 500px;
background: var(--year-review-blob-1-bg);
background: rgba(139, 92, 246, 0.4); /* brand-purple */
animation: spin 20s linear infinite;
}
@@ -58,7 +55,7 @@ const { yearReview } = useLocale()
right: -10%;
width: 600px;
height: 600px;
background: var(--year-review-blob-2-bg);
background: rgba(244, 114, 182, 0.2); /* brand-pink */
animation: reverse-spin 25s linear infinite;
}
@@ -76,7 +73,7 @@ const { yearReview } = useLocale()
transform: translate(-50%, -50%);
font-size: 14rem;
font-weight: 900;
color: var(--overlay-3);
color: rgba(255, 255, 255, 0.03);
pointer-events: none;
user-select: none;
line-height: 1;
@@ -85,7 +82,7 @@ const { yearReview } = useLocale()
.sub-title {
font-size: 1.5rem;
font-weight: 300;
color: var(--text-muted);
color: #9ca3af;
margin-bottom: 1rem;
letter-spacing: 0.2em;
text-transform: uppercase;
@@ -94,12 +91,12 @@ const { yearReview } = useLocale()
.main-title {
font-size: 5rem;
font-weight: 900;
background-image: linear-gradient(to right, var(--text-primary), var(--panel-border-light), var(--text-muted));
background-image: linear-gradient(to right, #ffffff, #e5e7eb, #6b7280);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
margin-bottom: 2rem;
filter: drop-shadow(0 25px 25px var(--mask-15));
filter: drop-shadow(0 25px 25px rgba(0, 0, 0, 0.15));
}
@media (max-width: 768px) {
+22 -17
View File
@@ -5,18 +5,18 @@
<Transition name="entry" appear>
<div v-show="active" class="content">
<div v-if="data.topPlatform" class="card platform-card">
<span class="label">{{ yearReview.commonPlatform }}</span>
<span class="label">常用平台</span>
<span class="platform-value">{{ formatPlatform(data.topPlatform) }}</span>
</div>
<div class="grid-container">
<div v-if="data.activeMonth" class="card active-card">
<span class="label">{{ yearReview.mostActive }}</span>
<span class="active-value">{{ yearReview.activeMonth(data.activeMonth) }}</span>
<span class="label">最活跃</span>
<span class="active-value">{{ data.activeMonth }}<span class="unit">月</span></span>
</div>
<div class="card votes-card">
<span class="label">{{ yearReview.votesCast }}</span>
<span class="label">投出票数</span>
<span class="votes-value">{{ data.totalVotes }}</span>
</div>
</div>
@@ -26,16 +26,21 @@
</template>
<script setup>
import { useLocale } from '~/utils/locale'
defineProps({
data: Object,
active: Boolean
})
const { yearReview } = useLocale()
const formatPlatform = (platform) => {
const map = yearReview.value.platforms
const map = {
netease: '网易云音乐',
bilibili: '哔哩哔哩',
qq: 'QQ音乐',
kugou: '酷狗音乐',
kuwo: '酷我音乐',
migu: '咪咕音乐',
tencent: 'QQ音乐'
}
return map[platform] || platform
}
</script>
@@ -49,7 +54,7 @@ const formatPlatform = (platform) => {
align-items: center;
justify-content: center;
overflow: hidden;
background-color: var(--panel-bg-dark); /* gray-900 */
background-color: var(--bg-secondary, #111827); /* gray-900 */
}
.bg-gradient {
@@ -58,7 +63,7 @@ const formatPlatform = (platform) => {
left: 0;
width: 100%;
height: 50%;
background: linear-gradient(to bottom, var(--panel-border-subtle), transparent);
background: linear-gradient(to bottom, var(--bg-secondary, #1f2937), transparent);
opacity: 0.2;
}
@@ -74,8 +79,8 @@ const formatPlatform = (platform) => {
.card {
padding: 1.5rem;
border-radius: 1.5rem;
background: var(--overlay-5);
border: 1px solid var(--overlay-10);
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(12px);
display: flex;
flex-direction: column;
@@ -85,7 +90,7 @@ const formatPlatform = (platform) => {
.label {
font-size: 0.75rem;
color: var(--year-review-text-tertiary);
color: #6b7280;
text-transform: uppercase;
letter-spacing: 0.1em;
margin-bottom: 0.5rem; /* adjusted */
@@ -94,7 +99,7 @@ const formatPlatform = (platform) => {
.platform-value {
font-size: 1.5rem; /* text-2xl */
font-weight: 700;
background-image: linear-gradient(to right, var(--color-error-light), var(--color-orange));
background-image: linear-gradient(to right, #f87171, #fb923c);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
@@ -114,19 +119,19 @@ const formatPlatform = (platform) => {
.active-value {
font-size: 2.25rem; /* text-4xl */
font-weight: 700;
color: var(--year-review-text-yellow);
color: #fde047; /* yellow-300 */
}
.unit {
font-size: 1rem;
margin-left: 0.25rem;
color: var(--text-muted);
color: #9ca3af;
}
.votes-value {
font-size: 1.875rem; /* text-3xl */
font-weight: 700;
color: var(--year-review-text-cyan); /* cyan-300 */
color: #67e8f9; /* cyan-300 */
}
@media (min-width: 768px) {
+16 -19
View File
@@ -4,14 +4,14 @@
<Transition name="entry" appear>
<div v-show="active" class="content">
<div class="label">{{ yearReview.future }}</div>
<div class="label">未来可期</div>
<div class="year-container">
<h2 class="year-next">{{ data.year + 1 }}</h2>
<div class="year-underline" />
</div>
<p class="text-intro">{{ yearReview.futureDesc }}</p>
<p class="text-intro">愿音乐继续陪伴你的每一天</p>
<div class="action-buttons">
<NuxtLink to="/" class="btn-primary group">
@@ -30,7 +30,7 @@
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
<polyline points="9 22 9 12 15 12 15 22" />
</svg>
{{ yearReview.backHome }}
返回首页
</span>
</NuxtLink>
</div>
@@ -40,14 +40,11 @@
</template>
<script setup>
import { useLocale } from '~/utils/locale'
defineProps({
data: Object,
active: Boolean
})
defineEmits(['share'])
const { yearReview } = useLocale()
</script>
<style scoped>
@@ -59,13 +56,13 @@ const { yearReview } = useLocale()
align-items: center;
justify-content: center;
overflow: hidden;
background-color: var(--bg-primary);
background-color: var(--bg-primary, #111111);
}
.bg-gradient {
position: absolute;
inset: 0;
background: radial-gradient(circle at center, var(--panel-border-subtle), var(--bg-primary), var(--bg-primary));
background: radial-gradient(circle at center, var(--bg-secondary, #1f2937), #000, #000);
opacity: 0.5;
}
@@ -78,7 +75,7 @@ const { yearReview } = useLocale()
}
.label {
color: var(--year-review-text-tertiary);
color: #6b7280;
font-size: 0.875rem;
letter-spacing: 0.5em;
text-transform: uppercase;
@@ -95,7 +92,7 @@ const { yearReview } = useLocale()
font-size: 6rem;
font-weight: 900;
line-height: 1;
background-image: linear-gradient(to bottom, var(--text-primary), var(--panel-border-subtle));
background-image: linear-gradient(to bottom, #fff, #1f2937);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
@@ -107,12 +104,12 @@ const { yearReview } = useLocale()
left: 0;
width: 100%;
height: 4px;
background: linear-gradient(to right, transparent, var(--overlay-20), transparent);
background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.2), transparent);
}
.text-intro {
font-size: 1.125rem;
color: var(--text-muted);
color: #9ca3af;
margin-bottom: 3rem;
}
@@ -135,8 +132,8 @@ const { yearReview } = useLocale()
width: 100%;
padding: 1rem 2rem;
border-radius: 9999px;
background: var(--text-primary);
color: var(--bg-primary);
background: var(--card-bg, #fff);
color: var(--text-primary, #000);
font-weight: 700;
font-size: 1.125rem;
overflow: hidden;
@@ -153,7 +150,7 @@ const { yearReview } = useLocale()
.btn-bg {
position: absolute;
inset: 0;
background: var(--panel-border-light);
background: #e5e7eb;
transform: translateY(100%);
transition: transform 0.3s;
}
@@ -174,9 +171,9 @@ const { yearReview } = useLocale()
width: 100%;
padding: 1rem 2rem;
border-radius: 9999px;
background: var(--overlay-10);
border: 1px solid var(--overlay-20);
color: var(--text-primary);
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: var(--text-primary, #ffffff);
font-weight: 700;
font-size: 1.125rem;
backdrop-filter: blur(12px);
@@ -188,7 +185,7 @@ const { yearReview } = useLocale()
}
.btn-secondary:hover {
background: var(--overlay-20);
background: rgba(255, 255, 255, 0.2);
}
.btn-secondary:active {
+19 -21
View File
@@ -12,27 +12,27 @@
</div>
<div class="title-section">
<h1 class="main-title">{{ yearReview.reportTitle }}</h1>
<h1 class="main-title">年度点歌报告</h1>
<p class="subtitle">Music Journey</p>
</div>
<div class="stats-grid">
<div class="stat-item">
<div class="stat-value">{{ data.totalRequests }}</div>
<div class="stat-label">{{ yearReview.requests }}</div>
<div class="stat-label">点歌次数</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ data.playedRequests }}</div>
<div class="stat-label">{{ yearReview.played }}</div>
<div class="stat-label">已播放</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ data.totalVotes }}</div>
<div class="stat-label">{{ yearReview.votes }}</div>
<div class="stat-label">投票数</div>
</div>
</div>
<div class="footer">
<div class="footer-text">{{ yearReview.footerSlogan }}</div>
<div class="footer-text">用音乐记录每一刻</div>
<div class="footer-line" />
</div>
</div>
@@ -41,7 +41,6 @@
<script setup>
import { ref } from 'vue'
import { useLocale } from '~/utils/locale'
defineProps({
data: {
@@ -51,7 +50,6 @@ defineProps({
})
const shareCardRef = ref(null)
const { yearReview } = useLocale()
defineExpose({
shareCardRef
@@ -65,7 +63,7 @@ defineExpose({
height: 100%;
min-height: 600px;
overflow: hidden;
background: linear-gradient(135deg, var(--panel-bg-tertiary) 0%, var(--panel-bg-tertiary) 50%, var(--panel-bg-tertiary) 100%);
background: linear-gradient(135deg, var(--bg-secondary, #0f0f23) 0%, #1a1a2e 50%, #16213e 100%);
}
.card-background {
@@ -77,9 +75,9 @@ defineExpose({
position: absolute;
inset: 0;
background:
radial-gradient(circle at 20% 30%, var(--index-card-glow) 0%, transparent 50%),
radial-gradient(circle at 80% 70%, var(--year-review-gradient-overlay-end) 0%, transparent 50%),
radial-gradient(circle at 50% 50%, var(--primary-10) 0%, transparent 60%);
radial-gradient(circle at 20% 30%, rgba(139, 92, 246, 0.15) 0%, transparent 50%),
radial-gradient(circle at 80% 70%, rgba(244, 114, 182, 0.15) 0%, transparent 50%),
radial-gradient(circle at 50% 50%, rgba(59, 130, 246, 0.1) 0%, transparent 60%);
}
.noise-overlay {
@@ -108,7 +106,7 @@ defineExpose({
.logo {
font-size: 1.5rem;
font-weight: 900;
background: linear-gradient(135deg, var(--color-collab), var(--color-pink));
background: linear-gradient(135deg, #8b5cf6, #ec4899);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
@@ -117,7 +115,7 @@ defineExpose({
.year {
font-size: 3rem;
font-weight: 900;
color: var(--overlay-10);
color: rgba(255, 255, 255, 0.1);
line-height: 1;
}
@@ -129,7 +127,7 @@ defineExpose({
.main-title {
font-size: 3.5rem;
font-weight: 900;
background: linear-gradient(135deg, var(--text-primary) 0%, var(--panel-border-light) 50%, var(--text-muted) 100%);
background: linear-gradient(135deg, var(--card-bg, #ffffff) 0%, #e5e7eb 50%, #9ca3af 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
@@ -139,7 +137,7 @@ defineExpose({
.subtitle {
font-size: 1.25rem;
color: var(--overlay-50);
color: rgba(255, 255, 255, 0.5);
letter-spacing: 0.3em;
text-transform: uppercase;
}
@@ -154,16 +152,16 @@ defineExpose({
.stat-item {
text-align: center;
padding: 1.5rem;
background: var(--overlay-3);
background: rgba(255, 255, 255, 0.03);
border-radius: 1rem;
border: 1px solid var(--overlay-8);
border: 1px solid rgba(255, 255, 255, 0.08);
backdrop-filter: blur(10px);
}
.stat-value {
font-size: 2.5rem;
font-weight: 900;
background: linear-gradient(135deg, var(--color-accent-light), var(--color-accent-light));
background: linear-gradient(135deg, #60a5fa, #3b82f6);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
@@ -172,7 +170,7 @@ defineExpose({
.stat-label {
font-size: 0.875rem;
color: var(--overlay-50);
color: rgba(255, 255, 255, 0.5);
letter-spacing: 0.05em;
}
@@ -183,7 +181,7 @@ defineExpose({
.footer-text {
font-size: 0.875rem;
color: var(--overlay-40);
color: rgba(255, 255, 255, 0.4);
letter-spacing: 0.1em;
margin-bottom: 1rem;
}
@@ -191,7 +189,7 @@ defineExpose({
.footer-line {
width: 100px;
height: 2px;
background: linear-gradient(90deg, transparent, var(--overlay-20), transparent);
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
margin: 0 auto;
}
+18 -21
View File
@@ -4,23 +4,23 @@
<Transition name="entry" appear>
<div v-show="active" class="content">
<div class="label">{{ yearReview.musicJourney }}</div>
<div class="label">音乐足迹</div>
<p class="text-intro">{{ yearReview.totalRequestsIntro }}</p>
<p class="text-intro">这一年,你一共发起了</p>
<div class="number-container">
<span class="big-number">{{ data.totalRequests.toLocaleString() }}</span>
<span class="suffix">{{ yearReview.requestCount }}</span>
<span class="suffix">次点歌</span>
</div>
<div class="sub-stats">
<div v-if="data.playedRequests > 0" class="sub-content">
<p class="text-base">
{{ yearReview.playedSummary(data.playedRequests) }}
其中,<span class="highlight-green">{{ data.playedRequests }}</span> 首
</p>
<p class="text-sub">{{ yearReview.playedDesc }}</p>
<p class="text-sub">在广播站被播出,传递给了更多人</p>
</div>
<p v-else class="text-sub">{{ yearReview.pendingPlayedDesc }}</p>
<p v-else class="text-sub">期待你的歌曲早日被播出</p>
</div>
</div>
</Transition>
@@ -28,13 +28,10 @@
</template>
<script setup>
import { useLocale } from '~/utils/locale'
defineProps({
data: Object,
active: Boolean
})
const { yearReview } = useLocale()
</script>
<style scoped>
@@ -46,7 +43,7 @@ const { yearReview } = useLocale()
align-items: center;
justify-content: center;
overflow: hidden;
background-color: var(--panel-bg-darkest); /* gray-950 */
background-color: var(--surface-primary, var(--bg-primary, #030712));
}
.bg-gradient {
@@ -54,7 +51,7 @@ const { yearReview } = useLocale()
inset: 0;
background: radial-gradient(
ellipse at top right,
var(--year-review-stats-bg-gradient),
rgba(30, 58, 138, 0.4),
transparent,
transparent
);
@@ -69,7 +66,7 @@ const { yearReview } = useLocale()
.label {
margin-bottom: 1rem;
color: var(--color-accent-light); /* brand-blue */
color: #3b82f6; /* brand-blue */
font-weight: 700;
letter-spacing: 0.05em;
font-size: 1.125rem;
@@ -77,7 +74,7 @@ const { yearReview } = useLocale()
.text-intro {
font-size: 1.5rem;
color: var(--text-muted);
color: #9ca3af;
margin-bottom: 0.5rem;
}
@@ -94,16 +91,16 @@ const { yearReview } = useLocale()
font-size: 10rem;
font-weight: 900;
line-height: 1;
background-image: linear-gradient(to bottom, var(--color-accent-light), var(--color-accent-light-hover));
background-image: linear-gradient(to bottom, #60a5fa, #1d4ed8);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
filter: drop-shadow(0 0 30px var(--year-review-stat-number-shadow));
filter: drop-shadow(0 0 30px rgba(37, 99, 235, 0.5));
}
.suffix {
font-size: 1.5rem;
color: var(--year-review-text-tertiary);
color: #6b7280;
font-weight: 500;
margin-left: 0.5rem;
}
@@ -112,8 +109,8 @@ const { yearReview } = useLocale()
margin-top: 3rem;
padding: 1.5rem;
border-radius: 1rem;
background: var(--overlay-5);
border: 1px solid var(--overlay-10);
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(4px);
}
@@ -125,19 +122,19 @@ const { yearReview } = useLocale()
.text-base {
font-size: 1.125rem;
color: var(--text-primary-lighter);
color: #d1d5db;
}
.highlight-green {
font-size: 1.875rem;
font-weight: 700;
color: var(--color-success-light);
color: #4ade80;
margin: 0 0.25rem;
}
.text-sub {
font-size: 1rem;
color: var(--text-muted);
color: #9ca3af;
}
@media (max-width: 768px) {