feat: 标题文案与样式焕新「星耀时刻,致敬奋斗者」
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed

- 中英文默认标题更新为「星耀时刻,致敬奋斗者」/「Stellar Moments · Tribute to the Driven」
- 在 main.ts 添加一次性迁移,自动覆盖本地缓存中的旧标题
- HeaderTitle 与 PrizeDraw 标题改用羚牛 logo 配色:深炭黑 + 翡翠绿 + 金色高光的渐变与流光动画
- 标题左右增加渐变细线 + 金/绿光点装饰,按钮统一为绿金品牌色
- 标题强制单行不换行,避免窄容器下折行

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-04-27 17:59:56 +08:00
parent 30ea764c44
commit 6889fdee1f
4 changed files with 282 additions and 24 deletions

View File

@@ -12,7 +12,7 @@ export const dataEn = {
operation: 'Operation',
delete: 'Delete',
removePerson: 'Remove the Person',
defaultTitle: 'The Prelude to the Six Ministries of the Ming Dynasty Cabinet',
defaultTitle: 'Stellar Moments · Tribute to the Driven',
xlsxName: 'personListTemplate-en.xlsx',
readmeName: 'readme-en.md',
}
@@ -31,7 +31,7 @@ export const dataZhCn = {
operation: '操作',
delete: '删除',
removePerson: '移入未中奖名单',
defaultTitle: '「氢」春正好,牛人闪耀',
defaultTitle: '星耀时刻,致敬奋斗者',
xlsxName: '人口登记表-zhCn.xlsx',
readmeName: 'readme-zhCn.md',
}

View File

@@ -38,6 +38,22 @@ import 'virtual:svg-icons-register'
// 更新CSS变量
document.documentElement.style.setProperty('--app-font-family', `"${globalConfig.theme.font}", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif`)
}
// 一次性迁移旧的默认标题,确保已有用户也能看到新文案
const legacyTitles = new Set([
'「氢」春正好,牛人闪耀',
'The Prelude to the Six Ministries of the Ming Dynasty Cabinet',
])
if (globalConfig.topTitle && legacyTitles.has(globalConfig.topTitle)) {
const isEn = globalConfig.language === 'en'
globalConfig.topTitle = isEn
? 'Stellar Moments · Tribute to the Driven'
: '星耀时刻,致敬奋斗者'
if (storageData.globalConfig) {
storageData.globalConfig = globalConfig
}
localStorage.setItem('globalConfig', JSON.stringify(storageData.globalConfig ? storageData : globalConfig))
}
}
}
catch (e) {

View File

@@ -40,22 +40,26 @@ const { t } = useI18n()
<template>
<div class="absolute z-10 flex flex-col items-center justify-center -translate-x-1/2 left-1/2">
<h2
class="pt-12 m-0 mb-12 tracking-wide text-center leading-12"
:class="{ 'animate-pulse bg-linear-to-r from-primary via-secondary to-accent bg-clip-text text-transparent': !isTextColor }"
:style="titleStyle"
>
{{ topTitle }}
</h2>
<div class="lingniu-title-row pt-12 mb-12">
<span v-if="!isTextColor" class="title-ornament title-ornament--left" aria-hidden="true" />
<h2
class="lingniu-title-text m-0 text-center"
:class="{ 'lingniu-title-gradient': !isTextColor }"
:style="titleStyle"
>
{{ topTitle }}
</h2>
<span v-if="!isTextColor" class="title-ornament title-ornament--right" aria-hidden="true" />
</div>
<div v-if="isInitialDone" class="flex gap-3">
<button
v-if="tableData.length <= 0" class="cursor-pointer btn btn-outline btn-secondary btn-lg"
v-if="tableData.length <= 0" class="cursor-pointer btn btn-outline btn-lg lingniu-btn"
@click="router.push('config')"
>
{{ t('button.noInfoAndImport') }}
</button>
<button
v-if="tableData.length <= 0" class="cursor-pointer btn btn-outline btn-secondary btn-lg"
v-if="tableData.length <= 0" class="cursor-pointer btn btn-outline btn-lg lingniu-btn"
@click="setDefaultPersonList"
>
{{ t('button.useDefault') }}
@@ -70,11 +74,132 @@ const { t } = useI18n()
</template>
<style scoped lang="scss">
.header-title {
.lingniu-title-row {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: nowrap;
gap: 28px;
white-space: nowrap;
-webkit-animation: tracking-in-expand-fwd 0.8s cubic-bezier(0.215, 0.610, 0.355, 1.000) both;
animation: tracking-in-expand-fwd 0.8s cubic-bezier(0.215, 0.610, 0.355, 1.000) both;
}
.lingniu-title-text {
line-height: 1.2;
font-weight: 700;
letter-spacing: 0.22em;
padding-inline: 0.22em; // 防止letter-spacing截断尾字渐变
white-space: nowrap;
}
.lingniu-title-gradient {
background: linear-gradient(
110deg,
#2F2828 0%,
#007143 18%,
#12a86b 36%,
#f5d27a 50%,
#12a86b 64%,
#007143 82%,
#2F2828 100%
);
background-size: 220% 100%;
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
filter: drop-shadow(0 6px 24px rgba(0, 113, 67, 0.35));
animation: lingniu-shine 6s linear infinite;
}
.title-ornament {
--ornament-w: clamp(56px, 12vw, 140px);
position: relative;
display: inline-block;
width: var(--ornament-w);
height: 1px;
background: linear-gradient(to right, transparent 0%, rgba(0, 113, 67, 0.05) 10%, #007143 50%, rgba(0, 113, 67, 0.05) 90%, transparent 100%);
flex: none;
&::before,
&::after {
content: '';
position: absolute;
top: 50%;
width: 8px;
height: 8px;
border-radius: 50%;
transform: translateY(-50%) rotate(45deg);
background: linear-gradient(135deg, #f5d27a 0%, #d4a960 100%);
box-shadow:
0 0 14px rgba(0, 113, 67, 0.55),
0 0 4px rgba(245, 210, 122, 0.7);
}
&--left {
&::before {
left: 50%;
margin-left: -4px;
background: linear-gradient(135deg, #007143 0%, #12a86b 100%);
}
&::after {
right: -4px;
}
}
&--right {
&::before {
left: -4px;
}
&::after {
right: 50%;
margin-right: -4px;
background: linear-gradient(135deg, #007143 0%, #12a86b 100%);
}
}
}
.lingniu-btn {
--btn-color: #007143;
--btn-color-hover: #12a86b;
color: #fff;
border-color: rgba(0, 113, 67, 0.6);
background: rgba(0, 113, 67, 0.08);
backdrop-filter: blur(6px);
box-shadow:
0 4px 18px rgba(0, 113, 67, 0.18),
inset 0 0 0 1px rgba(245, 210, 122, 0.12);
transition: transform 0.25s ease, box-shadow 0.25s ease, background 0.25s ease, border-color 0.25s ease;
&:hover {
background: linear-gradient(135deg, rgba(0, 113, 67, 0.85), rgba(18, 168, 107, 0.85));
border-color: rgba(245, 210, 122, 0.7);
box-shadow:
0 10px 28px rgba(0, 113, 67, 0.45),
inset 0 0 0 1px rgba(245, 210, 122, 0.45);
transform: translateY(-1px);
}
}
@media (max-width: 640px) {
.lingniu-title-row {
gap: 12px;
}
.title-ornament {
--ornament-w: 36px;
}
}
@keyframes lingniu-shine {
0% {
background-position: 200% 50%;
}
100% {
background-position: -200% 50%;
}
}
@-webkit-keyframes tracking-in-expand-fwd {
0% {
letter-spacing: -0.5em;

View File

@@ -5,13 +5,17 @@
<!-- 顶部标题 -->
<div class="header-wrapper">
<h2
class="page-title"
:class="{ 'animate-pulse bg-linear-to-r from-primary via-secondary to-accent bg-clip-text text-transparent': !isTextColor }"
:style="titleStyle"
>
{{ topTitle }}
</h2>
<div class="lingniu-title-row">
<span v-if="!isTextColor" class="title-ornament title-ornament--left" aria-hidden="true" />
<h2
class="page-title lingniu-title-text"
:class="{ 'lingniu-title-gradient': !isTextColor }"
:style="titleStyle"
>
{{ topTitle }}
</h2>
<span v-if="!isTextColor" class="title-ornament title-ornament--right" aria-hidden="true" />
</div>
</div>
<!-- 抽奖进度和重置按钮 -->
@@ -775,14 +779,127 @@ onUnmounted(() => {
justify-content: center;
}
.page-title {
.lingniu-title-row {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: nowrap;
white-space: nowrap;
gap: 28px;
padding-top: 48px;
margin: 0;
margin-bottom: 48px;
letter-spacing: 0.05em;
-webkit-animation: tracking-in-expand-fwd 0.8s cubic-bezier(0.215, 0.610, 0.355, 1.000) both;
animation: tracking-in-expand-fwd 0.8s cubic-bezier(0.215, 0.610, 0.355, 1.000) both;
}
.page-title {
margin: 0;
text-align: center;
line-height: 3rem;
font-weight: normal;
line-height: 1.2;
}
.lingniu-title-text {
font-weight: 700;
letter-spacing: 0.22em;
padding-inline: 0.22em;
white-space: nowrap;
}
.lingniu-title-gradient {
background: linear-gradient(
110deg,
#2F2828 0%,
#007143 18%,
#12a86b 36%,
#f5d27a 50%,
#12a86b 64%,
#007143 82%,
#2F2828 100%
);
background-size: 220% 100%;
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
filter: drop-shadow(0 6px 24px rgba(0, 113, 67, 0.35));
animation: lingniu-shine 6s linear infinite;
}
.title-ornament {
--ornament-w: clamp(56px, 12vw, 140px);
position: relative;
display: inline-block;
width: var(--ornament-w);
height: 1px;
flex: none;
background: linear-gradient(
to right,
transparent 0%,
rgba(0, 113, 67, 0.05) 10%,
#007143 50%,
rgba(0, 113, 67, 0.05) 90%,
transparent 100%
);
}
.title-ornament::before,
.title-ornament::after {
content: '';
position: absolute;
top: 50%;
width: 8px;
height: 8px;
border-radius: 50%;
transform: translateY(-50%) rotate(45deg);
background: linear-gradient(135deg, #f5d27a 0%, #d4a960 100%);
box-shadow:
0 0 14px rgba(0, 113, 67, 0.55),
0 0 4px rgba(245, 210, 122, 0.7);
}
.title-ornament--left::before {
left: 50%;
margin-left: -4px;
background: linear-gradient(135deg, #007143 0%, #12a86b 100%);
}
.title-ornament--left::after {
right: -4px;
}
.title-ornament--right::before {
left: -4px;
}
.title-ornament--right::after {
right: 50%;
margin-right: -4px;
background: linear-gradient(135deg, #007143 0%, #12a86b 100%);
}
@media (max-width: 640px) {
.lingniu-title-row {
gap: 12px;
}
.title-ornament {
--ornament-w: 36px;
}
}
@keyframes lingniu-shine {
0% { background-position: 200% 50%; }
100% { background-position: -200% 50%; }
}
@keyframes tracking-in-expand-fwd {
0% {
letter-spacing: -0.5em;
transform: translateZ(-700px);
opacity: 0;
}
40% { opacity: 0.6; }
100% {
transform: translateZ(0);
opacity: 1;
}
}
.prize-info {