detail.ejs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. <!DOCTYPE html>
  2. <html lang="<%= lang %>">
  3. <head>
  4. <%- include('common-meta') %>
  5. <meta property="og:image" content="<%= imageUrl %>" />
  6. <link rel="stylesheet" href="/stylesheets/styles.css">
  7. <link rel="stylesheet" href="/stylesheets/header.css">
  8. <link rel="stylesheet" href="/stylesheets/detail.css">
  9. <script type="text/javascript"
  10. src="https://platform-api.sharethis.com/js/sharethis.js#property=67e0d66a54a3d000192a4615&product=inline-share-buttons&source=platform"
  11. async="async"></script>
  12. <script type="application/ld+json">
  13. {
  14. "@context": "https://schema.org",
  15. "@type": "CreativeWork",
  16. "name": "<%= translate.printableColoringPage[lang] %>: <%= detail.title %>",
  17. "description": "<%= detail.desc %>",
  18. "url": "https://art.pcoloring.com<%= uri %>",
  19. "image": "<%= detail.thumb %>",
  20. "category": "<%= detail.tags[0] %>",
  21. "keywords": "coloring page, <%= detail.title %>, color by number, paint by number, free, printable, <%= detail.tags.join() %>",
  22. "contentRating": "General Audience",
  23. "mainEntityOfPage": "https://art.pcoloring.com<%= uri %>",
  24. "publisher": {
  25. "@type": "Organization",
  26. "name": "JCCY",
  27. "logo": {
  28. "@type": "ImageObject",
  29. "url": "https://art.pcoloring.com/assets/icon/icon.webp"
  30. }
  31. },
  32. "offers": {
  33. "@type": "Offer",
  34. "priceCurrency": "USD",
  35. "price": "0.00",
  36. "eligibleRegion": {
  37. "@type": "Place",
  38. "name": "Worldwide"
  39. },
  40. "url": "https://art.pcoloring.com<%= uri %>"
  41. },
  42. "author": {
  43. "@type": "Person",
  44. "name": "<%= detail.user.username %>"
  45. },
  46. "datePublished": "<%= detail.publishTime %>"
  47. }
  48. </script>
  49. </head>
  50. <!-- Google tag (gtag.js) -->
  51. <script async src="https://www.googletagmanager.com/gtag/js?id=G-JBGGVGLHTP"></script>
  52. <script>
  53. window.dataLayer = window.dataLayer || [];
  54. function gtag() { dataLayer.push(arguments); }
  55. gtag('js', new Date());
  56. gtag('config', 'G-JBGGVGLHTP');
  57. </script>
  58. <body>
  59. <%- include('header') %>
  60. <div class="details">
  61. <div id="poster" class="poster" data-content-id="<%= detail._id %>"><img src="<%= detail.thumb %>"
  62. alt="<%= detail.title %>"></div>
  63. <div class="description">
  64. <div style="display: flex; justify-content: space-between;">
  65. <h1>
  66. <%= detail.title %>
  67. </h1>
  68. <div class="sharethis-inline-share-buttons"></div>
  69. </div>
  70. <% if (detail.totalStartCount> 0) { %>
  71. <div style="color:gray;">
  72. <%=detail.totalStartCount%>
  73. <%= translate.interested[lang] %>
  74. </div>
  75. <% } %>
  76. <p>
  77. <%= translate.artist[lang] %>: <a href="/<%= lang %>/artist/<%= detail.user._id %>"
  78. class="tag-button">
  79. <%= detail.user.username %>
  80. </a>
  81. </p>
  82. <p>
  83. <%= translate.publishTime[lang] %>: <%= detail.publishTime %>
  84. </p>
  85. <p>
  86. <%= translate.tag[lang] %>:
  87. <% detail.tags.forEach(tag=> { %>
  88. <a href="/<%= lang %>/tag/<%= tag %>" class="tag-button">
  89. <%= tag %>
  90. </a>
  91. <% }); %>
  92. </p>
  93. <p>
  94. <%= detail.copy ?? detail.desc %>
  95. </p>
  96. <div class="button-wrapper">
  97. <a id="playBtn" href="/play/<%= detail._id %>" class="play-button">
  98. <%= translate.play[lang] %>
  99. </a>
  100. <a id="continueBtn" href="/play/<%= detail._id %>" class="play-button"
  101. style="display: none;">
  102. <%= translate.continuex[lang] %>
  103. </a>
  104. <a id="repaintBtn" onclick="onRepaint('<%= detail._id %>')" class="play-button"
  105. style="display: none;">
  106. <%= translate.repaint[lang] %>
  107. </a>
  108. <a id="reviewBtn" href="/play/<%= detail._id %>" class="play-button"
  109. style="background-color: orange; display: none;">
  110. <%= translate.view[lang] %>
  111. </a>
  112. <a id="appBtn" class="play-button" style="background-color: darkolivegreen;">
  113. <%= translate.playOnApp[lang] %>
  114. </a>
  115. <a href="/download/pdf/page/<%= detail._id %>" class="play-button"
  116. style="background-color: lightseagreen;">
  117. <%= translate.download[lang] %>
  118. </a>
  119. <a id="printBtn" onclick="printImage('<%= detail._id %>')" class="play-button"
  120. style="background-color: black;">
  121. <%= translate.print[lang] %>
  122. </a>
  123. <a id="deleteBtn" onclick="onDelete('<%= detail._id %>')" class="play-button"
  124. style="background-color: grey; display: none;">
  125. <%= translate.deletex[lang] %>
  126. </a>
  127. </div>
  128. </div>
  129. </div>
  130. <p style=" display: flex; justify-content: center; color: #777; font-size: 18px; font-weight: 500;">
  131. <%= translate.mayYouLike[lang] %>:
  132. </p>
  133. <div class="content" style="margin-bottom: 40px;">
  134. <div class="image-grid">
  135. <% relates.forEach(item=> { %>
  136. <div data-content-id="<%= item._id %>" class="image-card">
  137. <a href="<%= item.uri %>"><img src="<%= item.thumb %>" alt="<%= item.title %>"></a>
  138. <div class="card-title">
  139. <%= item.title %>
  140. </div>
  141. </div>
  142. <% }); %>
  143. </div>
  144. </div>
  145. <!-- <%- include('pagination') %> -->
  146. <script>
  147. // 重新进入或返回,强制刷新
  148. window.addEventListener('pageshow', function (event) {
  149. if (event.persisted) {
  150. window.location.reload();
  151. }
  152. });
  153. function isMobileDevice() {
  154. return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
  155. }
  156. window.onload = function () {
  157. if (isMobileDevice()) {
  158. const printBtn = document.getElementById('printBtn');
  159. printBtn.style.display = 'none'; // 移动端隐藏打印按钮
  160. }
  161. };
  162. document.getElementById('appBtn').addEventListener('click', function () {
  163. const userAgent = navigator.userAgent || navigator.vendor || window.opera;
  164. // Android 检测
  165. if (/android/i.test(userAgent)) {
  166. window.open('https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number', '_blank');
  167. }
  168. // iOS 检测
  169. else if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
  170. window.open('https://apps.apple.com/gb/app/art-number-coloring-book/id1575480118', '_blank');
  171. }
  172. // 其他操作系统(例如桌面)
  173. else {
  174. // 可以显示一个提示,或者跳转到通用的下载页面
  175. console.log('无法确定操作系统,或者为桌面操作系统');
  176. window.open('https://pcoloring.com/anc/', '_blank');
  177. }
  178. });
  179. async function printImage(id) {
  180. try {
  181. const response = await fetch(`/download/pdf/page/${id}`);
  182. if (!response.ok) {
  183. throw new Error(`HTTP error! status: ${response.status}`);
  184. }
  185. const pdfBlob = await response.blob();
  186. const pdfUrl = URL.createObjectURL(pdfBlob);
  187. const printWindow = window.open(pdfUrl, '_blank');
  188. printWindow.onload = () => {
  189. printWindow.print();
  190. };
  191. URL.revokeObjectURL(pdfUrl); // 释放 URL 对象
  192. } catch (error) {
  193. console.error('Error printing image:', error);
  194. }
  195. }
  196. function onDelete(id) {
  197. if (confirm('确定要删除游戏进度吗?')) {
  198. // 删除本地存储
  199. localStorage.removeItem(id);
  200. const METADATA_KEY = '__storage_metadata__';
  201. const metadata = JSON.parse(localStorage.getItem(METADATA_KEY) || '{}');
  202. delete metadata[id];
  203. localStorage.setItem(METADATA_KEY, JSON.stringify(metadata));
  204. location.reload(); // 刷新页面恢复初始状态
  205. }
  206. }
  207. function onRepaint(id) {
  208. // 删除本地存储
  209. localStorage.removeItem(id);
  210. const METADATA_KEY = '__storage_metadata__';
  211. const metadata = JSON.parse(localStorage.getItem(METADATA_KEY) || '{}');
  212. delete metadata[id];
  213. localStorage.setItem(METADATA_KEY, JSON.stringify(metadata));
  214. window.open(`/play/${id}`, '_self');
  215. }
  216. // 页面加载完成后执行
  217. document.addEventListener('DOMContentLoaded', () => {
  218. const METADATA_KEY = '__storage_metadata__';
  219. const container = document.getElementById('poster');
  220. const contentId = container.dataset.contentId;
  221. // 获取本地存储数据
  222. const metaData = JSON.parse(localStorage.getItem(METADATA_KEY)) || {};
  223. if (metaData[contentId]) {
  224. const progress = Math.round(metaData[contentId].progress);
  225. // 创建进度角标
  226. const badge = document.createElement('div');
  227. badge.className = 'progress-badge';
  228. badge.innerHTML = `<span>${progress >= 100 ? '✓' : progress + '%'}</span>`;
  229. badge.style.backgroundColor = progress >= 100 ? '#4CAF50' : '#FF5252';
  230. // 添加渐变动画
  231. badge.style.transition = 'background-color 0.3s ease';
  232. // 插入到缩略图容器内
  233. container.appendChild(badge);
  234. // 添加删除按钮
  235. const deleteBtn = document.getElementById('deleteBtn');
  236. deleteBtn.style.display = 'block';
  237. // 开始填色按钮便成继续填色或重新填色
  238. const playBtn = document.getElementById('playBtn');
  239. const continueBtn = document.getElementById('continueBtn');
  240. const repaintBtn = document.getElementById('repaintBtn');
  241. const reviewBtn = document.getElementById('reviewBtn');
  242. playBtn.style.display = 'none';
  243. if (progress < 100) {
  244. continueBtn.style.display = 'block';
  245. } else {
  246. repaintBtn.style.display = 'block';
  247. reviewBtn.style.display = 'block';
  248. const img = document.querySelector('#poster img');
  249. img.src = img.src.replace('/page/', '/work/');
  250. }
  251. }
  252. });
  253. </script>
  254. <script src="/scripts/progress.js"></script>
  255. </body>
  256. </html>