Files
dinner.tootaio.com/20251115/sponsorList/index.html
xiaomai 326ddee342 feat(sponsorList): enhance display with item sponsors and poems
This commit significantly updates the sponsor list page for the 2025/11/15 event.

- Adds support for displaying item-based sponsorships, including their details.
- Introduces a new visual layout with vertical poems on the sides, utilizing custom fonts.
- Updates the sponsor data with the latest list of cash, item, and table sponsors.
- Refactors the sorting logic to correctly prioritize all sponsor types.
- Centralizes font assets by updating paths to be absolute and removing redundant font files.
2025-11-12 21:54:45 +08:00

300 lines
9.9 KiB
HTML
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.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sponsor list - 汕河</title>
<script src="/analysis.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style type="text/tailwindcss">
@theme {
/* 🎨 定义自定义字体族变量 */
--font-bai-ge: "BaiGeTianXing", sans-serif;
--font-gu-huang: "ShangShouGuHuang", sans-serif;
--font-tang-ying: "YeZiTangYingHei", sans-serif;
}
@font-face {
font-family: "BaiGeTianXing";
src: url("/fonts/字魂白鸽天行体.ttf") format("truetype");
font-display: swap;
}
@font-face {
font-family: "ShangShouGuHuang";
src: url("/fonts/ShangShouGuHuangTi-2.ttf") format("truetype");
font-display: swap;
}
@font-face {
font-family: "YeZiTangYingHei";
src: url("/fonts/YeZiGongChangTangYingHei-2.ttf") format("truetype");
font-display: swap;
}
.poem {
@apply flex-1 [writing-mode:vertical-rl] flex items-center justify-center text-6xl font-bai-ge tracking-[0.5em] text-white ring-amber-300 text-shadow-lg text-shadow-black;
}
</style>
<style>
.sponsor-marquee-track {
animation: sponsor-marquee-move-text 120s linear infinite;
}
.special-marquee-track {
animation: special-marquee-move-text 30s linear infinite;
}
@keyframes sponsor-marquee-move-text {
to {
transform: translateY(-50%);
}
}
@keyframes special-marquee-move-text {
to {
transform: translateX(-50%);
}
}
</style>
</head>
<body>
<div id="app" class="h-screen flex flex-col select-none">
<div class="text-center text-6xl font-bold p-8 bg-red-700 text-white">
{{eventTitle}}
</div>
<!-- 特别赞助 -->
<div class="py-6 bg-yellow-300 text-red-500 shadow-yellow-500 shadow-lg">
<div class="overflow-clip mask-x-from-95% mask-x-to-100%">
<div class="flex pl-4 gap-4 w-max special-marquee-track text-4xl">
<div v-for="sponsor in specialSponsorDouble" :key="sponsor">
{{sponsor}}
</div>
</div>
</div>
</div>
<!-- 下半部分二八分,左侧放 image右侧走马灯 -->
<div
class="flex-1 flex min-h-0 overflow-clip bg-linear-to-b from-red-500 to-red-900"
>
<!-- <div class="flex-2 flex flex-col items-center justify-around">
<img
v-for="logo in logos"
:src="`../assets/${logo.imgSrc}`"
:alt="logo.imgSrc"
class="w-[80%] drop-shadow-2xl"
/>
</div> -->
<div class="poem">汕水流长通四海</div>
<div class="flex-8 inset-red-lg">
<div class="flex flex-col pt-4 gap-4 px-4 sponsor-marquee-track">
<div
v-for="sponsor in sponsorListDouble"
:key="sponsor"
class="bg-linear-to-br from-white/20 to-white/10 px-16 py-4 rounded-2xl border-2 border-white/40"
>
<div v-if="sponsor.type == 'cash'" class="text-center py-8">
<div class="text-7xl text-yellow-400 font-bold">
RM {{sponsor.displayAmount}}
</div>
<div
class="text-7xl text-white text-shadow-amber-400 text-shadow-lg"
>
{{sponsor.name}}
</div>
</div>
<div
v-else-if="sponsor.type == 'cash-group'"
class="text-center py-8"
>
<div class="text-7xl text-yellow-400 font-bold mb-8">
RM {{sponsor.amount}}
</div>
<div class="flex flex-wrap gap-4">
<div
v-for="child in sponsor.children"
class="text-3xl px-4 py-2 bg-white/40 rounded-2xl"
>
{{child}}
</div>
</div>
</div>
<div
v-else-if="sponsor.type == 'table'"
class="flex items-center"
>
<div
class="text-3xl bg-red-500 text-white font-bold px-4 py-2 border-2 border-white rounded-full"
>
{{tableToSeats(sponsor.amount)}}
</div>
<div class="text-4xl font-bold flex-1 ml-4 text-white">
{{sponsor.name}}
</div>
</div>
<div v-else-if="sponsor.type == 'item'" class="flex items-center">
<div
class="text-3xl bg-red-500 text-white font-bold px-4 py-2 border-2 border-white rounded-full"
>
{{sponsor.detail}}
</div>
<div class="text-4xl font-bold flex-1 ml-4 text-white">
{{sponsor.name}}
</div>
</div>
</div>
</div>
</div>
<div class="poem">河川万里泽邦家</div>
</div>
</div>
<script>
const { createApp, ref, computed, onMounted } = Vue;
createApp({
setup() {
const eventTitle = ref("");
const logos = ref([]);
const sponsorList = ref([]); // Load from JSON
const specialSponsor = ref(
"感谢 V World2.0 的特别赞助,现在下载 APP 并进行实名认证即可获得 RM50 的登录奖励!"
);
const typePriority = {
cash: 4,
"cash-group": 3,
table: 2,
item: 1,
};
const groupByCashLessThan = ref(0);
function sortSponsors(list) {
return list.sort((a, b) => {
// 先按 type 优先级排序
const typeDiff = typePriority[b.type] - typePriority[a.type];
if (typeDiff !== 0) return typeDiff;
// 若 type 相同,再按 amount 从大到小
if (b.amount !== a.amount) return b.amount - a.amount;
// 若 amount 相同,最后按名称排序(可选)
return a.name.localeCompare(b.name, "zh");
});
}
const loadData = async () => {
try {
const [sponsorListResult] = await Promise.all([
fetch("../sponsorList.json"),
]);
if (!sponsorListResult.ok) {
throw new Error(
"Error while loading sponsorList: " + sponsorListResult.status
);
}
const sponsorListJsonData = await sponsorListResult.json();
eventTitle.value = sponsorListJsonData.eventTitle || "活动名称";
logos.value = sponsorListJsonData.logos || [];
sponsorList.value = (
sponsorListJsonData.sponsorList || []
).reduce((acc, s, idx) => {
const sponsor = {
...s,
displayAmount:
s.type == "cash"
? s.amount.toLocaleString("en-MY")
: s.amount,
_uid: `s-${idx}`,
};
// 如果是现金赞助且金额小于阈值
if (s.type === "cash" && s.amount < groupByCashLessThan.value) {
// 查找是否已存在该金额的分组
const groupId = `group-${s.amount}`;
let amountGroup = acc.find((item) => item._uid === groupId);
if (!amountGroup) {
// 创建新的金额分组
amountGroup = {
name: "其他赞助商",
type: "cash-group",
amount: s.amount, // 保持原始数字,不格式化
children: [],
_uid: groupId,
};
acc.push(amountGroup);
}
// 将赞助商名称添加到分组的children中
amountGroup.children.push(s.name);
} else {
// 其他赞助商直接添加到结果中
acc.push(sponsor);
}
return acc;
}, []);
// Sort SponsorList by type and amount
sponsorList.value = sortSponsors(sponsorList.value);
console.log(sponsorList.value);
} catch (err) {
console.error(err);
}
};
onMounted(async () => {
await loadData();
});
const sponsorListDouble = computed(() => {
const a = sponsorList.value.map((s) => ({
...s,
_uid: s._uid + "-a",
}));
const b = sponsorList.value.map((s) => ({
...s,
_uid: s._uid + "-b",
}));
return [...a, ...b];
});
const specialSponsorDouble = computed(() => [
specialSponsor.value,
specialSponsor.value,
specialSponsor.value,
specialSponsor.value,
]);
const tableToSeats = (amount) => {
switch (amount) {
case 2:
return "两席";
case 1:
return "一席";
case 0.5:
return "半席";
default:
console.error("Error while converting table amount: ", amount);
}
};
return {
eventTitle,
logos,
sponsorListDouble,
specialSponsorDouble,
tableToSeats,
};
},
}).mount("#app");
</script>
</body>
</html>