From 041556786d18910c69a7efd6614654e6031497f7 Mon Sep 17 00:00:00 2001 From: furu04 Date: Thu, 8 Jan 2026 23:56:52 +0900 Subject: [PATCH] =?UTF-8?q?SNS=E3=82=B7=E3=82=A7=E3=82=A2=E6=A9=9F?= =?UTF-8?q?=E8=83=BD=E3=82=92=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/templates/assignments/statistics.html | 207 +++++++++++++++++++++- 1 file changed, 205 insertions(+), 2 deletions(-) diff --git a/web/templates/assignments/statistics.html b/web/templates/assignments/statistics.html index b774e76..b012d06 100644 --- a/web/templates/assignments/statistics.html +++ b/web/templates/assignments/statistics.html @@ -44,7 +44,62 @@ .stats-table td:first-child { min-width: 120px; } + + #shareCard { + width: 600px; + height: 315px; + position: fixed; + left: -9999px; + top: 0; + background: linear-gradient(135deg, #005bea 0%, #00c6fb 100%); + padding: 2rem; + color: white; + border-radius: 12px; + display: flex; + flex-direction: column; + justify-content: space-between; + font-family: 'Inter', system-ui, -apple-system, sans-serif; + } + + #shareCard .card-title { + font-size: 1.5rem; + font-weight: bold; + opacity: 0.9; + } + + #shareCard .rate-display { + font-size: 5rem; + font-weight: bold; + line-height: 1; + margin: 1rem 0; + } + + #shareCard .stats-row { + display: flex; + justify-content: space-around; + background: rgba(255, 255, 255, 0.1); + border-radius: 8px; + padding: 1rem; + backdrop-filter: blur(5px); + } + + #shareCard .stat-item { + text-align: center; + } + + #shareCard .stat-label { + font-size: 0.8rem; + opacity: 0.8; + display: block; + margin-bottom: 0.2rem; + } + + #shareCard .stat-value { + font-size: 1.4rem; + font-weight: bold; + } + {{end}} {{define "content"}} @@ -144,8 +199,11 @@
-
- 期限内完了率 +
+ 期限内完了率 +
@@ -252,6 +310,69 @@

課題を登録して科目を設定すると、ここに統計が表示されます。

+ +
+
+
+ + Super Homework Manager +
+
+ +
+
期限内完了率
+
+ {{printf "%.1f" .stats.OnTimeCompletionRate}}% +
+
+ +
+
+ 完了 + {{.stats.CompletedAssignments}} +
+
+ 未完了 + {{.stats.PendingAssignments}} +
+
+ 期限切れ + {{.stats.OverdueAssignments}} +
+
+
+ + + {{end}} {{define "scripts"}} @@ -269,6 +390,88 @@ var activePage = 1; var archivedPage = 1; + // Share Functionality + window.generateShareImage = function () { + var card = document.getElementById('shareCard'); + // Ensure card is visible for rendering but off-screen + card.style.display = 'flex'; + + html2canvas(card, { + backgroundColor: null, + scale: 2 // High resolution + }).then(canvas => { + var imgData = canvas.toDataURL('image/png'); + + // Set up preview + var previewContainer = document.getElementById('sharePreviewContainer'); + previewContainer.innerHTML = ''; + var img = document.createElement('img'); + img.src = imgData; + img.style.maxWidth = '100%'; + img.style.borderRadius = '8px'; + img.style.boxShadow = '0 4px 12px rgba(0,0,0,0.1)'; + previewContainer.appendChild(img); + + // Set up download link + var downloadLink = document.getElementById('downloadLink'); + downloadLink.href = imgData; + + // Set up Twitter button + var text = '私の課題完了状況\n期限内完了率: {{printf "%.1f" .stats.OnTimeCompletionRate}}%\n#HomeworkManager'; + var twitterBtn = document.getElementById('twitterShareBtn'); + twitterBtn.href = "https://twitter.com/intent/tweet?text=" + encodeURIComponent(text); + + // Show modal + var modal = new bootstrap.Modal(document.getElementById('shareModal')); + modal.show(); + }); + }; + + // Helper to convert Data URL to Blob + function dataURLtoBlob(dataurl) { + var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], + bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new Blob([u8arr], { type: mime }); + } + + window.copyImageToClipboard = function (btn) { + var canvas = document.querySelector('#sharePreviewContainer img'); + if (!canvas) return; + + if (!navigator.clipboard) { + alert('このブラウザまたは環境(非HTTPS/非localhost)では、クリップボードへのコピー機能がサポートされていません。\n「画像を保存」を使用してください。'); + return; + } + + try { + var blob = dataURLtoBlob(canvas.src); + navigator.clipboard.write([ + new ClipboardItem({ + 'image/png': blob + }) + ]).then(function () { + var originalText = btn.innerHTML; + btn.innerHTML = 'コピーしました'; + btn.classList.remove('btn-outline-primary'); + btn.classList.add('btn-success'); + setTimeout(function () { + btn.innerHTML = originalText; + btn.classList.add('btn-outline-primary'); + btn.classList.remove('btn-success'); + }, 2000); + }).catch(function (err) { + console.error('Failed to copy: ', err); + alert('画像のコピーに失敗しました。\nエラー: ' + err.message + '\n「画像を保存」を使用してください。'); + }); + } catch (err) { + console.error('Failed to create blob: ', err); + alert('画像データの生成に失敗しました: ' + err.message); + } + }; + function getRateClass(rate) { if (rate >= 80) return 'text-success'; if (rate >= 50) return 'text-warning';