소스 검색

完善填色游戏体验

guoziyun 1 년 전
부모
커밋
46df58b968

+ 19 - 0
config/meta.js

@@ -225,6 +225,22 @@ let videosDescription = {
   ja: '塗り絵ページの動画物語を通じて、これまでにない物語体験をしてみましょう',
 }
 
+let myworksTitle = {
+  zh: '我的填色页作品',
+  en: 'My Coloring Page Works',
+  es: 'Mis trabajos de páginas para colorear',
+  pt: 'Meus trabalhos de páginas para colorir',
+  ja: '私の着色ページの作品',
+}
+
+let myworksDescription = {
+  zh: '记录我的填色足迹,包括进行中的,已完成的,以及我收藏的作品',
+  en: 'Record my coloring footprints, including the ones in progress, the completed ones, and the works I have collected.',
+  es: 'Registra mis huellas de coloreado, incluyendo las en curso, las completadas y las obras que he coleccionado.',
+  pt: 'Registre minhas pegadas de coloração, incluindo as em andamento, as concluídas e as obras que eu coletei.',
+  ja: '私の着色の足跡を記録します。進行中のもの、完了したもの、そして私がコレクションした作品を含めて。',
+}
+
 
 
 
@@ -258,6 +274,9 @@ let meta = {
   playDescription,
   videosTitle,
   videosDescription,
+  myworksTitle,
+  myworksDescription,
+
 }
 
 

+ 119 - 0
config/translate.js

@@ -184,6 +184,30 @@ let myWorks = {
   ja: '私の作品',
 }
 
+let inProgress = {
+  zh: '进行中',
+  en: 'In Progress',
+  es: 'En Progreso',
+  pt: 'En Progreso',
+  ja: '進行中',
+}
+
+let completed = {
+  zh: '已完成',
+  en: 'Completed',
+  es: 'Completado',
+  pt: 'Completado',
+  ja: '完了した',
+}
+
+let favorite = {
+  zh: '收藏',
+  en: 'Favorite',
+  es: 'Favorito',
+  pt: 'Favorito',
+  ja: '好きな',
+}
+
 
 let play = {
   zh: '在线填色',
@@ -217,6 +241,88 @@ let print = {
   ja: '印刷',
 }
 
+let replay = {
+  zh: '播放',
+  en: 'Play',
+  es: 'Reproducir',
+  pt: 'Reproduzir',
+  ja: 'Play',
+}
+
+let continuex = {
+  zh: '继续填色',
+  en: 'Continue',
+  es: 'Continuar',
+  pt: 'Continuar',
+  ja: '続ける',
+}
+
+let share = {
+  zh: '分享',
+  en: 'Share',
+  es: 'Compartir',
+  pt: 'Compartilhar',
+  ja: '共有する',
+}
+
+let view = {
+  zh: '查看',
+  en: 'Review',
+  es: 'Revisar',
+  pt: 'Revisar',
+  ja: '見る',
+}
+
+
+let deletex = {
+  zh: '删除',
+  en: 'Delete',
+  es: 'Borrar',
+  pt: 'Apagar',
+  ja: '削除する',
+}
+
+let repaint = {
+  zh: '重新着色',
+  en: 'Repaint',
+  es: 'Repintar',
+  pt: 'Repintar',
+  ja: '再塗る',
+}
+
+let hintStyle = {
+  zh: '提示层样式',
+  en: 'Hint Style',
+  es: 'Estilo de la capa de sugerencia',
+  pt: 'Estilo da camada de dica',
+  ja: 'ヒント レイヤー スタイル',
+}
+
+let sound = {
+  zh: '声音',
+  en: 'Sound',
+  es: 'Sonido',
+  pt: 'Som',
+  ja: '声音',
+}
+
+let vibrate = {
+  zh: '震动',
+  en: 'Vibrate',
+  es: 'Vibrar',
+  pt: 'Vibrar',
+  ja: '振動する',
+}
+
+let autoNext = {
+  zh: '自动切换到下一个颜色',
+  en: 'Auto switch to next color',
+  es: 'Cambiar automáticamente al siguiente color',
+  pt: 'Mudar automaticamente para a próxima cor',
+  ja: '自動的に次の色に切り替えます',
+}
+
+
 let tag = {
   zh: '标签',
   en: 'Tag',
@@ -613,6 +719,9 @@ let translate = {
   appDownload,
   my,
   myWorks,
+  inProgress,
+  completed,
+  favorite,
   play,
   playOnApp,
   download,
@@ -663,6 +772,16 @@ let translate = {
   gallery,
   galleryHeader,
   coloringPageCategories,
+  replay,
+  share,
+  continuex,
+  view,
+  deletex,
+  repaint,
+  hintStyle,
+  sound,
+  vibrate,
+  autoNext,
 }
 
 

BIN
dist/assets/coloring_ic_save@3x-B4R4i8qI.png


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/assets/main-Bk9rJI5U.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/assets/main-DGuEntp1.css


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/assets/main-DsmAs4tp.css


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/assets/main-Ia4jp5dB.js


BIN
dist/assets/sound/color_done_02.mp3


BIN
dist/assets/sound/section_done.mp3


BIN
dist/assets/sound/sound_hint.mp3


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 44 - 0
dist/play.html


+ 33 - 0
dist/scripts/progress.js

@@ -0,0 +1,33 @@
+document.addEventListener('DOMContentLoaded', () => {
+  const METADATA_KEY = '__storage_metadata__';
+
+  const containers = document.querySelectorAll('.image-card');
+
+  // 获取本地存储数据
+  const metaData = JSON.parse(localStorage.getItem(METADATA_KEY)) || {};
+
+  containers.forEach(container => {
+    const contentId = container.dataset.contentId;
+    if (metaData[contentId]) {
+      const progress = Math.round(metaData[contentId].progress);
+
+      // 如何已完成,展示work图
+      if (progress >= 100) {
+        const img = container.querySelector('img');  // 获取当前div内的img元素
+        img.src = img.src.replace('/page/', '/work/');
+      }
+
+      // 添加角标
+      const badge = document.createElement('div');
+      badge.className = 'progress-badge';
+      badge.innerHTML = `<span>${progress >= 100 ? '✓' : progress + '%'}</span>`;
+      badge.style.backgroundColor = progress >= 100 ? '#4CAF50' : '#FF5252';
+      // 添加渐变动画
+      badge.style.transition = 'background-color 0.3s ease';
+
+      container.appendChild(badge);
+
+
+    }
+  });
+});

+ 14 - 1
dist/stylesheets/detail.css

@@ -2,7 +2,7 @@
   display: flex;
   flex-wrap: wrap;
   justify-content: space-between;
-  align-items: flex-start;
+  align-items: center;
   margin: 20px auto;
   padding: 20px;
   max-width: 1200px;
@@ -14,6 +14,8 @@
   flex: 1 1 30%;
   max-width: 30%;
   margin-bottom: 20px;
+  position: relative;
+  display: inline-block;
 }
 .poster img {
   width: 100%;
@@ -22,6 +24,7 @@
   aspect-ratio: 1;
   border-radius: 4px;
 }
+
 .tag-button {
   display: inline-block;
   text-align: center;
@@ -44,12 +47,16 @@
 
 .button-wrapper {
   display: flex;
+  flex-wrap: wrap;
   justify-content: start;
   align-items: center;
 }
 
 .play-button {
   display: inline-block;
+  flex: 1 0 auto;   /* 允许伸缩,不收缩,基础尺寸自适应 */
+  min-width: max-content; /* 最小宽度由内容决定 */
+  white-space: nowrap;    /* 禁止按钮文字换行 */
   margin-top: 20px;
   margin-right: 20px;
   padding: 10px 20px;
@@ -61,6 +68,12 @@
   font-weight: bold;
   border: none;
   cursor: pointer;
+  transition: transform 0.2s;
+}
+
+.play-button:hover {
+  transform: translateY(-5px);
+  opacity: 0.75;
 }
 
 /* 媒体查询:当屏幕宽度小于768px时(移动端) */

+ 65 - 0
dist/stylesheets/myworks.css

@@ -0,0 +1,65 @@
+/* 标签容器样式 */
+.tab-container {
+  margin: 2px auto;
+  background: white;
+  border-radius: 0px 0px 12px 12px;
+}
+
+/* 标签导航样式 */
+.tab-nav {
+  display: flex;
+  border-bottom: 2px solid #eee;
+}
+
+.tab-button {
+  padding: 1rem 2rem;
+  border: none;
+  background: none;
+  cursor: pointer;
+  font-size: 1.0rem;
+  color: #666;
+  transition: all 0.3s ease;
+  position: relative;
+}
+
+.tab-button.active {
+  color: #2196F3;
+  font-weight: 600;
+}
+
+.tab-button.active::after {
+  content: '';
+  position: absolute;
+  bottom: -2px;
+  left: 0;
+  width: 100%;
+  height: 3px;
+  background: #2196F3;
+}
+
+/* 内容区域样式 */
+.tab-content {
+  display: none;
+}
+
+.tab-content.active {
+  margin-top: 20px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  animation: fadeIn 0.3s ease;
+}
+
+@keyframes fadeIn {
+  from { opacity: 0; transform: translateY(10px); }
+  to { opacity: 1; transform: translateY(0); }
+}
+
+/* 响应式设计, 如果是手机屏幕 */
+@media (max-width: 768px) {
+  .tab-button  {
+    padding: 1rem 1rem;
+  }
+
+}

+ 21 - 1
dist/stylesheets/styles.css

@@ -38,14 +38,16 @@ body {
   flex-direction: column;
   justify-content: center;
   align-items: center;
-
 }
 
 .image-card {
+  position: relative;
+  display: inline-block;
   padding: 5px;
   border: 1px solid #ccc; /* 卡片边框 */
   border-radius: 8px;     /* 卡片圆角 */
   box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 卡片阴影 */
+  transition: transform 0.2s;
 }
 
 .image-card:hover {
@@ -315,3 +317,21 @@ body {
 }
 
 
+/* 进度角标样式 */
+.progress-badge {
+  position: absolute;
+  top: 0px;
+  right: 0px;
+  background: #FF5252;
+  color: white;
+  padding: 4px 8px;
+  border-radius: 0px 8px 0px 8px;
+  font-size: 12px;
+  font-family: Arial, sans-serif;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
+  z-index: 10;
+}
+

+ 48 - 2
routes/index.js

@@ -1211,6 +1211,38 @@ router.get('/:lang/artist/:id', function (req, res, next) {
 });
 
 
+// myworks
+router.get('/:lang/myworks', function (req, res, next) {
+  (async function () {
+    let lang = utils.lang.ensureLanguage(req.params.lang);
+    if (!req.cookies.lang || req.cookies.lang != lang) {
+      res.cookie('lang', lang, config.cookie);
+    }
+
+    let data = {
+      title: `${meta.myworksTitle[lang]}`,
+      description: meta.myworksDescription[lang],
+      host: config.cdnHost ?? config.resHost,
+      translate,
+      meta,
+      lang,
+      languages,
+      uri: `/${lang}/myworks`,
+    };
+
+    // 渲染EJS模板到内存中
+    res.render('myworks', data, async (err, html) => {
+      if (err) {
+        // 如果渲染出错,调用next()传递错误
+        return next(err);
+      }
+
+      res.send(html);
+    });
+
+  })().catch(next);
+
+});
 
 
 
@@ -1284,7 +1316,8 @@ router.get('/:lang/coloring-page/:str', function (req, res, next) {
         lang,
         languages,
         relates: result.data,
-        uri: req.originalUrl,
+        uri: `/${lang}/coloring-page/${doc._id}`,
+        imageUrl: doc.thumb,
         pageUri: replaceUriParams,
       };
 
@@ -1408,6 +1441,12 @@ router.get('/play/:id', function (req, res, next) {
     let id = req.params.id;
     utils.validators.validateId(id);
 
+    let lang = req.cookies?.lang || 'en';
+
+    let host = config.cdnHost ?? config.resHost;
+    let imageType = req.headers.accept?.includes('image/webp') ? 'webp' : 'jpeg';  // 浏览器支持webp就用webp
+    let workUrl = `${host}/thumbs/coloring-page/work/480/${id}.${imageType}`;
+
     let cacheKey = `${CACHE_PREFIX}_play_${id}`;
     let htmlData = await redis.getAsync(cacheKey);
     if (!htmlData) {
@@ -1417,8 +1456,12 @@ router.get('/play/:id', function (req, res, next) {
 
       let data = {
         id,
+        lang,
+        translate,
         title: meta.playTitle.en,
         description: meta.playDescription.en,
+        uri: req.originalUrl,
+        imageUrl: workUrl,
       };
 
       // 渲染EJS模板到内存中
@@ -1501,6 +1544,7 @@ const organizeData = (data, lang, imageType) => {
     let version = publishVersion + 1500;
 
     doc.thumb = `${host}/thumbs/coloring-page/page/480/${doc._id}.${imageType}`;
+    doc.work = `${host}/thumbs/coloring-page/work/480/${doc._id}.${imageType}`;
     doc.zip = `${host}/zips/v2/number_mini/${version}/${doc._id}.zip`;
 
     let uriTitle = doc.name;
@@ -1519,7 +1563,8 @@ const organizeData = (data, lang, imageType) => {
     doc.tags = doc.tags.filter(str => !/[\u4e00-\u9fa5]/.test(str)); // 过滤掉tags中的中文
 
     let utf8name = encodeURIComponent(uriTitle.replace(/[\s_]+/g, '-')).toLowerCase();
-    doc.uri = `/${lang}/coloring-page/${utf8name}-${doc._id}`;
+    // doc.uri = `/${lang}/coloring-page/${utf8name}-${doc._id}`;  // 不想搞那么复杂了, 对seo帮助意思不大
+    doc.uri = `/${lang}/coloring-page/${doc._id}`;
 
     delete doc.hasSpecial;
     delete doc.useSpecialThumb;
@@ -1535,6 +1580,7 @@ const organizeDetail = (doc, lang, imageType) => {
   let version = publishVersion + 1500;
 
   doc.thumb = `${host}/thumbs/coloring-page/page/480/${doc._id}.${imageType}`;
+  doc.work = `${host}/thumbs/coloring-page/work/480/${doc._id}.${imageType}`;
   doc.zip = `${host}/zips/v2/number_mini/${version}/${doc._id}.zip`
 
   // doc.title = translate.titleTest[lang];

+ 445 - 36
service/cron-jobs/sitemap.js

@@ -25,7 +25,6 @@ async function generateSitemap() {
     '>',
     '  <url>',
     '    <loc>https://art.pcoloring.com/en</loc>',
-    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en" />',
     '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh" />',
     '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es" />',
     '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt" />',
@@ -35,8 +34,47 @@ async function generateSitemap() {
     '    <priority>1.0</priority>',
     '  </url>',
     '  <url>',
+    '    <loc>https://art.pcoloring.com/zh</loc>',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>daily</changefreq>',
+    '    <priority>1.0</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/es</loc>',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en" />',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>daily</changefreq>',
+    '    <priority>1.0</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/pt</loc>',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es" />',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>daily</changefreq>',
+    '    <priority>1.0</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/ja</loc>',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt" />',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>daily</changefreq>',
+    '    <priority>1.0</priority>',
+    '  </url>',
+    '  <url>',
     '    <loc>https://art.pcoloring.com/en/gallery</loc>',
-    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/gallery" />',
     '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/gallery" />',
     '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/gallery" />',
     '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/gallery" />',
@@ -46,8 +84,47 @@ async function generateSitemap() {
     '    <priority>0.8</priority>',
     '  </url>',
     '  <url>',
+    '    <loc>https://art.pcoloring.com/zh/gallery</loc>',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/gallery" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/gallery" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/gallery" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/gallery" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>weekly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/es/gallery</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/gallery" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/gallery" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/gallery" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/gallery" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>weekly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/pt/gallery</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/gallery" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/gallery" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/gallery" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/gallery" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>weekly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/ja/gallery</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/gallery" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/gallery" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/gallery" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/gallery" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>weekly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
     '    <loc>https://art.pcoloring.com/en/videos</loc>',
-    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/videos" />',
     '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/videos" />',
     '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/videos" />',
     '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/videos" />',
@@ -56,15 +133,48 @@ async function generateSitemap() {
     '    <changefreq>weekly</changefreq>',
     '    <priority>0.8</priority>',
     '  </url>',
-    // '  <url>',
-    // '    <loc>https://art.pcoloring.com/en/category</loc>',
-    // `    <lastmod>${date}</lastmod>`,
-    // '    <changefreq>daily</changefreq>',
-    // '    <priority>0.8</priority>',
-    // '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/zh/videos</loc>',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/videos" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/videos" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/videos" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/videos" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>weekly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/es/videos</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/videos" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/videos" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/videos" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/videos" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>weekly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/pt/videos</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/videos" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/videos" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/videos" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/videos" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>weekly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/ja/videos</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/videos" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/videos" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/videos" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/videos" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>weekly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
     '  <url>',
     '    <loc>https://art.pcoloring.com/en/tag</loc>',
-    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/tag" />',
     '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/tag" />',
     '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/tag" />',
     '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/tag" />',
@@ -74,8 +184,47 @@ async function generateSitemap() {
     '    <priority>0.8</priority>',
     '  </url>',
     '  <url>',
+    '    <loc>https://art.pcoloring.com/zh/tag</loc>',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/tag" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/tag" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/tag" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/tag" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>daily</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/es/tag</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/tag" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/tag" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/tag" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/tag" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>daily</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/pt/tag</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/tag" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/tag" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/tag" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/tag" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>daily</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/ja/tag</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/tag" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/tag" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/tag" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/tag" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>daily</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
     '    <loc>https://art.pcoloring.com/en/albums</loc>',
-    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/albums" />',
     '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/albums" />',
     '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/albums" />',
     '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/albums" />',
@@ -85,8 +234,47 @@ async function generateSitemap() {
     '    <priority>0.8</priority>',
     '  </url>',
     '  <url>',
+    '    <loc>https://art.pcoloring.com/zh/albums</loc>',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/albums" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/albums" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/albums" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/albums" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>weekly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/es/albums</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/albums" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/albums" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/albums" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/albums" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>weekly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/pt/albums</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/albums" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/albums" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/albums" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/albums" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>weekly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/ja/albums</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/albums" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/albums" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/albums" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/albums" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>weekly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
     '    <loc>https://art.pcoloring.com/en/special</loc>',
-    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/special" />',
     '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/special" />',
     '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/special" />',
     '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/special" />',
@@ -96,8 +284,47 @@ async function generateSitemap() {
     '    <priority>0.8</priority>',
     '  </url>',
     '  <url>',
+    '    <loc>https://art.pcoloring.com/zh/special</loc>',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/special" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/special" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/special" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/special" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>daily</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/es/special</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/special" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/special" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/special" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/special" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>daily</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/pt/special</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/special" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/special" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/special" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/special" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>daily</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/ja/special</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/special" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/special" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/special" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/special" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>daily</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
     '    <loc>https://art.pcoloring.com/en/artists</loc>',
-    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/artists" />',
     '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/artists" />',
     '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/artists" />',
     '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/artists" />',
@@ -107,29 +334,83 @@ async function generateSitemap() {
     '    <priority>0.8</priority>',
     '  </url>',
     '  <url>',
+    '    <loc>https://art.pcoloring.com/zh/artists</loc>',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/artists" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/artists" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/artists" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/artists" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>monthly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/es/artists</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/artists" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/artists" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/artists" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/artists" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>monthly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/pt/artists</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/artists" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/artists" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/artists" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/artists" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>monthly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
+    '    <loc>https://art.pcoloring.com/ja/artists</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/artists" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/artists" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/artists" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/artists" />',
+    `    <lastmod>${date}</lastmod>`,
+    '    <changefreq>monthly</changefreq>',
+    '    <priority>0.8</priority>',
+    '  </url>',
+    '  <url>',
     '    <loc>https://art.pcoloring.com/en/info</loc>',
-    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/info" />',
     '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/info" />',
     '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/info" />',
     '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/info" />',
     '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/info" />',
     `    <lastmod>${date}</lastmod>`,
     '  </url>',
+    '    <loc>https://art.pcoloring.com/zh/info</loc>',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/info" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/info" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/info" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/info" />',
+    `    <lastmod>${date}</lastmod>`,
+    '  </url>',
+    '    <loc>https://art.pcoloring.com/es/info</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/info" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/info" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/info" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/info" />',
+    `    <lastmod>${date}</lastmod>`,
+    '  </url>',
+    '    <loc>https://art.pcoloring.com/pt/info</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/info" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/info" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/info" />',
+    '    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/info" />',
+    `    <lastmod>${date}</lastmod>`,
+    '  </url>',
+    '    <loc>https://art.pcoloring.com/ja/info</loc>',
+    '    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/info" />',
+    '    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/info" />',
+    '    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/info" />',
+    '    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/info" />',
+    `    <lastmod>${date}</lastmod>`,
+    '  </url>',
   ];
 
-  // categories
-  // let categoriesXml = [];
-  // categories.forEach(e => {
-  //   categoriesXml = categoriesXml.concat([
-  //     '  <url>',
-  //     `    <loc>https://art.pcoloring.com/en/category/${e.id}</loc>`,
-  //     `    <lastmod>${date}</lastmod>`,
-  //     '  </url>',
-  //   ]
-  //   );
-  // });
-
-  // console.log(categoriesXml);
 
   // tags
   let tagsXml = [];
@@ -138,13 +419,40 @@ async function generateSitemap() {
     tagsXml = tagsXml.concat([
       '  <url>',
       `    <loc>https://art.pcoloring.com/en/tag/${e.tag}</loc>`,
-      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/tag/${e.tag}" />`,
       `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/tag/${e.tag}" />`,
       `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/tag/${e.tag}" />`,
       `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/tag/${e.tag}" />`,
       `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/tag/${e.tag}" />`,
       `    <lastmod>${date}</lastmod>`,
       '  </url>',
+      `    <loc>https://art.pcoloring.com/zh/tag/${e.tag}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/tag/${e.tag}" />`,
+      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/tag/${e.tag}" />`,
+      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/tag/${e.tag}" />`,
+      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/tag/${e.tag}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
+      `    <loc>https://art.pcoloring.com/es/tag/${e.tag}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/tag/${e.tag}" />`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/tag/${e.tag}" />`,
+      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/tag/${e.tag}" />`,
+      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/tag/${e.tag}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
+      `    <loc>https://art.pcoloring.com/pt/tag/${e.tag}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/tag/${e.tag}" />`,
+      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/tag/${e.tag}" />`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/tag/${e.tag}" />`,
+      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/tag/${e.tag}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
+      `    <loc>https://art.pcoloring.com/ja/tag/${e.tag}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/tag/${e.tag}" />`,
+      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/tag/${e.tag}" />`,
+      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/tag/${e.tag}" />`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/tag/${e.tag}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
     ]);
   });
   console.log(tagsXml);
@@ -161,13 +469,44 @@ async function generateSitemap() {
     albumsXml = albumsXml.concat([
       '  <url>',
       `    <loc>https://art.pcoloring.com/en/coloring-page-album/${e._id}</loc>`,
-      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/coloring-page-album/${e._id}" />`,
       `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/coloring-page-album/${e._id}" />`,
       `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/coloring-page-album/${e._id}" />`,
       `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/coloring-page-album/${e._id}" />`,
       `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/coloring-page-album/${e._id}" />`,
       `    <lastmod>${date}</lastmod>`,
       '  </url>',
+      '  <url>',
+      `    <loc>https://art.pcoloring.com/zh/coloring-page-album/${e._id}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/coloring-page-album/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/coloring-page-album/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/coloring-page-album/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/coloring-page-album/${e._id}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
+      '  <url>',
+      `    <loc>https://art.pcoloring.com/es/coloring-page-album/${e._id}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/coloring-page-album/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/coloring-page-album/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/coloring-page-album/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/coloring-page-album/${e._id}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
+      '  <url>',
+      `    <loc>https://art.pcoloring.com/pt/coloring-page-album/${e._id}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/coloring-page-album/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/coloring-page-album/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/coloring-page-album/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/coloring-page-album/${e._id}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
+      '  <url>',
+      `    <loc>https://art.pcoloring.com/ja/coloring-page-album/${e._id}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/coloring-page-album/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/coloring-page-album/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/coloring-page-album/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/coloring-page-album/${e._id}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
     ])
   });
   console.log(albumsXml);
@@ -207,13 +546,44 @@ async function generateSitemap() {
     designersXml = designersXml.concat([
       '  <url>',
       `    <loc>https://art.pcoloring.com/en/artist/${e._id}</loc>`,
-      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/artist/${e._id}" />`,
       `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/artist/${e._id}" />`,
       `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/artist/${e._id}" />`,
       `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/artist/${e._id}" />`,
       `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/artist/${e._id}" />`,
       `    <lastmod>${date}</lastmod>`,
       '  </url>',
+      '  <url>',
+      `    <loc>https://art.pcoloring.com/zh/artist/${e._id}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/artist/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/artist/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/artist/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/artist/${e._id}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
+      '  <url>',
+      `    <loc>https://art.pcoloring.com/es/artist/${e._id}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/artist/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/artist/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/artist/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/artist/${e._id}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
+      '  <url>',
+      `    <loc>https://art.pcoloring.com/pt/artist/${e._id}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/artist/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/artist/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/artist/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/artist/${e._id}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
+      '  <url>',
+      `    <loc>https://art.pcoloring.com/ja/artist/${e._id}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/artist/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/artist/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/artist/${e._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/artist/${e._id}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
     ])
   });
   console.log(designersXml);
@@ -237,13 +607,52 @@ async function generateSitemap() {
     }
     let utf8name = encodeURIComponent(uriTitle.replace(/[\s_]+/g, '-')).toLowerCase();
     detailsXml = detailsXml.concat([
+      // '  <url>',
+      // `    <loc>https://art.pcoloring.com/en/coloring-page/${utf8name}-${doc._id}</loc>`,
+      // `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/coloring-page/${utf8name}-${doc._id}" />`,
+      // `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/coloring-page/${utf8name}-${doc._id}" />`,
+      // `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/coloring-page/${utf8name}-${doc._id}" />`,
+      // `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/coloring-page/${utf8name}-${doc._id}" />`,
+      // `    <lastmod>${date}</lastmod>`,
+      // '  </url>',
+      '  <url>',
+      `    <loc>https://art.pcoloring.com/en/coloring-page/${doc._id}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/coloring-page/${doc._id}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
+      '  <url>',
+      `    <loc>https://art.pcoloring.com/zh/coloring-page/${doc._id}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/coloring-page/${doc._id}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
+      '  <url>',
+      `    <loc>https://art.pcoloring.com/es/coloring-page/${doc._id}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/coloring-page/${doc._id}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
+      '  <url>',
+      `    <loc>https://art.pcoloring.com/pt/coloring-page/${doc._id}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/coloring-page/${doc._id}" />`,
+      `    <lastmod>${date}</lastmod>`,
+      '  </url>',
       '  <url>',
-      `    <loc>https://art.pcoloring.com/en/coloring-page/${utf8name}-${doc._id}</loc>`,
-      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/coloring-page/${utf8name}-${doc._id}" />`,
-      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/coloring-page/${utf8name}-${doc._id}" />`,
-      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/coloring-page/${utf8name}-${doc._id}" />`,
-      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/coloring-page/${utf8name}-${doc._id}" />`,
-      `    <xhtml:link rel="alternate" hreflang="ja" href="https://art.pcoloring.com/ja/coloring-page/${utf8name}-${doc._id}" />`,
+      `    <loc>https://art.pcoloring.com/ja/coloring-page/${doc._id}</loc>`,
+      `    <xhtml:link rel="alternate" hreflang="zh" href="https://art.pcoloring.com/zh/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="es" href="https://art.pcoloring.com/es/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="pt" href="https://art.pcoloring.com/pt/coloring-page/${doc._id}" />`,
+      `    <xhtml:link rel="alternate" hreflang="en" href="https://art.pcoloring.com/en/coloring-page/${doc._id}" />`,
       `    <lastmod>${date}</lastmod>`,
       '  </url>',
     ]);

+ 3 - 1
views/album.ejs

@@ -69,7 +69,7 @@
     <div class="content">
       <div class="image-grid">
         <% data.contents.forEach(item=> { %>
-          <div class="image-card">
+          <div data-content-id="<%= item._id %>" class="image-card">
             <a href="<%= item.uri %>"><img src="<%= item.thumb %>" alt="<%= item.title %>"></a>
             <div class="card-title">
               <%= item.title %>
@@ -82,6 +82,8 @@
     <div style="padding: 40px"></div>
 
 
+    <script src="/scripts/progress.js"></script>
+    
 </body>
 
 </html>

+ 3 - 1
views/category.ejs

@@ -75,7 +75,7 @@
     <div class="content">
       <div class="image-grid">
         <% data.forEach(item=> { %>
-          <div class="image-card">
+          <div data-content-id="<%= item._id %>" class="image-card">
             <a href="<%= item.uri %>"><img src="<%= item.thumb %>" alt="<%= item.title %>"></a>
             <div class="card-title">
               <%= item.title %>
@@ -87,6 +87,8 @@
 
     <%- include('pagination') %>
 
+    <script src="/scripts/progress.js"></script>
+
 </body>
 
 </html>

+ 4 - 2
views/common-meta.ejs

@@ -2,7 +2,6 @@
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <link rel="icon" href="/assets/icon/favicon.ico" type="image/x-icon">
 
-<link rel="canonical" href="https://art.pcoloring.com<%=uri%>">
 <link rel="alternate" href="https://art.pcoloring.com<%=uri.replace('/'+lang, '/en') %>" hrefLang="en" />
 <link rel="alternate" href="https://art.pcoloring.com<%=uri.replace('/'+lang, '/zh') %>" hrefLang="zh" />
 <link rel="alternate" href="https://art.pcoloring.com<%=uri.replace('/'+lang, '/es') %>" hrefLang="es" />
@@ -13,4 +12,7 @@
 <title>
   <%= title %>
 </title>
-<meta name="description" content="<%= description %>">
+<meta name="description" content="<%= description %>">
+
+<meta property="og:title" content="<%= title %>">
+<meta property="og:description" content="<%= description %>">

+ 3 - 1
views/designer.ejs

@@ -28,7 +28,7 @@
     <div class="content">
       <div class="image-grid">
         <% data.forEach(item=> { %>
-          <div class="image-card">
+          <div data-content-id="<%= item._id %>" class="image-card">
             <a href="<%= item.uri %>"><img src="<%= item.thumb %>" alt="<%= item.title %>"></a>
             <div class="card-title">
               <%= item.title %>
@@ -42,6 +42,8 @@
 
     <%- include('pagination') %>
 
+    <script src="/scripts/progress.js"></script>
+    
 </body>
 
 </html>

+ 141 - 46
views/detail.ejs

@@ -3,51 +3,52 @@
 
 <head>
     <%- include('common-meta') %>
+    <meta property="og:image" content="<%= imageUrl %>" />
 
-        <link rel="stylesheet" href="/stylesheets/styles.css">
-        <link rel="stylesheet" href="/stylesheets/header.css">
-        <link rel="stylesheet" href="/stylesheets/detail.css">
-
-        <script type="text/javascript"
-            src="https://platform-api.sharethis.com/js/sharethis.js#property=67e0d66a54a3d000192a4615&product=inline-share-buttons&source=platform"
-            async="async"></script>
-
-        <script type="application/ld+json">
-        {
-            "@context": "https://schema.org",
-            "@type": "CreativeWork",
-            "name": "<%= translate.printableColoringPage[lang] %>: <%= detail.title %>",
-            "description": "<%= detail.desc %>",
-            "url": "https://art.pcoloring.com<%= uri %>",
-            "image": "<%= detail.thumb %>",
-            "category": "<%= detail.tags[0] %>",
-            "keywords": "coloring page, <%= detail.title %>, color by number, paint by number, free, printable,  <%= detail.tags.join() %>",
-            "contentRating": "General Audience",
-            "mainEntityOfPage": "https://art.pcoloring.com<%= uri %>",
-            "publisher": {
-                "@type": "Organization",
-                "name": "JCCY",
-                "logo": {
-                    "@type": "ImageObject",
-                    "url": "https://art.pcoloring.com/assets/icon/icon.webp"
-                }
-            },
-            "offers": {
-                "@type": "Offer",
-                "priceCurrency": "USD",
-                "price": "0.00",
-                "eligibleRegion": {
-                "@type": "Place",
-                "name": "Worldwide"
-                },
-                "url": "https://art.pcoloring.com<%= uri %>"
-            },
-            "author": {
-                "@type": "Person",
-                "name": "<%= detail.user.username %>"
+    <link rel="stylesheet" href="/stylesheets/styles.css">
+    <link rel="stylesheet" href="/stylesheets/header.css">
+    <link rel="stylesheet" href="/stylesheets/detail.css">
+
+    <script type="text/javascript"
+        src="https://platform-api.sharethis.com/js/sharethis.js#property=67e0d66a54a3d000192a4615&product=inline-share-buttons&source=platform"
+        async="async"></script>
+
+    <script type="application/ld+json">
+    {
+        "@context": "https://schema.org",
+        "@type": "CreativeWork",
+        "name": "<%= translate.printableColoringPage[lang] %>: <%= detail.title %>",
+        "description": "<%= detail.desc %>",
+        "url": "https://art.pcoloring.com<%= uri %>",
+        "image": "<%= detail.thumb %>",
+        "category": "<%= detail.tags[0] %>",
+        "keywords": "coloring page, <%= detail.title %>, color by number, paint by number, free, printable,  <%= detail.tags.join() %>",
+        "contentRating": "General Audience",
+        "mainEntityOfPage": "https://art.pcoloring.com<%= uri %>",
+        "publisher": {
+            "@type": "Organization",
+            "name": "JCCY",
+            "logo": {
+                "@type": "ImageObject",
+                "url": "https://art.pcoloring.com/assets/icon/icon.webp"
+            }
+        },
+        "offers": {
+            "@type": "Offer",
+            "priceCurrency": "USD",
+            "price": "0.00",
+            "eligibleRegion": {
+            "@type": "Place",
+            "name": "Worldwide"
             },
-            "datePublished": "<%= detail.publishTime %>"
-        }
+            "url": "https://art.pcoloring.com<%= uri %>"
+        },
+        "author": {
+            "@type": "Person",
+            "name": "<%= detail.user.username %>"
+        },
+        "datePublished": "<%= detail.publishTime %>"
+    }
     </script>
 </head>
 <!-- Google tag (gtag.js) -->
@@ -63,7 +64,8 @@
 <body>
     <%- include('header') %>
         <div class="details">
-            <div class="poster"><img src="<%= detail.thumb %>" alt="<%= detail.title %>"></div>
+            <div id="poster" class="poster" data-content-id="<%= detail._id %>"><img src="<%= detail.thumb %>"
+                    alt="<%= detail.title %>"></div>
             <div class="description">
                 <div style="display: flex; justify-content: space-between;">
                     <h1>
@@ -98,9 +100,21 @@
                             <%= detail.copy ?? detail.desc %>
                         </p>
                         <div class="button-wrapper">
-                            <a href="/play/<%= detail._id %>" class="play-button">
+                            <a id="playBtn" href="/play/<%= detail._id %>" class="play-button">
                                 <%= translate.play[lang] %>
                             </a>
+                            <a id="continueBtn" href="/play/<%= detail._id %>" class="play-button"
+                                style="display: none;">
+                                <%= translate.continuex[lang] %>
+                            </a>
+                            <a id="repaintBtn" onclick="onRepaint('<%= detail._id %>')" class="play-button"
+                                style="display: none;">
+                                <%= translate.repaint[lang] %>
+                            </a>
+                            <a id="reviewBtn" href="/play/<%= detail._id %>" class="play-button"
+                                style="background-color: orange; display: none;">
+                                <%= translate.view[lang] %>
+                            </a>
                             <a id="appBtn" class="play-button" style="background-color: darkolivegreen;">
                                 <%= translate.playOnApp[lang] %>
                             </a>
@@ -112,6 +126,10 @@
                                 style="background-color: black;">
                                 <%= translate.print[lang] %>
                             </a>
+                            <a id="deleteBtn" onclick="onDelete('<%= detail._id %>')" class="play-button"
+                                style="background-color: grey; display: none;">
+                                <%= translate.deletex[lang] %>
+                            </a>
                         </div>
             </div>
         </div>
@@ -123,7 +141,7 @@
         <div class="content" style="margin-bottom: 40px;">
             <div class="image-grid">
                 <% relates.forEach(item=> { %>
-                    <div class="image-card">
+                    <div data-content-id="<%= item._id %>" class="image-card">
                         <a href="<%= item.uri %>"><img src="<%= item.thumb %>" alt="<%= item.title %>"></a>
                         <div class="card-title">
                             <%= item.title %>
@@ -137,6 +155,13 @@
 
 
         <script>
+            // 重新进入或返回,强制刷新
+            window.addEventListener('pageshow', function (event) {
+                if (event.persisted) {
+                    window.location.reload();
+                }
+            });
+
             function isMobileDevice() {
                 return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
             }
@@ -188,7 +213,77 @@
                     console.error('Error printing image:', error);
                 }
             }
+
+            function onDelete(id) {
+                if (confirm('确定要删除游戏进度吗?')) {
+                    // 删除本地存储
+                    localStorage.removeItem(id);
+
+                    const METADATA_KEY = '__storage_metadata__';
+                    const metadata = JSON.parse(localStorage.getItem(METADATA_KEY) || '{}');
+                    delete metadata[id];
+                    localStorage.setItem(METADATA_KEY, JSON.stringify(metadata));
+                    location.reload(); // 刷新页面恢复初始状态
+                }
+            }
+
+            function onRepaint(id) {
+                // 删除本地存储
+                localStorage.removeItem(id);
+
+                const METADATA_KEY = '__storage_metadata__';
+                const metadata = JSON.parse(localStorage.getItem(METADATA_KEY) || '{}');
+                delete metadata[id];
+                localStorage.setItem(METADATA_KEY, JSON.stringify(metadata));
+
+                window.open(`/play/${id}`, '_self');
+            }
+
+            // 页面加载完成后执行
+            document.addEventListener('DOMContentLoaded', () => {
+                const METADATA_KEY = '__storage_metadata__';
+
+                const container = document.getElementById('poster');
+                const contentId = container.dataset.contentId;
+
+                // 获取本地存储数据
+                const metaData = JSON.parse(localStorage.getItem(METADATA_KEY)) || {};
+
+                if (metaData[contentId]) {
+                    const progress = Math.round(metaData[contentId].progress);
+                    // 创建进度角标
+                    const badge = document.createElement('div');
+                    badge.className = 'progress-badge';
+                    badge.innerHTML = `<span>${progress >= 100 ? '✓' : progress + '%'}</span>`;
+                    badge.style.backgroundColor = progress >= 100 ? '#4CAF50' : '#FF5252';
+                    // 添加渐变动画
+                    badge.style.transition = 'background-color 0.3s ease';
+                    // 插入到缩略图容器内
+                    container.appendChild(badge);
+
+                    // 添加删除按钮
+                    const deleteBtn = document.getElementById('deleteBtn');
+                    deleteBtn.style.display = 'block';
+
+                    // 开始填色按钮便成继续填色或重新填色
+                    const playBtn = document.getElementById('playBtn');
+                    const continueBtn = document.getElementById('continueBtn');
+                    const repaintBtn = document.getElementById('repaintBtn');
+                    const reviewBtn = document.getElementById('reviewBtn');
+                    playBtn.style.display = 'none';
+                    if (progress < 100) {
+                        continueBtn.style.display = 'block';
+                    } else {
+                        repaintBtn.style.display = 'block';
+                        reviewBtn.style.display = 'block';
+
+                        const img = document.querySelector('#poster img');
+                        img.src = img.src.replace('/page/', '/work/');
+                    }
+                }
+            });
         </script>
+        <script src="/scripts/progress.js"></script>
 </body>
 
 </html>

+ 3 - 1
views/gallery.ejs

@@ -29,7 +29,7 @@
     <div class="content">
       <div class="image-grid">
         <% data.forEach(item=> { %>
-          <div class="image-card">
+          <div data-content-id="<%= item._id %>" class="image-card">
             <a href="<%= item.uri %>"><img src="<%= item.thumb %>" alt="<%= item.title %>"></a>
             <div class="card-title">
               <%= item.title %>
@@ -50,6 +50,8 @@
           <% }); %>
       </div>
 
+      <script src="/scripts/progress.js"></script>
+      
 </body>
 
 </html>

+ 2 - 2
views/header.ejs

@@ -118,8 +118,8 @@
 
     </div>
 
-    <!-- <a href="/<%= lang %>/app" class="header-right-btn"><%= translate.app[lang] %></a>
-    <a href="/<%= lang %>/my-works" class="header-right-btn"><%= translate.my[lang] %></a> -->
+    <!-- <a href="/<%= lang %>/app" class="header-right-btn"><%= translate.app[lang] %></a>-->
+    <a href="/<%= lang %>/myworks" class="header-right-btn"><%= translate.my[lang] %></a>
   </div>
 
 </header>

+ 1 - 1
views/hot-section.ejs

@@ -11,7 +11,7 @@
   <div class="content">
     <div class="image-grid">
       <% recommend.forEach(item=> { %>
-        <div class="image-card">
+        <div data-content-id="<%= item._id %>" class="image-card">
           <a href="<%= item.uri %>"><img src="<%= item.thumb %>" alt="<%= item.title %>"></a>
           <div class="card-title"><%= item.title %></div>
         </div>

+ 2 - 0
views/index.ejs

@@ -59,6 +59,8 @@
     <%- include('footer') %>
     <%- include('cookie-banner') %>
     <div style="height: 50px;"></div>
+
+  <script src="/scripts/progress.js"></script>
 </body>
 
 

+ 1 - 1
views/latest-section.ejs

@@ -11,7 +11,7 @@
   <div class="content">
     <div class="image-grid">
       <% latest.forEach(item=> { %>
-        <div class="image-card">
+        <div data-content-id="<%= item._id %>" class="image-card">
           <a href="<%= item.uri %>"><img src="<%= item.thumb %>" alt="<%= item.title %>"></a>
           <div class="card-title"><%= item.title %></div>
         </div>

+ 127 - 0
views/myworks.ejs

@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<html lang="<%= lang %>">
+
+<head>
+  <%- include('common-meta') %>
+    <link rel="stylesheet" href="/stylesheets/styles.css">
+    <link rel="stylesheet" href="/stylesheets/header.css">
+    <link rel="stylesheet" href="/stylesheets/myworks.css">
+</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>
+  <%- include('header') %>
+    <div class="tab-container">
+      <!-- 标签导航 -->
+      <nav class="tab-nav">
+        <button class="tab-button active" data-tab="ongoing"><%= translate.inProgress[lang] %></button>
+        <button class="tab-button" data-tab="completed"><%= translate.completed[lang] %></button>
+        <button class="tab-button" data-tab="favorite"><%= translate.favorite[lang] %></button>
+      </nav>
+
+      <!-- 进行中内容 -->
+      <div id="ongoing" class="tab-content active">
+        <div class="image-grid">
+        </div>
+      </div>
+
+      <!-- 已完成内容 -->
+      <div id="completed" class="tab-content">
+        <div class="image-grid">
+        </div>
+      </div>
+
+      <!-- 收藏内容 -->
+      <div id="favorite" class="tab-content">
+        <div class="image-grid">
+        </div>
+      </div>
+    </div>
+
+    <script>
+      const host = '<%= host %>';
+      const lang = '<%= lang %>';
+
+      // 标签切换功能
+      const tabButtons = document.querySelectorAll('.tab-button');
+      const tabContents = document.querySelectorAll('.tab-content');
+
+      tabButtons.forEach(button => {
+        button.addEventListener('click', () => {
+          const targetTab = button.dataset.tab;
+
+          // 移除所有激活状态
+          tabButtons.forEach(btn => btn.classList.remove('active'));
+          tabContents.forEach(content => content.classList.remove('active'));
+
+          // 添加当前激活状态
+          button.classList.add('active');
+          document.getElementById(targetTab).classList.add('active');
+        });
+      });
+
+
+      // 加载
+      const loadWorks = (tabType) => {
+        let data = {};
+        if (tabType === 'favorite') {
+          const raw = localStorage.getItem('_storage_collection__') || '{}';
+          data = JSON.parse(raw);
+        } else {
+          const rawMeta = localStorage.getItem('__storage_metadata__') || '{}';
+          const metaData = JSON.parse(rawMeta);
+          data = Object.entries(metaData).filter(([_, item]) =>
+            tabType === 'ongoing' ? item.progress < 100 : item.progress >= 100
+          ).reduce((acc, [id, item]) => ({ ...acc, [id]: item }), {});
+        }
+
+        return Object.entries(data).map(([id, item]) => ({
+          id,
+          uri: `/${lang}/coloring-page/${id}`,
+          thumbnail: `${host}/thumbs/coloring-page/page/480/${id}.png`, // 缩略图拼接规则‌:ml-citation{ref="7" data="citationList"}
+          progress: item.progress,
+          timestamp: item.timestamp
+        })).sort((a, b) => b.timestamp - a.timestamp); // 时间倒序排列
+      };
+
+
+      // 动态渲染
+      const renderWorks = (container, items) => {
+        container.innerHTML = '';
+        items.forEach(item => {
+          const card = document.createElement('div');
+          card.className = 'image-card';
+          card.innerHTML = `
+                    <a href="${item.uri}"><img src="${item.thumbnail}"></a>
+                `;
+          if (item.progress) {
+            card.innerHTML += `
+                <div class="progress-badge" style="background-color: ${item.progress >= 100 ? '#4CAF50' : '#FF5252'}; transition: background-color 0.3s ease; ">
+                  <span>${item.progress >= 100 ? '✓' : item.progress + '%'}</span>
+                </div>
+            `
+          }
+          container.appendChild(card);
+        });
+      };
+
+
+      document.querySelectorAll('.tab-content').forEach(container => {
+        const tabType = container.id;
+        const works = loadWorks(tabType);
+        const grid = container.querySelector('.image-grid');
+        renderWorks(grid, works);
+      });
+
+    </script>
+</body>
+
+</html>

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 24 - 11
views/play.ejs


+ 1 - 1
views/special-section.ejs

@@ -11,7 +11,7 @@
   <div class="content">
     <div class="image-grid">
       <% special.forEach(item=> { %>
-        <div class="image-card">
+        <div data-content-id="<%= item._id %>" class="image-card">
           <a href="<%= item.uri %>"><img src="<%= item.thumb %>" alt="<%= item.title %>"></a>
           <div class="card-title"><%= item.title %></div>
         </div>

+ 3 - 1
views/special.ejs

@@ -29,7 +29,7 @@
     <div class="content">
       <div class="image-grid">
         <% data.forEach(item=> { %>
-          <div class="image-card">
+          <div data-content-id="<%= item._id %>" class="image-card">
             <a href="<%= item.uri %>"><img src="<%= item.thumb %>" alt="<%= item.title %>"></a>
             <div class="card-title">
               <%= item.title %>
@@ -50,6 +50,8 @@
         <% }); %>
     </div>
 
+    <script src="/scripts/progress.js"></script>
+    
 </body>
 
 </html>

+ 2 - 1
views/tag.ejs

@@ -67,7 +67,7 @@
       <div class="content">
         <div class="image-grid">
           <% data.forEach(item=> { %>
-            <div class="image-card">
+            <div data-content-id="<%= item._id %>" class="image-card">
               <a href="<%= item.uri %>"><img src="<%= item.thumb %>" alt="<%= item.title %>"></a>
               <div class="card-title">
                 <%= item.title %>
@@ -89,6 +89,7 @@
               <% }); %>
           </div>
 
+    <script src="/scripts/progress.js"></script>
 </body>
 
 </html>

+ 1 - 1
views/video-story-section.ejs

@@ -101,7 +101,7 @@
 
     video.contents.forEach(item => {
       contentHTML += `
-        <div class="image-card" style="margin-bottom: 10px;">
+        <div data-content-id="${item._id}" class="image-card" style="margin-bottom: 10px;">
           <a href=${item.uri}><img src=${item.thumb} alt='${item.title}'></a>
           <div class="card-title">${item.title}</div>
         </div>

+ 1 - 3
views/videos.ejs

@@ -125,7 +125,7 @@
 
         video.contents.forEach(item => {
           contentHTML += `
-            <div class="image-card" style="margin-bottom: 10px;">
+            <div data-content-id="${item._id}" class="image-card" style="margin-bottom: 10px;">
               <a href=${item.uri}><img src=${item.thumb} alt='${item.title}'></a>
               <div class="card-title">${item.title}</div>
             </div>
@@ -139,8 +139,6 @@
       }
 
     </script>
-
-
 </body>
 
 </html>

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.