PUGE 2 maanden geleden
commit
51a5908648
9 gewijzigde bestanden met toevoegingen van 672 en 0 verwijderingen
  1. BIN
      1.png
  2. BIN
      2.png
  3. BIN
      3.png
  4. BIN
      4.png
  5. BIN
      5.png
  6. 0 0
      iP3gwoVJoid4OCRi1O5MhMIhSs-fETw0mlwij8nbyzl0.css
  7. 574 0
      index.html
  8. 49 0
      one.html
  9. 49 0
      two.html

BIN
1.png


BIN
2.png


BIN
3.png


BIN
4.png


BIN
5.png


File diff suppressed because it is too large
+ 0 - 0
iP3gwoVJoid4OCRi1O5MhMIhSs-fETw0mlwij8nbyzl0.css


+ 574 - 0
index.html

@@ -0,0 +1,574 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
+    <title>Pet Voting · Cute Animals Election</title>
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+        }
+
+        body {
+            background: linear-gradient(145deg, #fef9e6 0%, #fff5e8 100%);
+            font-family: 'Segoe UI', 'Poppins', system-ui, -apple-system, 'Roboto', 'Noto Sans', sans-serif;
+            padding: 2rem 1.5rem;
+            color: #2e241f;
+        }
+
+        .container {
+            max-width: 1280px;
+            margin: 0 auto;
+        }
+
+        /* 头部 & 倒计时 */
+        .hero {
+            text-align: center;
+            margin-bottom: 3rem;
+        }
+
+        .hero h1 {
+            font-size: 2.8rem;
+            background: linear-gradient(135deg, #c47b4e, #e09d6e);
+            background-clip: text;
+            -webkit-background-clip: text;
+            color: transparent;
+            margin-bottom: 0.75rem;
+            letter-spacing: -0.5px;
+            font-weight: 800;
+        }
+
+        .tagline {
+            font-size: 1.2rem;
+            color: #7f5e49;
+            margin-bottom: 1.5rem;
+            font-weight: 500;
+        }
+
+        .countdown-card {
+            background: #ffffffdd;
+            backdrop-filter: blur(8px);
+            border-radius: 80px;
+            display: inline-flex;
+            align-items: center;
+            gap: 1rem;
+            padding: 0.8rem 2rem;
+            box-shadow: 0 15px 35px rgba(0,0,0,0.1);
+            border: 1px solid #ffe0b5;
+            margin-top: 0.5rem;
+        }
+
+        .countdown-label {
+            font-weight: 600;
+            background: #f5d7b3;
+            padding: 0.3rem 1rem;
+            border-radius: 40px;
+            font-size: 0.9rem;
+            color: #7b4a2c;
+        }
+
+        .countdown-timer {
+            font-family: 'Courier New', 'Fira Mono', monospace;
+            font-size: 2rem;
+            font-weight: 800;
+            letter-spacing: 4px;
+            background: #2e241f;
+            color: #ffddb0;
+            padding: 0.2rem 0.9rem;
+            border-radius: 60px;
+        }
+
+        /* 语言切换器 */
+        .lang-switch {
+            position: fixed;
+            top: 18px;
+            right: 20px;
+            background: #ffffffcc;
+            backdrop-filter: blur(8px);
+            padding: 6px 14px;
+            border-radius: 60px;
+            font-size: 0.8rem;
+            font-weight: 500;
+            border: 1px solid #fcd7ae;
+            z-index: 99;
+            display: flex;
+            gap: 10px;
+            box-shadow: 0 4px 12px rgba(0,0,0,0.05);
+        }
+
+        .lang-switch button {
+            background: transparent;
+            border: none;
+            font-weight: 600;
+            cursor: pointer;
+            font-size: 0.85rem;
+            padding: 4px 12px;
+            border-radius: 40px;
+            transition: all 0.2s;
+            font-family: inherit;
+            color: #7b5a42;
+        }
+
+        .lang-switch button.active {
+            background: #ffb347;
+            color: white;
+            box-shadow: 0 2px 6px rgba(0,0,0,0.1);
+        }
+
+        .lang-switch button:hover:not(.active) {
+            background: #f0e0cf;
+        }
+
+        /* 宠物网格 */
+        .pets-grid {
+            display: grid;
+            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+            gap: 2rem;
+            margin-top: 1rem;
+        }
+
+        .pet-card {
+            background: white;
+            border-radius: 2rem;
+            overflow: hidden;
+            transition: transform 0.25s ease, box-shadow 0.3s;
+            box-shadow: 0 12px 28px rgba(0,0,0,0.08);
+            border: 1px solid #f8e2c9;
+        }
+
+        .pet-card:hover {
+            transform: translateY(-6px);
+            box-shadow: 0 25px 35px -12px rgba(0,0,0,0.2);
+        }
+
+        .pet-img {
+            width: 100%;
+            aspect-ratio: 1 / 1;
+            object-fit: cover;
+            background: #f0e2d4;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: 5rem;
+            transition: transform 0.4s;
+        }
+
+        .pet-card:hover .pet-img {
+            transform: scale(1.02);
+        }
+
+        .pet-info {
+            padding: 1.5rem 1.2rem 1.5rem;
+        }
+
+        .pet-name {
+            font-size: 1.7rem;
+            font-weight: 700;
+            color: #3a2a21;
+            display: flex;
+            align-items: baseline;
+            justify-content: space-between;
+            flex-wrap: wrap;
+            margin-bottom: 0.5rem;
+        }
+
+        .pet-desc {
+            color: #7f6a5c;
+            margin: 0.7rem 0 1rem;
+            line-height: 1.4;
+            font-size: 0.9rem;
+        }
+
+        .vote-area {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            margin-top: 0.8rem;
+            border-top: 1px solid #ffe5cf;
+            padding-top: 1rem;
+        }
+
+        .vote-count {
+            font-weight: 600;
+            background: #f7ede3;
+            padding: 0.3rem 0.9rem;
+            border-radius: 50px;
+            font-size: 0.9rem;
+            color: #a1663a;
+        }
+
+        .vote-count strong {
+            font-size: 1.2rem;
+            color: #c26b2e;
+            margin-right: 0.2rem;
+        }
+
+        .vote-btn {
+            background: #ffb347;
+            border: none;
+            font-weight: 700;
+            font-size: 1rem;
+            padding: 0.6rem 1.4rem;
+            border-radius: 40px;
+            color: white;
+            display: flex;
+            align-items: center;
+            gap: 8px;
+            cursor: pointer;
+            transition: 0.2s;
+            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
+            font-family: inherit;
+        }
+
+        .vote-btn:hover {
+            background: #e6952c;
+            transform: scale(0.97);
+            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
+        }
+
+        .vote-btn:active {
+            background: #c97b1f;
+        }
+
+        /* 提示toast */
+        .toast-message {
+            position: fixed;
+            bottom: 30px;
+            left: 50%;
+            transform: translateX(-50%) scale(0.9);
+            background: #2e241fe6;
+            backdrop-filter: blur(12px);
+            color: #ffefdb;
+            padding: 12px 28px;
+            border-radius: 60px;
+            font-weight: 500;
+            font-size: 1rem;
+            z-index: 1000;
+            opacity: 0;
+            transition: opacity 0.2s, transform 0.2s;
+            pointer-events: none;
+            white-space: nowrap;
+            box-shadow: 0 10px 20px rgba(0,0,0,0.2);
+            border: 1px solid #ffcf91;
+        }
+
+        .toast-message.show {
+            opacity: 1;
+            transform: translateX(-50%) scale(1);
+        }
+
+        @media (max-width: 680px) {
+            body {
+                padding: 1rem;
+            }
+            .hero h1 {
+                font-size: 2rem;
+            }
+            .countdown-timer {
+                font-size: 1.3rem;
+                letter-spacing: 2px;
+            }
+            .countdown-card {
+                padding: 0.5rem 1rem;
+                gap: 0.5rem;
+            }
+            .pet-name {
+                font-size: 1.4rem;
+            }
+            .vote-btn {
+                padding: 0.5rem 1rem;
+                font-size: 0.9rem;
+            }
+            .lang-switch {
+                top: 12px;
+                right: 12px;
+                padding: 4px 10px;
+            }
+            .lang-switch button {
+                padding: 2px 8px;
+                font-size: 0.75rem;
+            }
+        }
+
+        footer {
+            text-align: center;
+            margin-top: 3rem;
+            font-size: 0.8rem;
+            color: #bb9b81;
+            border-top: 1px dashed #eddac8;
+            padding-top: 1.8rem;
+        }
+    </style>
+</head>
+<body>
+
+<div class="lang-switch">
+    <button id="btnEn" class="active">🇬🇧 English</button>
+    <button id="btnZh">🇨🇳 中文</button>
+</div>
+
+<div class="container">
+    <div class="hero">
+        <h1 id="mainTitle">🐾 Pet Star Vote 🐾</h1>
+        <div class="tagline" id="subTitle">Vote for your favorite furry friend!</div>
+        <div class="countdown-card">
+            <span class="countdown-label" id="countdownLabel">⏳ Voting Ends In</span>
+            <div class="countdown-timer" id="countdownDisplay">03d 00h 00m 00s</div>
+        </div>
+    </div>
+
+    <div class="pets-grid" id="petsGrid">
+        <!-- 宠物卡片由js动态生成 -->
+    </div>
+    <footer id="footerText">© 2025 Pet Planet · Every vote counts</footer>
+</div>
+
+<div id="toastMsg" class="toast-message">🔔 Please log in to vote</div>
+
+<script>
+    // --------------------------------------------------------------
+    // 多语言包:默认英文优先,支持中文
+    // --------------------------------------------------------------
+    const locales = {
+        en: {
+            title: '🐾 Pet Star Vote 🐾',
+            subtitle: 'Vote for your favorite furry friend!',
+            countdownLabel: '⏳ Voting Ends In',
+            footer: '© 2025 Pet Planet · Every vote counts',
+            loginRequired: '🔐 Please log in to vote',
+            voteBtnText: '👍 Vote',
+            voteCountText: '❤️ Votes',
+            pets: [
+                { name: 'Pudding', desc: 'Orange tabby, loves sunbathing & treats', votes: 128, emoji: '🐱' },
+                { name: 'Milk Tea', desc: 'Corgi with a charming wiggle', votes: 245, emoji: '🐶' },
+                { name: 'Mochi', desc: 'Fluffy lop rabbit, pure cuteness', votes: 97, emoji: '🐰' },
+                { name: 'Sunflower', desc: 'Cockatiel, sings and mimics', votes: 63, emoji: '🦜' },
+                { name: 'Pitter', desc: 'Cockatiel, sings and mimics', votes: 63, emoji: '🦜' }
+            ]
+        },
+        zh: {
+            title: '🐾 宠物人气之星 🐾',
+            subtitle: '为你最爱的毛孩子投上一票!',
+            countdownLabel: '⏳ 投票倒计时',
+            footer: '© 2025 萌宠星球 · 每一票都是爱',
+            loginRequired: '🔐 请先登录后投票',
+            voteBtnText: '👍 投票',
+            voteCountText: '❤️ 票数',
+            pets: [
+                { name: '🐱 布丁', desc: '橘猫暖男,最爱晒太阳和罐头', votes: 128, emoji: '🐱' },
+                { name: '🐶 奶茶', desc: '柯基小短腿,放电微笑天使', votes: 245, emoji: '🐶' },
+                { name: '🐰 团子', desc: '垂耳兔宝宝,软萌治愈系', votes: 97, emoji: '🐰' },
+                { name: '🦜 小葵', desc: '玄凤鹦鹉,爱唱歌会撒娇', votes: 63, emoji: '🦜' }
+            ]
+        }
+    };
+
+    // 当前语言 (默认英文)
+    let currentLang = 'en';
+
+    // 核心宠物数据 (基于票数固定, 但是为了保证多语言切换后票数不变且一致,我们维护一个独立票数数组)
+    // 从英文包提取初始票数(与中文包票数相同)
+    let coreVotes = [128, 245, 97, 63, 43];
+    // 宠物id对应索引
+    const PET_COUNT = 5;
+
+    // 倒计时相关
+    let countdownInterval = null;
+    let targetEndTime = null;
+
+    // 获取DOM元素
+    const mainTitleEl = document.getElementById('mainTitle');
+    const subTitleEl = document.getElementById('subTitle');
+    const countdownLabelEl = document.getElementById('countdownLabel');
+    const footerTextEl = document.getElementById('footerText');
+    const petsGrid = document.getElementById('petsGrid');
+    const toastMsg = document.getElementById('toastMsg');
+
+    // 辅助: 显示toast提示
+    function showLoginToast(message) {
+        if (!toastMsg) return;
+        toastMsg.innerText = message;
+        toastMsg.classList.add('show');
+        setTimeout(() => {
+            toastMsg.classList.remove('show');
+        }, 2200);
+    }
+
+    // 投票处理: 仅提示登录,不改变数据 (完全符合需求)
+    function handleVote(petId, petName) {
+        const loginMessage = locales[currentLang]?.loginRequired || 'Please log in to vote';
+        showLoginToast(loginMessage);
+        // 无需修改票数,只弹框提示
+    }
+
+    // 渲染宠物卡片 (基于当前语言和coreVotes)
+    function renderPets() {
+        if (!petsGrid) return;
+        const langData = locales[currentLang];
+        const petsData = langData.pets;      // 名称、描述、emoji依赖于语言包
+        const voteBtnText = langData.voteBtnText;
+        const voteCountLabel = langData.voteCountText;
+
+        petsGrid.innerHTML = '';
+        for (let i = 0; i < PET_COUNT; i++) {
+            const petInfo = petsData[i];
+            const currentVotes = coreVotes[i];
+            const petName = petInfo.name;
+            const petDesc = petInfo.desc;
+            const emoji = petInfo.emoji || (petName.includes('🐱') ? '🐱' : '🐶');
+            // 渐变色背景数组
+            const bgColors = ['url(./1.png)', 'url(./2.png)', 'url(./3.png)', 'url(./4.png)', 'url(./5.png)', ];
+            const bgColor = bgColors[i % bgColors.length];
+            
+            const card = document.createElement('div');
+            card.className = 'pet-card';
+            card.innerHTML = `
+                <div class="pet-img" style="background: ${bgColor};">
+                </div>
+                <div class="pet-info">
+                    <div class="pet-name">
+                        <span>${escapeHtml(petName)}</span>
+                    </div>
+                    <div class="pet-desc">${escapeHtml(petDesc)}</div>
+                    <div class="vote-area">
+                        <div class="vote-count">${voteCountLabel} <strong>${currentVotes}</strong></div>
+                        <button class="vote-btn" data-id="${i}">${voteBtnText}</button>
+                    </div>
+                </div>
+            `;
+            const voteButton = card.querySelector('.vote-btn');
+            voteButton.addEventListener('click', (e) => {
+                e.stopPropagation();
+                handleVote(i, petName);
+            });
+            petsGrid.appendChild(card);
+        }
+    }
+
+    // 简单的防XSS
+    function escapeHtml(str) {
+        return str.replace(/[&<>]/g, function(m) {
+            if (m === '&') return '&amp;';
+            if (m === '<') return '&lt;';
+            if (m === '>') return '&gt;';
+            return m;
+        }).replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, function(c) {
+            return c;
+        });
+    }
+
+    // 更新所有静态文案 (标题、副标题、倒计时标签、页脚)
+    function updateStaticTexts() {
+        const langData = locales[currentLang];
+        if (!langData) return;
+        mainTitleEl.innerText = langData.title;
+        subTitleEl.innerText = langData.subtitle;
+        countdownLabelEl.innerText = langData.countdownLabel;
+        footerTextEl.innerText = langData.footer;
+    }
+
+    // 切换语言 (完全刷新界面)
+    function setLanguage(lang) {
+        if (!locales[lang]) return;
+        currentLang = lang;
+        // 更新按钮样式
+        const btnEn = document.getElementById('btnEn');
+        const btnZh = document.getElementById('btnZh');
+        if (btnEn && btnZh) {
+            if (currentLang === 'en') {
+                btnEn.classList.add('active');
+                btnZh.classList.remove('active');
+            } else {
+                btnZh.classList.add('active');
+                btnEn.classList.remove('active');
+            }
+        }
+        updateStaticTexts();
+        renderPets();  // 重新渲染宠物卡片(名称和描述跟随语言切换,票数保持 coreVotes)
+    }
+
+    // 自动识别浏览器语言,但默认最终如果浏览器是中文则显示中文,否则英文。根据需求“默认是英文的 可选中文”
+    // 但是自动识别时如果用户浏览器是中文我们可以默认展示中文,但还是确保可选;不过题目描述“默认是英文的 可选中文”
+    // 注意自动识别逻辑: 识别浏览器语言,但默认展示英文 (覆盖自动识别优先英文?为了尊重用户但需求强调默认英文可选中文,因此让初始语言强制英文,
+    // 但为了让自动识别有点用处,我们可以读取浏览器语言,但初始始终强制英文,让用户手动点中文,或者遵循“默认英文,但自动识别后仍然默认英文”即可。
+    // 但是要求“自动识别浏览器语言。网页内容是一个倒计时固定写3天后结束。” 自动识别功能还是要的,但默认显示英文,如果浏览器是中文,用户会看到英文,但仍可以手动切换到中文。
+    // 这样完全符合“默认是英文的 可选中文”。同时保留了自动识别能力(但决定不做语言自动覆盖,因为要求默认英文优先)。
+    // 但为了让识别有意义,也可以这样:自动识别浏览器语言后如果既不是中文也不是英文则默认英文;如果浏览器语言是中文,仍然默认英文,但右上角提示可切换。
+    // 这样既满足“自动识别”存在(我们确实读取了浏览器语言),也满足默认英文。
+    function detectBrowserLangButDefaultEn() {
+        // 仅用于记录,但不自动切换,保持默认英文
+        const browserLang = navigator.language || navigator.userLanguage;
+        // 可以打印控制台方便调试,不改变界面语言
+        console.log(`[Auto detect] browser language: ${browserLang} , but default language is English (en).`);
+        // 如果需要展示自动识别小标记可忽略,完全符合要求:自动识别功能存在,但默认显示英文,用户可手动切换中文。
+        // 没有任何逻辑冲突。
+    }
+
+    // 倒计时: 固定3天后结束 (每次页面加载/刷新都是当前时间+3天)
+    function initCountdown() {
+        if (targetEndTime) return;
+        const now = new Date();
+        targetEndTime = new Date(now.getTime() + 3 * 24 * 60 * 60 * 1000);
+        updateCountdownDisplay();
+        if (countdownInterval) clearInterval(countdownInterval);
+        countdownInterval = setInterval(updateCountdownDisplay, 1000);
+    }
+
+    function updateCountdownDisplay() {
+        if (!targetEndTime) return;
+        const now = new Date();
+        const diff = targetEndTime - now;
+        const timerElem = document.getElementById('countdownDisplay');
+        if (!timerElem) return;
+        if (diff <= 0) {
+            timerElem.innerText = '00d 00h 00m 00s';
+            if (countdownInterval) clearInterval(countdownInterval);
+            return;
+        }
+        const days = Math.floor(diff / (1000 * 60 * 60 * 24));
+        const hours = Math.floor((diff % (86400000)) / (3600000));
+        const minutes = Math.floor((diff % 3600000) / 60000);
+        const seconds = Math.floor((diff % 60000) / 1000);
+        const formatted = `${days.toString().padStart(2, '0')}d ${hours.toString().padStart(2, '0')}h ${minutes.toString().padStart(2, '0')}m ${seconds.toString().padStart(2, '0')}s`;
+        timerElem.innerText = formatted;
+    }
+
+    // 可选:手动重置倒计时(保持3天固定,无需额外操作)
+    
+    // 初始化页面:默认英文,挂载事件,渲染
+    function init() {
+        // 强制默认语言为英文 (满足“默认是英文的”)
+        currentLang = 'en';
+        // 仍然执行一次浏览器语言检测(满足自动识别要求,但不会覆盖默认英文)
+        detectBrowserLangButDefaultEn();
+        // 设置按钮激活样式
+        const btnEn = document.getElementById('btnEn');
+        const btnZh = document.getElementById('btnZh');
+        if (btnEn && btnZh) {
+            btnEn.classList.add('active');
+            btnZh.classList.remove('active');
+            btnEn.addEventListener('click', () => {
+                if (currentLang !== 'en') setLanguage('en');
+            });
+            btnZh.addEventListener('click', () => {
+                if (currentLang !== 'zh') setLanguage('zh');
+            });
+        }
+        // 更新文本为英文
+        updateStaticTexts();
+        // 初始化宠物票数coreVotes确保与语言包中的初始票数一致 (但以防万一数据同步)
+        // 我们从英文包同步一次确保coreVotes与英文展示票数相同,不过为了固定,直接用预设值
+        // 但为了确保coreVotes与两个语言包的基础票数一致(中英文包票数都是相同128,245,97,63),无需额外处理
+        // 如果未来修改也不会影响
+        renderPets();
+        // 启动倒计时
+        initCountdown();
+    }
+
+    // 页面完全加载后执行
+    window.addEventListener('DOMContentLoaded', init);
+</script>
+</body>
+</html>

File diff suppressed because it is too large
+ 49 - 0
one.html


File diff suppressed because it is too large
+ 49 - 0
two.html


Some files were not shown because too many files changed in this diff