Quellcode durchsuchen

调整share页面央视

guoziyun vor 10 Monaten
Ursprung
Commit
bc184a52d2
5 geänderte Dateien mit 461 neuen und 232 gelöschten Zeilen
  1. 9 0
      config/translate.js
  2. 1 1
      routes/v2/share.js
  3. 136 0
      test/placeholder.html
  4. 182 143
      views/v2/share copy.ejs
  5. 133 88
      views/v2/share.ejs

+ 9 - 0
config/translate.js

@@ -717,6 +717,14 @@ let downloadApp = {
   ja: 'アプリをダウンロードする',
 }
 
+let claimBonus = {
+  zh: '领取奖励',
+  en: 'Claim Bonus',
+  es: 'Reclamar Bonificación',
+  pt: 'Resgatar Bônus',
+  ja: 'ボーナスを受け取る',
+}
+
 let artColor = {
   zh: 'Art Color',
   en: 'Art Color',
@@ -841,6 +849,7 @@ let translate = {
   TOOLSTRICKS,
 
   downloadApp,
+  claimBonus,
   artColor,
   colorRelex,
   detail,

+ 1 - 1
routes/v2/share.js

@@ -19,7 +19,7 @@ router.get('/:id', function (req, res, next) {
     let applink = `https://art.pcoloring.com${req.originalUrl}`;
     let downlink = `https://pcoloring.com/anc/`;
 
-    let openapplink = applink.concat(req.originalUrl.includes('?') ? '&pullapp=1' : '?pullapp=1');
+    let openapplink = applink.concat(req.originalUrl.includes('?') ? '&check=1' : '?check=1');
 
 
     const userAgent = req.headers['user-agent'];

+ 136 - 0
test/placeholder.html

@@ -0,0 +1,136 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>图片占位符示例</title>
+  <style>
+    /* 容器样式 - 关键:通过JS动态设置尺寸 */
+    .image-container {
+      position: relative;
+      max-width: 90%;
+      margin: 20px auto;
+      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+      border-radius: 8px;
+      overflow: hidden;
+    }
+
+    /* 占位符样式 - 与图片尺寸完全一致 */
+    .image-placeholder {
+      width: 100%;
+      height: 100%;
+      background-color: #f5f5f5;
+      /* 浅灰色背景 */
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+
+    /* 加载动画 - 旋转圆圈 */
+    .loading-spinner {
+      width: 40px;
+      height: 40px;
+      border: 4px solid #e0e0e0;
+      border-top: 4px solid #ff6b6b;
+      /* 主题色 */
+      border-radius: 50%;
+      animation: spin 1s linear infinite;
+    }
+
+    @keyframes spin {
+      0% {
+        transform: rotate(0deg);
+      }
+
+      100% {
+        transform: rotate(360deg);
+      }
+    }
+
+    /* 图片样式 - 初始隐藏,加载后显示 */
+    .target-image {
+      width: 100%;
+      height: 100%;
+      object-fit: contain;
+      opacity: 0;
+      /* 初始透明 */
+      transition: opacity 0.3s ease;
+      /* 淡入效果 */
+    }
+
+    /* 图片加载完成后显示 */
+    .target-image.loaded {
+      opacity: 1;
+    }
+  </style>
+</head>
+
+<body>
+  <!-- 图片容器:包含占位符和图片 -->
+  <div class="image-container">
+    <div class="image-placeholder" id="placeholder">
+      <div class="loading-spinner"></div>
+    </div>
+    <img id="targetImg" class="target-image"
+      src="http://color.jccytech.cn/thumbs/coloring-page/done/480/614d6e7987ca20188d3cc089.webp" alt="示例图片">
+  </div>
+
+  <script>
+    // 目标图片URL
+    const imageUrl = "http://color.jccytech.cn/thumbs/coloring-page/done/480/614d6e7987ca20188d3cc089.webp";
+    const container = document.querySelector('.image-container');
+    const placeholder = document.getElementById('placeholder');
+    const targetImg = document.getElementById('targetImg');
+
+    // 步骤1:预加载图片获取尺寸
+    function getImageDimensions(url) {
+      return new Promise((resolve, reject) => {
+        const tempImg = new Image();
+        tempImg.src = url;
+        // 图片元信息加载完成(无需加载完整内容)
+        tempImg.onload = () => {
+          resolve({
+            width: tempImg.naturalWidth,
+            height: tempImg.naturalHeight
+          });
+        };
+        tempImg.onerror = () => reject(new Error("图片尺寸获取失败"));
+      });
+    }
+
+    // 步骤2:设置占位容器尺寸(与图片一致)
+    async function setupPlaceholder() {
+      try {
+        const { width, height } = await getImageDimensions(imageUrl);
+
+        // 设置容器尺寸(与图片完全一致)
+        container.style.width = `${width}px`;
+        container.style.height = `${height}px`;
+
+        // 对于响应式设计,可改为百分比宽度(根据实际需求)
+        // container.style.width = '100%';
+        // container.style.maxWidth = `${width}px`;
+        // container.style.height = 'auto';
+        // container.style.aspectRatio = `${width}/${height}`; // 宽高比
+
+      } catch (error) {
+        console.error(error);
+        // 失败时使用默认尺寸
+        container.style.width = '800px';
+        container.style.height = '600px';
+      }
+    }
+
+    // 步骤3:图片加载完成后隐藏占位符
+    targetImg.onload = function () {
+      targetImg.classList.add('loaded'); // 图片淡入
+      placeholder.style.display = 'none'; // 隐藏占位符
+    };
+
+    // 初始化
+    setupPlaceholder();
+  </script>
+</body>
+
+</html>

+ 182 - 143
views/v2/share copy.ejs

@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html lang="en">
+<html lang="<%= lang %>">
 
 <head>
   <meta charset="UTF-8">
@@ -7,38 +7,31 @@
   <meta http-equiv="x-ua-compatible" content="ie=edge">
   <title>Art Color</title>
 
-  <link rel="alternate" href="https://art.pcoloring.com/share/67f33f5d8f7086254fee7dd2?lang=en" hrefLang="en" />
-  <link rel="alternate" href="https://art.pcoloring.com/share/67f33f5d8f7086254fee7dd2?lang=zh" hrefLang="zh" />
-  <link rel="alternate" href="https://art.pcoloring.com/share/67f33f5d8f7086254fee7dd2?lang=es" hrefLang="es" />
-  <link rel="alternate" href="https://art.pcoloring.com/share/67f33f5d8f7086254fee7dd2?lang=pt" hrefLang="pt" />
-  <link rel="alternate" href="https://art.pcoloring.com/share/67f33f5d8f7086254fee7dd2?lang=ja" hrefLang="ja" />
-  <link rel="alternate" href="https://art.pcoloring.com/share/67f33f5d8f7086254fee7dd2" hrefLang="x-default" />
+  <link rel="alternate" href="https://art.pcoloring.com/share/<%= id %>?lang=en" hrefLang="en" />
+  <link rel="alternate" href="https://art.pcoloring.com/share/<%= id %>?lang=zh" hrefLang="zh" />
+  <link rel="alternate" href="https://art.pcoloring.com/share/<%= id %>?lang=es" hrefLang="es" />
+  <link rel="alternate" href="https://art.pcoloring.com/share/<%= id %>?lang=pt" hrefLang="pt" />
+  <link rel="alternate" href="https://art.pcoloring.com/share/<%= id %>?lang=ja" hrefLang="ja" />
+  <link rel="alternate" href="https://art.pcoloring.com/share/<%= id %>" hrefLang="x-default" />
 
-  <meta name="description" content="Color and Relax!">
+  <meta name="description" content="<%= translate.colorRelex[lang] %>">
   <meta name="keywords" content="color, paint, app, ios, android, game">
 
   <meta property="og:site_name" content="art.pcoloring.com">
   <meta property="og:title" content="Art Color">
-  <meta property="og:description" content="Color and Relax!">
-  <meta property="og:image"
-    content="http://color.jccytech.cn/thumbs/coloring-page/done/480/67f33f5d8f7086254fee7dd2.webp">
+  <meta property="og:description" content="<%= translate.colorRelex[lang] %>">
+  <meta property="og:image" content="<%= imageUrl %>">
   <meta property="og:type" content="website">
 
-  <!-- <meta property="fb:page_id" content="565152927316964"> -->
-
-  <!-- MARK: Universal Link / Android App Link 的核心配置 -->
-  <!-- 这些 meta 标签的值应该是完整的 HTTPS 链接,Facebook 会识别并尝试拉起 App -->
-  <meta property="og:url" content="https://art.pcoloring.com/share/67f33f5d8f7086254fee7dd2" />
-  <!-- **Universal Link 路径** -->
-  <meta property="al:ios:url" content="https://art.pcoloring.com/share/67f33f5d8f7086254fee7dd2" />
-  <!-- **Universal Link 路径** -->
-  <meta property="al:ios:app_store_id" content="1575480118" /> <!-- **iOS App Store ID** -->
-  <meta property="al:ios:app_name" content="Art Color" /> <!-- **iOS 应用名称** -->
-
-  <meta property="al:android:package" content="com.pcoloring.art.puzzle.color.by.number" /> <!-- **Android 包名** -->
-  <meta property="al:android:url" content="https://art.pcoloring.com/share/67f33f5d8f7086254fee7dd2" />
-  <!-- ** Universal Link 路径** -->
-  <meta property="al:android:app_name" content="Art Color" /> <!-- **Android 应用名称** -->
+  <meta property="og:url" content="<%= applink %>" />
+  <meta property="al:ios:url" content="<%= applink %>" />
+  <meta property="al:ios:app_store_id" content="1575480118" />
+  <meta property="al:ios:app_name" content="Art Color" />
+
+  <meta property="al:android:package" content="com.pcoloring.art.puzzle.color.by.number" />
+  <meta property="al:android:url" content="<%= applink %>" />
+  <meta property="al:android:app_name" content="Art Color" />
+
   <meta name="apple-itunes-app" content="app-id=1575480118">
 
   <link rel="icon" href="/assets/icon/favicon.ico" type="image/x-icon">
@@ -63,33 +56,24 @@
       font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
       display: flex;
       flex-direction: column;
-      /* 垂直方向排列子元素 */
       height: 100vh;
-      /* 严格限制高度为视口高度,确保不超出 */
       margin: 0;
-      padding: 20px;
-      /* 页面内边距 */
       box-sizing: border-box;
-      /* 盒模型为边框盒 */
       background-color: var(--background-color);
       color: var(--text-color);
       line-height: 1.6;
       align-items: center;
-      /* 水平居中所有flex子项 */
     }
 
-    /* 头部容器 */
     .header-container {
       width: 100%;
-      /* 占据全部宽度 */
+      height: 20vh;
+      margin-top: 10px;
       display: flex;
       flex-direction: column;
       align-items: center;
       justify-content: center;
-      padding-bottom: 15px;
-      /* 与下方内容留出间距,略微缩小 */
       flex-shrink: 0;
-      /* 不会收缩 */
     }
 
     .app-icon {
@@ -101,10 +85,8 @@
     }
 
     .app-icon img {
-      width: 90px;
-      /* 图标调小 */
-      height: 90px;
-      /* 图标调小 */
+      width: auto;
+      height: 100%;
       border: 3px solid #eeeeee;
       border-radius: 10px;
       box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
@@ -113,70 +95,64 @@
 
     .app-title {
       font-size: 1.8rem;
-      /* 标题调小 */
       font-weight: 700;
       margin-bottom: 15px;
-      /* 调整为与图标的间距,略微缩小 */
       text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
       text-align: center;
-      /* 确保标题在移动端也居中 */
     }
 
-    /* 图片和 Canvas 容器,占据剩余所有空间 */
+    /* 图片容器 - 关键优化部分 */
     .image-canvas-container {
       position: relative;
-      width: 100%;
-      /* 占据所有可用宽度 */
-      max-width: 600px;
-      /* 限制最大宽度,保持美观 */
-      flex-grow: 1;
-      /* 占据所有剩余垂直空间 */
-      min-height: 0;
-      /* 允许flex-grow在必要时收缩 */
-      display: flex;
-      /* 内部使用flex布局来居中图片和canvas */
-      justify-content: center;
-      align-items: center;
+      max-width: 90%;
+      display: block;
+      margin: 0 auto;
       box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
-      /* 添加阴影效果 */
       border-radius: 12px;
-      /* 圆角 */
       overflow: hidden;
-      /* 隐藏超出容器的内容 */
-      margin-bottom: 15px;
-      /* 与下方按钮留出间距,略微缩小 */
-      /* aspect-ratio: 1 / 1; /* 移除1:1比例,让高度自适应剩余空间 */
+      background-color: #f0f0f0;
+      /* 初始占位样式,会被JS动态修改 */
+      width: 100%;
+      height: 0;
+      padding-bottom: 75%;
+      /* 默认4:3比例,会被JS动态调整 */
     }
 
-    /* 图片样式:使其响应式并填充容器 */
-    .image-canvas-container img {
+    .image-canvas-container img,
+    .image-canvas-container canvas {
       position: absolute;
-      /* 绝对定位,与canvas重叠 */
-      display: block;
-      /* 移除图片底部空白 */
+      top: 0;
+      left: 0;
       width: 100%;
-      /* 宽度填充父容器 */
       height: 100%;
-      /* 高度填充父容器 */
       object-fit: contain;
-      /* 保持图片比例,适应容器 */
       border-radius: 12px;
-      /* 与容器相同的圆角 */
+    }
+
+    .image-canvas-container img {
+      opacity: 0;
+      transition: opacity 0.3s ease;
       z-index: 100;
-      /* 确保图片在canvas之上 */
     }
 
-    /* Canvas 样式:绝对定位,与图片完全重叠 */
+    .image-canvas-container img.loaded {
+      opacity: 1;
+    }
+
     .image-canvas-container canvas {
-      position: absolute;
-      top: 0;
-      left: 0;
-      width: 100%;
-      height: 100%;
-      border-radius: 12px;
-      /* 与容器相同的圆角 */
       z-index: 50;
-      /* 在图片之下 */
+    }
+
+    .buttons {
+      width: 100%;
+      max-width: 550px;
+      display: flex;
+      flex-wrap: wrap;
+      flex-direction: column;
+      justify-content: center;
+      align-items: center;
+      margin-top: 30px;
+      flex-shrink: 0;
     }
 
     .btn {
@@ -224,7 +200,6 @@
       justify-content: center;
       transition: all 0.3s ease;
       z-index: 110;
-      /* 确保播放按钮在图片之上 */
     }
 
     .play-button:hover {
@@ -242,25 +217,40 @@
       margin-left: 5px;
     }
 
-    /* 按钮容器在底部 */
-    .buttons {
+    /* 加载占位符样式 */
+    .image-placeholder {
+      position: absolute;
+      top: 0;
+      left: 0;
       width: 100%;
-      /* 占据全部宽度 */
-      max-width: 550px;
-      /* 限制最大宽度 */
+      height: 100%;
+      background-color: #f0f0f0;
       display: flex;
-      flex-wrap: wrap;
-      flex-direction: column;
-      /* 按钮垂直排列 */
-      justify-content: center;
       align-items: center;
-      margin-top: 15px;
-      /* 与上方内容留出间距,略微缩小 */
-      flex-shrink: 0;
-      /* 不会收缩 */
+      justify-content: center;
+      z-index: 20;
+    }
+
+    .loading-spinner {
+      width: 40px;
+      height: 40px;
+      border: 4px solid #ddd;
+      border-top: 4px solid var(--primary-color);
+      border-radius: 50%;
+      animation: spin 1s linear infinite;
     }
 
-    /* MARK: 微信引导层样式 */
+    @keyframes spin {
+      0% {
+        transform: rotate(0deg);
+      }
+
+      100% {
+        transform: rotate(360deg);
+      }
+    }
+
+    /* 微信引导层样式 */
     .wechat-guide-overlay {
       position: fixed;
       top: 0;
@@ -268,11 +258,8 @@
       width: 100%;
       height: 100%;
       background-color: rgba(0, 0, 0, 0.75);
-      /* 半透明黑色背景 */
       z-index: 9999;
-      /* 确保在最上层 */
       display: none;
-      /* 默认隐藏 */
       justify-content: center;
       align-items: center;
       color: white;
@@ -285,101 +272,133 @@
 
     .wechat-guide-overlay.active {
       display: flex;
-      /* 显示引导层 */
     }
 
     .wechat-guide-arrow {
       position: absolute;
       top: 10px;
-      /* 箭头位置靠近右上角 */
       right: 20px;
       width: 80px;
       height: 80px;
       background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" transform="rotate(90 12 12)"/></svg>') no-repeat center center;
       background-size: contain;
       transform: rotate(90deg);
-      /* 旋转箭头指向右下 */
     }
 
     .wechat-guide-text {
       margin-top: 100px;
-      /* 留出箭头空间 */
       line-height: 1.8;
     }
 
     .wechat-guide-text strong {
       color: var(--accent-color);
-      /* 突出显示关键文字 */
     }
 
     @media (max-width: 768px) {
-      body {
-        padding: 10px;
-        /* 移动端减小内边距 */
-      }
-
       .app-title {
         font-size: 1.5rem;
-        /* 移动端标题进一步调小 */
         margin-bottom: 10px;
-        /* 移动端调整间距 */
-      }
-
-      .app-icon img {
-        width: 70px;
-        /* 移动端图标进一步调小 */
-        height: 70px;
-      }
-
-      .buttons {
-        margin-top: 15px;
-        /* 移动端调整间距 */
       }
 
       .btn {
         min-width: 150px;
-        /* 移动端按钮小一点 */
         font-size: 1rem;
         margin-right: 0;
-        /* 垂直排列时不需要右边距 */
       }
     }
   </style>
+
+  <!-- 预加载图片尺寸的脚本 -->
+  <script>
+    // 从模板获取图片URL
+    const imageUrl = "<%= imageUrl %>";
+
+    // 预加载图片获取尺寸信息
+    function preloadImageDimensions() {
+      return new Promise((resolve, reject) => {
+        const tempImg = new Image();
+
+        // 仅加载图片元数据(尺寸)
+        tempImg.src = imageUrl;
+
+        tempImg.onload = () => {
+          resolve({
+            width: tempImg.naturalWidth,
+            height: tempImg.naturalHeight
+          });
+        };
+
+        tempImg.onerror = () => {
+          reject(new Error('Failed to load image dimensions'));
+        };
+      });
+    }
+
+    // 设置容器尺寸
+    function setContainerDimensions(width, height) {
+      const container = document.querySelector('.image-canvas-container');
+      if (!container) return;
+
+      const aspectRatio = width / height;
+      // 使用padding-bottom设置宽高比,确保容器尺寸正确
+      container.style.paddingBottom = (100 / aspectRatio) + '%';
+      container.style.backgroundColor = 'transparent';
+    }
+
+    // 执行预加载
+    preloadImageDimensions()
+      .then(dimensions => {
+        setContainerDimensions(dimensions.width, dimensions.height);
+      })
+      .catch(error => {
+        console.log('Using default dimensions due to error:', error);
+        // 失败时使用默认比例
+        const container = document.querySelector('.image-canvas-container');
+        if (container) {
+          container.style.paddingBottom = '75%'; // 默认4:3
+        }
+      });
+  </script>
 </head>
-<!-- Google tag (gtag.js) -->
-<script async src="https://www.googletagmanager.com/gtag/js?id=G-JBGGVGLHTP"></script>
-<script>
-  window.dataLayer = window.dataLayer || [];
-  function gtag() { dataLayer.push(arguments); }
-  gtag('js', new Date());
-  gtag('config', 'G-JBGGVGLHTP');
-</script>
 
 <body>
+  <!-- Google tag (gtag.js) -->
+  <script async src="https://www.googletagmanager.com/gtag/js?id=G-JBGGVGLHTP"></script>
+  <script>
+    window.dataLayer = window.dataLayer || [];
+    function gtag() { dataLayer.push(arguments); }
+    gtag('js', new Date());
+    gtag('config', 'G-JBGGVGLHTP');
+  </script>
+
   <div class="header-container">
     <div class="app-icon">
       <img src="/assets/icon/logo_640x640.webp" alt="Art Color App Logo">
     </div>
-    <h1 class="app-title">🎨 Art Color - Color by Number 🎨</h1>
+    <div class="app-title">🎨 ArtColor 🎨</div>
   </div>
 
   <div class="image-canvas-container">
-    <img id="poster-img" src="http://color.jccytech.cn/thumbs/coloring-page/done/480/67f33f5d8f7086254fee7dd2.webp"
-      alt="Art Color" />
+    <!-- 加载占位符 -->
+    <div class="image-placeholder" id="imagePlaceholder">
+      <div class="loading-spinner"></div>
+    </div>
+
+    <img id="poster-img" src="<%= imageUrl %>" alt="Art Color" />
     <canvas id="canvas"></canvas>
     <div id="play-button" class="play-button"></div>
   </div>
 
   <div class="buttons">
-    <a href="https://pcoloring.com/anc/" class="btn btn-secondary">
-      Download App
-    </a>
-    <a href="https://art.pcoloring.com/share/67f33f5d8f7086254fee7dd2?pullapp=1" class="btn btn-primary">
+    <a href="<%= applink %>" target="_blank" class="btn btn-primary">
       Claim Bonus
     </a>
+    <a href="<%= downlink %>" class="btn btn-secondary">
+      <%= translate.downloadApp[lang] %>
+    </a>
   </div>
 
-  <!-- MARK: 微信引导层 -->
+  <!-- 微信引导层 -->
   <div id="wechat-guide-overlay" class="wechat-guide-overlay">
     <div class="wechat-guide-arrow" onclick="closeOverlay()"></div>
     <p class="wechat-guide-text">
@@ -390,9 +409,29 @@
   </div>
 
   <script>
+    // 图片加载完成处理
+    const posterImg = document.getElementById('poster-img');
+    const imagePlaceholder = document.getElementById('imagePlaceholder');
+
+    posterImg.onload = function () {
+      // 图片加载完成后显示
+      posterImg.classList.add('loaded');
+      // 隐藏占位符
+      if (imagePlaceholder) {
+        imagePlaceholder.style.display = 'none';
+      }
+    };
+
+    // 图片加载失败处理
+    posterImg.onerror = function () {
+      if (imagePlaceholder) {
+        imagePlaceholder.innerHTML = '<p style="color: #666;">图片加载失败</p>';
+      }
+    };
+
+    // 微信环境检测
     const wechatGuideOverlay = document.getElementById('wechat-guide-overlay');
 
-    // MARK: 微信环境检测
     function isWeChatBrowser() {
       const ua = window.navigator.userAgent.toLowerCase();
       return ua.includes('micromessenger');
@@ -406,7 +445,7 @@
       wechatGuideOverlay.classList.add('active');
       console.log("检测到微信浏览器,显示引导层。");
     } else {
-      wechatGuideOverlay.classList.remove('active'); // 确保隐藏
+      wechatGuideOverlay.classList.remove('active');
     }
   </script>
 </body>

+ 133 - 88
views/v2/share.ejs

@@ -60,33 +60,37 @@
       font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
       display: flex;
       flex-direction: column;
-      /* 垂直方向排列子元素 */
-      height: 100vh;
-      /* 严格限制高度为视口高度,确保不超出 */
+      height: 92vh;
       margin: 0;
-      padding: 20px;
-      /* 页面内边距 */
       box-sizing: border-box;
-      /* 盒模型为边框盒 */
       background-color: var(--background-color);
       color: var(--text-color);
       line-height: 1.6;
       align-items: center;
-      /* 水平居中所有flex子项 */
     }
 
     /* 头部容器 */
     .header-container {
       width: 100%;
-      /* 占据全部宽度 */
+      margin-top: 10px;
       display: flex;
       flex-direction: column;
       align-items: center;
       justify-content: center;
-      padding-bottom: 15px;
-      /* 与下方内容留出间距,略微缩小 */
       flex-shrink: 0;
-      /* 不会收缩 */
+      z-index: 100;
+    }
+
+    /* 图片加载前隐藏,避免破碎的加载体验 */
+    #header {
+      opacity: 0;
+      transition: opacity 0.3s ease;
+      /* 加载完成后淡入 */
+    }
+
+    /* 图片加载完成后显示 */
+    #header.loaded {
+      opacity: 1;
     }
 
     .app-icon {
@@ -99,9 +103,7 @@
 
     .app-icon img {
       width: 90px;
-      /* 图标调小 */
       height: 90px;
-      /* 图标调小 */
       border: 3px solid #eeeeee;
       border-radius: 10px;
       box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
@@ -119,48 +121,73 @@
       /* 确保标题在移动端也居中 */
     }
 
-    /* 图片和 Canvas 容器,占据剩余所有空间 */
+    /* 父容器,用于包裹图片和 Canvas,并使其相对定位 */
     .image-canvas-container {
       position: relative;
-      width: 100%;
-      /* 占据所有可用宽度 */
-      max-width: 600px;
-      /* 限制最大宽度,保持美观 */
-      flex-grow: 1;
-      /* 占据所有剩余垂直空间 */
-      min-height: 0;
-      /* 允许flex-grow在必要时收缩 */
-      display: flex;
-      /* 内部使用flex布局来居中图片和canvas */
-      justify-content: center;
-      align-items: center;
+      max-width: 90%;
+      height: auto;
+      display: inline-block;
       box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
-      /* 添加阴影效果 */
       border-radius: 12px;
-      /* 圆角 */
       overflow: hidden;
-      /* 隐藏超出容器的内容 */
-      margin-bottom: 15px;
-      /* 与下方按钮留出间距,略微缩小 */
-      /* aspect-ratio: 1 / 1; 移除1:1比例,让高度自适应剩余空间 */
+    }
+
+    /* 占位容器:全屏覆盖 */
+    .image-placeholder {
+      position: absolute;
+      top: 0;
+      left: 0;
+      height: 100%;
+      width: 100%;
+      background-color: var(--background-color);
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      z-index: 20;
+      /* 位于 canvas 之上,图片之下 */
+    }
+
+    /* 简单的加载动画(旋转圆圈) */
+    .loading-spinner {
+      width: 40px;
+      height: 40px;
+      border: 4px solid #ddd;
+      border-top: 4px solid var(--primary-color);
+      border-radius: 50%;
+      animation: spin 1s linear infinite;
+    }
+
+    @keyframes spin {
+      0% {
+        transform: rotate(0deg);
+      }
+
+      100% {
+        transform: rotate(360deg);
+      }
     }
 
     /* 图片样式:使其响应式并填充容器 */
     .image-canvas-container img {
-      position: absolute;
-      /* 绝对定位,与canvas重叠 */
+      position: relative;
       display: block;
-      /* 移除图片底部空白 */
-      width: 100%;
-      /* 宽度填充父容器 */
+      max-width: 100%;
       height: 100%;
-      /* 高度填充父容器 */
       object-fit: contain;
-      /* 保持图片比例,适应容器 */
       border-radius: 12px;
-      /* 与容器相同的圆角 */
       z-index: 100;
-      /* 确保图片在canvas之上 */
+    }
+
+    /* 图片加载前隐藏,避免破碎的加载体验 */
+    #poster-img {
+      opacity: 0;
+      transition: opacity 0.3s ease;
+      /* 加载完成后淡入 */
+    }
+
+    /* 图片加载完成后显示 */
+    #poster-img.loaded {
+      opacity: 1;
     }
 
     /* Canvas 样式:绝对定位,与图片完全重叠 */
@@ -171,11 +198,36 @@
       width: 100%;
       height: 100%;
       border-radius: 12px;
-      /* 与容器相同的圆角 */
       z-index: 50;
-      /* 在图片之下 */
     }
 
+    /* 按钮容器在底部 */
+    .buttons {
+      width: 100%;
+      max-width: 550px;
+      display: flex;
+      flex-wrap: wrap;
+      flex-direction: column;
+      justify-content: center;
+      align-items: center;
+      margin-top: 30px;
+      flex-shrink: 0;
+      z-index: 100;
+    }
+
+    /* buttons 淡入 */
+    #buttons {
+      opacity: 0;
+      transition: opacity 0.3s ease;
+      /* 加载完成后淡入 */
+    }
+
+    /* 图片加载完成后显示 */
+    #buttons.loaded {
+      opacity: 1;
+    }
+
+
     .btn {
       display: inline-block;
       min-width: 180px;
@@ -239,24 +291,6 @@
       margin-left: 5px;
     }
 
-    /* 按钮容器在底部 */
-    .buttons {
-      width: 100%;
-      /* 占据全部宽度 */
-      max-width: 550px;
-      /* 限制最大宽度 */
-      display: flex;
-      flex-wrap: wrap;
-      flex-direction: column;
-      /* 按钮垂直排列 */
-      justify-content: center;
-      align-items: center;
-      margin-top: 15px;
-      /* 与上方内容留出间距,略微缩小 */
-      flex-shrink: 0;
-      /* 不会收缩 */
-    }
-
     /* MARK: 微信引导层样式 */
     .wechat-guide-overlay {
       position: fixed;
@@ -310,35 +344,15 @@
     }
 
     @media (max-width: 768px) {
-      body {
-        padding: 10px;
-        /* 移动端减小内边距 */
-      }
-
       .app-title {
         font-size: 1.5rem;
-        /* 移动端标题进一步调小 */
         margin-bottom: 10px;
-        /* 移动端调整间距 */
-      }
-
-      .app-icon img {
-        width: 70px;
-        /* 移动端图标进一步调小 */
-        height: 70px;
-      }
-
-      .buttons {
-        margin-top: 15px;
-        /* 移动端调整间距 */
       }
 
       .btn {
         min-width: 150px;
-        /* 移动端按钮小一点 */
         font-size: 1rem;
         margin-right: 0;
-        /* 垂直排列时不需要右边距 */
       }
     }
   </style>
@@ -354,24 +368,30 @@
 </script>
 
 <body>
-  <div class="header-container">
+  <div class="image-placeholder" id="imagePlaceholder">
+    <div class="loading-spinner"></div>
+  </div>
+  <div id="header" class="header-container">
     <div class="app-icon">
       <img src="/assets/icon/logo_640x640.webp" alt="Art Color App Logo">
     </div>
-    <h1 class="app-title">🎨 ArtColor 🎨</h1>
+    <div class="app-title">🎨 ArtColor 🎨</div>
   </div>
+
   <div class="image-canvas-container">
     <img id="poster-img" src="<%= imageUrl %>" alt="Art Color" />
     <canvas id="canvas"></canvas>
     <div id="play-button" class="play-button"></div>
   </div>
-  <div class="buttons">
+
+
+  <div id="buttons" class="buttons">
+    <a href="<%= openapplink %>" target="_blank" class="btn btn-primary">
+      <%= translate.claimBonus[lang] %>
+    </a>
     <a href="<%= downlink %>" class="btn btn-secondary">
       <%= translate.downloadApp[lang] %>
     </a>
-    <a href="<%= applink %>" target="_blank" class="btn btn-primary">
-      Claim Bonus
-    </a>
   </div>
 
   <!-- MARK: 微信引导层 -->
@@ -385,6 +405,32 @@
   </div>
 
   <script>
+
+    // 图片加载逻辑
+    const header = document.getElementById('header');
+    const posterImg = document.getElementById('poster-img');
+    const imagePlaceholder = document.getElementById('imagePlaceholder');
+    const buttons = document.getElementById('buttons');
+
+    // 图片加载完成后
+    posterImg.onload = function () {
+      // header淡入
+      header.classList.add('loaded');
+      // 标记图片已加载,触发 CSS 淡入效果
+      posterImg.classList.add('loaded');
+      // buttons淡入
+      buttons.classList.add('loaded');
+      // 隐藏占位符
+      if (imagePlaceholder) {
+        imagePlaceholder.style.display = 'none';
+      }
+    };
+
+    // 图片加载失败时(备选方案)
+    posterImg.onerror = function () {
+      imagePlaceholder.innerHTML = '<p>图片加载失败</p>'; // 显示错误提示
+    };
+
     const wechatGuideOverlay = document.getElementById('wechat-guide-overlay');
 
     // MARK: 微信环境检测
@@ -403,7 +449,6 @@
     } else {
       wechatGuideOverlay.classList.remove('active'); // 确保隐藏
     }
-
   </script>
 </body>