hyapp-h5/app-store/lalu.html
2026-06-04 23:07:37 +08:00

632 lines
20 KiB
HTML

<!doctype html>
<html lang="zh">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover"
/>
<title>Lalu Landing</title>
<meta
name="description"
content="Join a Lalu Party voice room and download the app."
/>
<link rel="stylesheet" href="../common/theme.css" />
<style>
* {
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
html,
body {
margin: 0;
min-height: 100%;
background: #090a10;
color: #f9f4ff;
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Arial,
sans-serif;
}
body {
min-height: 100vh;
min-height: 100svh;
overflow-x: hidden;
}
button {
border: 0;
font: inherit;
}
.page {
position: relative;
display: flex;
width: min(100%, 430px);
min-height: 100vh;
min-height: 100svh;
margin: 0 auto;
padding: max(28px, env(safe-area-inset-top)) 22px
calc(118px + env(safe-area-inset-bottom));
align-items: center;
justify-content: center;
overflow: hidden;
background:
linear-gradient(
180deg,
rgba(255, 236, 213, 0.1) 0%,
rgba(255, 236, 213, 0) 25%
),
#090a10;
}
.page::before {
content: '';
position: absolute;
inset: 0;
background:
linear-gradient(
90deg,
transparent 0 28%,
rgba(255, 255, 255, 0.04) 28% 29%,
transparent 29% 100%
),
linear-gradient(
180deg,
rgba(255, 255, 255, 0.06),
transparent 34%
);
opacity: 0.6;
pointer-events: none;
}
.ribbon {
position: absolute;
width: 34px;
height: 7px;
border-radius: 999px;
background: linear-gradient(90deg, #fff4dc, #ffb77e, #fff4dc);
box-shadow: 0 0 16px rgba(255, 205, 170, 0.42);
transform: rotate(-28deg);
}
.ribbon.one {
top: 48px;
right: 46px;
}
.ribbon.two {
left: 16px;
bottom: 222px;
transform: rotate(-38deg);
}
.ribbon.three {
right: 24px;
bottom: 168px;
transform: rotate(36deg);
}
.invite-shell {
position: relative;
z-index: 1;
width: 100%;
max-width: 340px;
padding: 12px;
border: 1px solid rgba(255, 228, 216, 0.9);
border-radius: 9px;
box-shadow:
0 0 22px rgba(255, 221, 215, 0.32),
0 26px 60px rgba(0, 0, 0, 0.52);
}
.invite-shell::before,
.invite-shell::after {
content: '';
position: absolute;
top: 42px;
width: 17px;
height: 172px;
border: 1px solid rgba(255, 228, 216, 0.72);
pointer-events: none;
}
.invite-shell::before {
left: -10px;
border-right: 0;
border-radius: 10px 0 0 10px;
}
.invite-shell::after {
right: -10px;
border-left: 0;
border-radius: 0 10px 10px 0;
}
.invite-card {
position: relative;
overflow: hidden;
border-radius: 6px;
background: #fbf2f3;
color: #353047;
}
.card-main {
position: relative;
z-index: 1;
padding: 24px 22px 34px;
background: #fbf2f3;
}
.card-main::after {
content: '';
position: absolute;
left: -10%;
right: -10%;
bottom: -30px;
height: 58px;
border-radius: 0 0 50% 50%;
background: #fbf2f3;
box-shadow: 0 14px 0 rgba(255, 255, 255, 0.26);
}
.brand-row {
position: relative;
z-index: 2;
display: flex;
align-items: center;
gap: 12px;
}
.brand-logo {
width: 48px;
height: 48px;
border-radius: 999px;
box-shadow: 0 8px 18px rgba(58, 36, 120, 0.22);
}
.brand-name {
margin: 0;
color: #302b45;
font-size: 20px;
font-weight: 900;
letter-spacing: 0;
}
.message {
position: relative;
z-index: 2;
margin: 26px 0 16px;
color: #4c465c;
font-size: 16px;
font-weight: 800;
line-height: 1.45;
text-align: center;
}
.rewards {
position: relative;
z-index: 2;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 22px;
}
.reward {
display: grid;
justify-items: center;
gap: 10px;
}
.reward-visual {
position: relative;
display: grid;
width: 86px;
height: 86px;
place-items: center;
overflow: hidden;
border-radius: 12px;
background:
linear-gradient(145deg, rgba(255, 255, 255, 0.14), transparent),
#1a1822;
box-shadow:
inset 0 0 0 1px rgba(255, 255, 255, 0.08),
0 12px 22px rgba(0, 0, 0, 0.16);
}
.reward-frame {
width: 72px;
height: 72px;
object-fit: contain;
filter: drop-shadow(0 0 10px rgba(57, 215, 255, 0.36));
}
.reward-coin {
width: 78px;
height: 78px;
object-fit: contain;
filter: drop-shadow(0 8px 10px rgba(233, 151, 33, 0.28));
}
.reward-label {
color: #4b465d;
font-size: 15px;
font-weight: 800;
line-height: 1;
}
.card-action {
position: relative;
z-index: 0;
display: grid;
justify-items: center;
gap: 14px;
padding: 62px 22px 22px;
background: #282a3a;
}
.join-button {
display: flex;
width: 224px;
min-height: 56px;
align-items: center;
justify-content: center;
border-radius: 999px;
color: #6d6277;
background: linear-gradient(180deg, #fff7ef, #f1dfd2);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.8),
0 12px 22px rgba(0, 0, 0, 0.18);
font-size: 18px;
font-weight: 800;
cursor: pointer;
}
.room-line {
margin: 0;
color: #f8f7ff;
font-size: 16px;
font-weight: 900;
line-height: 1;
text-shadow: 0 0 10px rgba(255, 255, 255, 0.22);
}
.download-dock {
position: fixed;
left: 50%;
right: auto;
bottom: 0;
z-index: 3;
display: flex;
width: min(100%, 430px);
min-height: calc(94px + env(safe-area-inset-bottom));
padding: 16px 22px calc(14px + env(safe-area-inset-bottom));
align-items: center;
justify-content: space-between;
gap: 16px;
background: rgba(30, 33, 45, 0.96);
transform: translateX(-50%);
backdrop-filter: blur(14px);
}
.app-summary {
display: flex;
min-width: 0;
align-items: center;
gap: 12px;
}
.app-summary img {
width: 52px;
height: 52px;
border-radius: 12px;
flex: 0 0 auto;
}
.app-copy {
min-width: 0;
}
.app-copy strong {
display: block;
overflow: hidden;
color: #fff;
font-size: 18px;
font-weight: 900;
line-height: 1.12;
text-overflow: ellipsis;
white-space: nowrap;
}
.app-copy span {
display: block;
margin-top: 5px;
overflow: hidden;
color: rgba(255, 255, 255, 0.78);
font-size: 14px;
font-weight: 760;
line-height: 1.1;
text-overflow: ellipsis;
white-space: nowrap;
}
.download-button {
display: flex;
min-width: 112px;
min-height: 48px;
align-items: center;
justify-content: center;
border-radius: 999px;
color: #fff;
background: linear-gradient(100deg, #38bdff 0%, #3165f4 100%);
box-shadow: 0 12px 24px rgba(49, 101, 244, 0.28);
font-size: 16px;
font-weight: 900;
cursor: pointer;
}
.toast {
position: fixed;
left: 50%;
bottom: calc(112px + env(safe-area-inset-bottom));
z-index: 10;
max-width: calc(100vw - 36px);
padding: 10px 14px;
border-radius: 999px;
background: rgba(0, 0, 0, 0.82);
color: #fff;
font-size: 13px;
font-weight: 700;
line-height: 1.2;
opacity: 0;
pointer-events: none;
transform: translateX(-50%) translateY(12px);
transition:
opacity 0.2s ease,
transform 0.2s ease;
}
.toast.show {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
@media (max-width: 360px) {
.page {
padding-left: 16px;
padding-right: 16px;
}
.invite-shell {
max-width: 312px;
}
.card-main {
padding-left: 18px;
padding-right: 18px;
}
.rewards {
gap: 14px;
}
.join-button {
width: 204px;
}
.download-dock {
padding-left: 16px;
padding-right: 16px;
}
.download-button {
min-width: 96px;
}
}
</style>
</head>
<body>
<main class="page">
<span class="ribbon one" aria-hidden="true"></span>
<span class="ribbon two" aria-hidden="true"></span>
<span class="ribbon three" aria-hidden="true"></span>
<section class="invite-shell" aria-label="Lalu landing card">
<div class="invite-card">
<div class="card-main">
<div class="brand-row">
<img
class="brand-logo"
src="assets/lalu-logo.png"
alt="Lalu"
/>
<p class="brand-name" id="hostName">Lalu</p>
</div>
<p
class="message"
data-i18n="lalu_landing.message"
>
送你一份礼物,快来和我一起玩吧!
</p>
<div class="rewards" aria-label="Invite rewards">
<div class="reward">
<div class="reward-visual">
<img
class="reward-frame"
src="assets/lalu-avatar-frame.png"
alt=""
/>
</div>
<span
class="reward-label"
data-i18n="lalu_landing.frame_duration"
>
3天
</span>
</div>
<div class="reward">
<div class="reward-visual">
<img
class="reward-coin"
src="assets/lalu-coin.png"
alt=""
/>
</div>
<span class="reward-label" id="coinAmount">
1000
</span>
</div>
</div>
</div>
<div class="card-action">
<button
type="button"
class="join-button"
id="joinButton"
data-i18n="lalu_landing.join_party"
>
加入派对
</button>
<p class="room-line">
<span data-i18n="lalu_landing.room_no">
房间号:
</span>
<span id="roomNo">112360</span>
</p>
</div>
</div>
</section>
</main>
<aside class="download-dock" aria-label="Lalu download">
<div class="app-summary">
<img src="assets/lalu-logo.png" alt="Lalu" />
<div class="app-copy">
<strong>Lalu</strong>
<span data-i18n="lalu_landing.tagline">
结识新朋友
</span>
</div>
</div>
<button
type="button"
class="download-button"
id="downloadButton"
data-i18n="lalu_landing.download"
>
下载
</button>
</aside>
<div class="toast" id="pageToast" aria-live="polite"></div>
<script src="../common/i18n.js"></script>
<script>
(function () {
var DEFAULT_ANDROID_URL =
'https://play.google.com/store/apps/details?id=com.org.laluparty';
var query = new URLSearchParams(window.location.search);
var els = {
hostName: document.getElementById('hostName'),
roomNo: document.getElementById('roomNo'),
coinAmount: document.getElementById('coinAmount'),
joinButton: document.getElementById('joinButton'),
downloadButton: document.getElementById('downloadButton'),
toast: document.getElementById('pageToast'),
};
function firstParam(names) {
for (var i = 0; i < names.length; i += 1) {
var value = String(query.get(names[i]) || '').trim();
if (value) return value;
}
return '';
}
function isIOS() {
return /iPad|iPhone|iPod/.test(navigator.userAgent);
}
function resolveDownloadURL() {
var commonURL = firstParam(['downloadUrl', 'download_url', 'url']);
var iosURL = firstParam(['iosUrl', 'ios_url']);
var androidURL =
firstParam(['androidUrl', 'android_url']) ||
DEFAULT_ANDROID_URL;
if (commonURL) return commonURL;
if (isIOS() && iosURL) return iosURL;
return androidURL;
}
function t(key, fallback) {
if (window.HyAppI18n && window.HyAppI18n.t) {
return window.HyAppI18n.t(key, fallback);
}
return fallback;
}
function showToast(message) {
els.toast.textContent = message;
els.toast.classList.add('show');
window.clearTimeout(showToast.timer);
showToast.timer = window.setTimeout(function () {
els.toast.classList.remove('show');
}, 1800);
}
function openDownload() {
var url = resolveDownloadURL();
if (!url) {
showToast(
t(
'lalu_landing.open_download_failed',
'下载地址未配置'
)
);
return;
}
window.location.href = url;
}
function renderParams() {
var hostName = firstParam([
'name',
'nickname',
'hostName',
'host_name',
]);
var roomNo = firstParam([
'roomNo',
'room_no',
'roomId',
'room_id',
'room',
]);
var coinAmount = firstParam([
'coins',
'coin',
'coinAmount',
'coin_amount',
]);
if (hostName) els.hostName.textContent = hostName;
if (roomNo) els.roomNo.textContent = roomNo;
if (coinAmount) els.coinAmount.textContent = coinAmount;
}
renderParams();
els.joinButton.addEventListener('click', openDownload);
els.downloadButton.addEventListener('click', openDownload);
})();
</script>
</body>
</html>