GameSentenceMiner 2.17.7__py3-none-any.whl → 2.18.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- GameSentenceMiner/ai/ai_prompting.py +6 -6
- GameSentenceMiner/anki.py +236 -152
- GameSentenceMiner/gametext.py +7 -4
- GameSentenceMiner/gsm.py +49 -10
- GameSentenceMiner/locales/en_us.json +7 -3
- GameSentenceMiner/locales/ja_jp.json +8 -4
- GameSentenceMiner/locales/zh_cn.json +8 -4
- GameSentenceMiner/obs.py +238 -59
- GameSentenceMiner/ocr/owocr_helper.py +1 -1
- GameSentenceMiner/tools/ss_selector.py +7 -8
- GameSentenceMiner/ui/__init__.py +0 -0
- GameSentenceMiner/ui/anki_confirmation.py +187 -0
- GameSentenceMiner/{config_gui.py → ui/config_gui.py} +100 -35
- GameSentenceMiner/ui/screenshot_selector.py +215 -0
- GameSentenceMiner/util/configuration.py +124 -22
- GameSentenceMiner/util/db.py +22 -13
- GameSentenceMiner/util/downloader/download_tools.py +2 -2
- GameSentenceMiner/util/ffmpeg.py +24 -30
- GameSentenceMiner/util/get_overlay_coords.py +34 -34
- GameSentenceMiner/util/gsm_utils.py +31 -1
- GameSentenceMiner/util/text_log.py +11 -9
- GameSentenceMiner/vad.py +31 -12
- GameSentenceMiner/web/database_api.py +742 -123
- GameSentenceMiner/web/static/css/dashboard-shared.css +241 -0
- GameSentenceMiner/web/static/css/kanji-grid.css +94 -2
- GameSentenceMiner/web/static/css/overview.css +850 -0
- GameSentenceMiner/web/static/css/popups-shared.css +126 -0
- GameSentenceMiner/web/static/css/shared.css +97 -0
- GameSentenceMiner/web/static/css/stats.css +192 -597
- GameSentenceMiner/web/static/js/anki_stats.js +6 -4
- GameSentenceMiner/web/static/js/database.js +209 -5
- GameSentenceMiner/web/static/js/goals.js +610 -0
- GameSentenceMiner/web/static/js/kanji-grid.js +267 -4
- GameSentenceMiner/web/static/js/overview.js +1176 -0
- GameSentenceMiner/web/static/js/shared.js +25 -0
- GameSentenceMiner/web/static/js/stats.js +154 -1459
- GameSentenceMiner/web/stats.py +2 -2
- GameSentenceMiner/web/templates/anki_stats.html +5 -0
- GameSentenceMiner/web/templates/components/navigation.html +3 -1
- GameSentenceMiner/web/templates/database.html +73 -1
- GameSentenceMiner/web/templates/goals.html +376 -0
- GameSentenceMiner/web/templates/index.html +13 -11
- GameSentenceMiner/web/templates/overview.html +416 -0
- GameSentenceMiner/web/templates/stats.html +46 -251
- GameSentenceMiner/web/texthooking_page.py +18 -0
- {gamesentenceminer-2.17.7.dist-info → gamesentenceminer-2.18.0.dist-info}/METADATA +5 -1
- {gamesentenceminer-2.17.7.dist-info → gamesentenceminer-2.18.0.dist-info}/RECORD +51 -41
- {gamesentenceminer-2.17.7.dist-info → gamesentenceminer-2.18.0.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.17.7.dist-info → gamesentenceminer-2.18.0.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.17.7.dist-info → gamesentenceminer-2.18.0.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.17.7.dist-info → gamesentenceminer-2.18.0.dist-info}/top_level.txt +0 -0
GameSentenceMiner/web/stats.py
CHANGED
|
@@ -48,8 +48,8 @@ def get_gradient_color(frequency, max_frequency):
|
|
|
48
48
|
if max_frequency == 0:
|
|
49
49
|
return "#ebedf0" # Default color for no encounters
|
|
50
50
|
|
|
51
|
-
# kanji with
|
|
52
|
-
if frequency >
|
|
51
|
+
# kanji with 300+ encounters should always get cyan color cause i think u should know them
|
|
52
|
+
if frequency > 300:
|
|
53
53
|
return "#2ee6e0"
|
|
54
54
|
|
|
55
55
|
# Normalize frequency to 0-1 range with square root transformation
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
<!-- Include shared CSS -->
|
|
18
18
|
<link rel="stylesheet" href="/static/css/shared.css">
|
|
19
19
|
|
|
20
|
+
<!-- Include shared dashboard and popup CSS -->
|
|
21
|
+
<link rel="stylesheet" href="/static/css/dashboard-shared.css">
|
|
22
|
+
<link rel="stylesheet" href="/static/css/popups-shared.css">
|
|
23
|
+
|
|
20
24
|
<!-- Include stats-specific CSS -->
|
|
21
25
|
<link rel="stylesheet" href="/static/css/stats.css">
|
|
22
26
|
|
|
@@ -81,6 +85,7 @@
|
|
|
81
85
|
Missing High-Frequency Kanji
|
|
82
86
|
</h3>
|
|
83
87
|
<p class="dashboard-card-subtitle">Kanji seen often in GSM but not present in your Anki collection</p>
|
|
88
|
+
<p class="dashboard-card-subtitle">Note: Please Sort By frequency, as grey means the Kanji might be in your Anki</p>
|
|
84
89
|
</div>
|
|
85
90
|
<div class="dashboard-streak-indicator" id="missingKanjiStreak" style="display: none;">
|
|
86
91
|
<span id="missingStreakValue">0</span> to learn
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
<div class="navigation" style="display: flex; justify-content: center; align-items: center; margin-bottom: 30px; padding: 15px; background: var(--bg-secondary); border-radius: 8px; box-shadow: 0 2px 8px var(--shadow-color); border: 1px solid var(--border-color);">
|
|
3
3
|
<div style="display: flex; gap: 15px;">
|
|
4
4
|
<!-- <a href="/" class="nav-link">Home</a> -->
|
|
5
|
+
<a href="/overview" class="nav-link">Overview</a>
|
|
5
6
|
<a href="/stats" class="nav-link">Statistics</a>
|
|
7
|
+
<a href="/goals" class="nav-link">Goals</a>
|
|
8
|
+
<a href="/anki_stats" class="nav-link">Anki Stats</a>
|
|
6
9
|
<a href="/search" class="nav-link">Search</a>
|
|
7
10
|
<a href="/database" class="nav-link">Database Management</a>
|
|
8
|
-
<a href="/anki_stats" class="nav-link">Anki Stats</a>
|
|
9
11
|
</div>
|
|
10
12
|
<button class="theme-toggle" id="settingsToggle" title="Settings">
|
|
11
13
|
<span id="settingsIcon">⚙️</span>
|
|
@@ -95,11 +95,19 @@
|
|
|
95
95
|
<div id="gamesDeletionModal" class="modal">
|
|
96
96
|
<div class="modal-content" style="max-width: 800px;">
|
|
97
97
|
<div class="modal-header">
|
|
98
|
-
<h3>
|
|
98
|
+
<h3>Manage Games</h3>
|
|
99
99
|
<span class="close-btn" data-action="closeModal" data-modal="gamesDeletionModal">×</span>
|
|
100
100
|
</div>
|
|
101
101
|
<div class="modal-body">
|
|
102
102
|
<p class="warning-text">Select games to delete. This will permanently remove all associated sentences and data.</p>
|
|
103
|
+
|
|
104
|
+
<p class="warning-text">When Merging, the first selected game will be the target for all merged data.</p>
|
|
105
|
+
|
|
106
|
+
<div style="margin-bottom: 15px; padding: 10px; background: var(--bg-tertiary); border-radius: 5px; border-left: 4px solid var(--accent-color);">
|
|
107
|
+
<small style="color: var(--text-secondary); font-size: 13px;">
|
|
108
|
+
<strong>Note:</strong> Game names come from the OBS Scene, to change the name for future stats, change the scene name in OBS.
|
|
109
|
+
</small>
|
|
110
|
+
</div>
|
|
103
111
|
|
|
104
112
|
<div id="gamesLoadingIndicator" class="loading-indicator">
|
|
105
113
|
<div class="spinner"></div>
|
|
@@ -118,6 +126,7 @@
|
|
|
118
126
|
</div>
|
|
119
127
|
<div class="modal-footer">
|
|
120
128
|
<button class="action-btn" data-action="closeModal" data-modal="gamesDeletionModal">Cancel</button>
|
|
129
|
+
<button class="action-btn warning" id="mergeSelectedGamesBtn" data-action="mergeSelectedGames" disabled>Merge Selected Games</button>
|
|
121
130
|
<button class="action-btn danger" id="deleteSelectedGamesBtn" data-action="deleteSelectedGames" disabled>Delete Selected</button>
|
|
122
131
|
</div>
|
|
123
132
|
</div>
|
|
@@ -272,6 +281,69 @@
|
|
|
272
281
|
</div>
|
|
273
282
|
</div>
|
|
274
283
|
|
|
284
|
+
<!-- Game Merge Confirmation Modal -->
|
|
285
|
+
<div id="gameMergeModal" class="modal">
|
|
286
|
+
<div class="modal-content" style="max-width: 700px;">
|
|
287
|
+
<div class="modal-header">
|
|
288
|
+
<h3>Confirm Game Merge</h3>
|
|
289
|
+
<span class="close-btn" data-action="closeModal" data-modal="gameMergeModal">×</span>
|
|
290
|
+
</div>
|
|
291
|
+
<div class="modal-body">
|
|
292
|
+
<p class="warning-text">
|
|
293
|
+
⚠️ This action is irreversible! You are about to merge multiple games into a single game entry.
|
|
294
|
+
</p>
|
|
295
|
+
|
|
296
|
+
<div class="merge-summary">
|
|
297
|
+
<h4 style="margin-bottom: 15px; color: var(--text-primary);">Merge Details:</h4>
|
|
298
|
+
|
|
299
|
+
<div class="primary-game-info" style="background: var(--bg-tertiary); padding: 15px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid var(--success-color);">
|
|
300
|
+
<h5 style="margin: 0 0 10px 0; color: var(--success-color);">
|
|
301
|
+
📁 Primary Game (will keep this name):
|
|
302
|
+
</h5>
|
|
303
|
+
<div id="primaryGameName" style="font-weight: 600; font-size: 16px; color: var(--text-primary);"></div>
|
|
304
|
+
<div id="primaryGameStats" style="color: var(--text-secondary); font-size: 14px; margin-top: 5px;"></div>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
<div class="secondary-games-info" style="background: var(--bg-tertiary); padding: 15px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid var(--warning-color);">
|
|
308
|
+
<h5 style="margin: 0 0 10px 0; color: var(--warning-color);">
|
|
309
|
+
🔄 Games to be merged (will be removed):
|
|
310
|
+
</h5>
|
|
311
|
+
<div id="secondaryGamesList" style="max-height: 150px; overflow-y: auto;"></div>
|
|
312
|
+
</div>
|
|
313
|
+
|
|
314
|
+
<div class="merge-stats" style="background: var(--bg-secondary); padding: 15px; border-radius: 8px; border: 1px solid var(--border-color);">
|
|
315
|
+
<div class="stats-row">
|
|
316
|
+
<span class="stats-label">Total sentences after merge:</span>
|
|
317
|
+
<span class="stats-value" id="totalSentencesAfterMerge">0</span>
|
|
318
|
+
</div>
|
|
319
|
+
<div class="stats-row">
|
|
320
|
+
<span class="stats-label">Total characters after merge:</span>
|
|
321
|
+
<span class="stats-value" id="totalCharactersAfterMerge">0</span>
|
|
322
|
+
</div>
|
|
323
|
+
<div class="stats-row">
|
|
324
|
+
<span class="stats-label">Games being consolidated:</span>
|
|
325
|
+
<span class="stats-value" id="gamesBeingMerged">0</span>
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
</div>
|
|
329
|
+
|
|
330
|
+
<div id="mergeError" class="error-text" style="display: none;"></div>
|
|
331
|
+
<div id="mergeSuccess" class="success-text" style="display: none;"></div>
|
|
332
|
+
|
|
333
|
+
<div id="mergeLoadingIndicator" class="loading-indicator" style="display: none;">
|
|
334
|
+
<div class="spinner"></div>
|
|
335
|
+
<span>Merging games...</span>
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
<div class="modal-footer">
|
|
339
|
+
<button class="action-btn" data-action="closeModal" data-modal="gameMergeModal">Cancel</button>
|
|
340
|
+
<button class="action-btn warning" id="confirmMergeBtn" data-action="confirmGameMerge">
|
|
341
|
+
🔀 Confirm Merge
|
|
342
|
+
</button>
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
</div>
|
|
346
|
+
|
|
275
347
|
<!-- Include shared JavaScript first (required dependency for database.js) -->
|
|
276
348
|
<script src="/static/js/shared.js"></script>
|
|
277
349
|
<script src="/static/js/database.js"></script>
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>GSM - Goals</title>
|
|
8
|
+
<!-- Include Chart.js from a CDN -->
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
10
|
+
|
|
11
|
+
<!-- Include html2canvas for screenshot functionality -->
|
|
12
|
+
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
|
|
13
|
+
|
|
14
|
+
<!-- Include shared theme styles -->
|
|
15
|
+
{% include 'components/theme-styles.html' %}
|
|
16
|
+
|
|
17
|
+
<!-- Include shared CSS -->
|
|
18
|
+
<link rel="stylesheet" href="/static/css/shared.css">
|
|
19
|
+
|
|
20
|
+
<!-- Include shared dashboard and popup CSS -->
|
|
21
|
+
<link rel="stylesheet" href="/static/css/dashboard-shared.css">
|
|
22
|
+
<link rel="stylesheet" href="/static/css/popups-shared.css">
|
|
23
|
+
|
|
24
|
+
<!-- Include stats-specific CSS for goals -->
|
|
25
|
+
<link rel="stylesheet" href="/static/css/stats.css">
|
|
26
|
+
</head>
|
|
27
|
+
|
|
28
|
+
<body>
|
|
29
|
+
|
|
30
|
+
<div class="container">
|
|
31
|
+
<h1>GSM - Goals</h1>
|
|
32
|
+
|
|
33
|
+
<!-- Include shared navigation -->
|
|
34
|
+
{% include 'components/navigation.html' %}
|
|
35
|
+
|
|
36
|
+
<!-- Goal Progress Chart -->
|
|
37
|
+
<div class="dashboard-card goal-progress-chart" id="goalProgressChart" style="margin-bottom: 30px;">
|
|
38
|
+
<div class="dashboard-card-header">
|
|
39
|
+
<h3 class="dashboard-card-title">
|
|
40
|
+
<span class="dashboard-card-icon">🎯</span>
|
|
41
|
+
Goal Progress Chart
|
|
42
|
+
</h3>
|
|
43
|
+
<p class="dashboard-card-subtitle">Track your reading goals and projected completion dates</p>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div class="goal-progress-grid">
|
|
47
|
+
<!-- Reading Hours Goal -->
|
|
48
|
+
<div class="goal-progress-item">
|
|
49
|
+
<div class="goal-progress-header">
|
|
50
|
+
<div class="goal-progress-label">
|
|
51
|
+
<span class="goal-icon">⏱️</span>
|
|
52
|
+
Reading Hours
|
|
53
|
+
</div>
|
|
54
|
+
<div class="goal-progress-values">
|
|
55
|
+
<span class="goal-current" id="goalHoursCurrent">-</span>
|
|
56
|
+
<span class="goal-separator">/</span>
|
|
57
|
+
<span class="goal-target" id="goalHoursTarget">-</span>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="goal-progress-bar">
|
|
61
|
+
<div class="goal-progress-fill" id="goalHoursProgress" data-percentage="0"></div>
|
|
62
|
+
</div>
|
|
63
|
+
<div class="goal-progress-info">
|
|
64
|
+
<span class="goal-percentage" id="goalHoursPercentage">0%</span>
|
|
65
|
+
<span class="goal-projection" id="goalHoursProjection">-</span>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<!-- Character Count Goal -->
|
|
70
|
+
<div class="goal-progress-item">
|
|
71
|
+
<div class="goal-progress-header">
|
|
72
|
+
<div class="goal-progress-label">
|
|
73
|
+
<span class="goal-icon">📖</span>
|
|
74
|
+
Characters Read
|
|
75
|
+
</div>
|
|
76
|
+
<div class="goal-progress-values">
|
|
77
|
+
<span class="goal-current" id="goalCharsCurrent">-</span>
|
|
78
|
+
<span class="goal-separator">/</span>
|
|
79
|
+
<span class="goal-target" id="goalCharsTarget">-</span>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
<div class="goal-progress-bar">
|
|
83
|
+
<div class="goal-progress-fill" id="goalCharsProgress" data-percentage="0"></div>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="goal-progress-info">
|
|
86
|
+
<span class="goal-percentage" id="goalCharsPercentage">0%</span>
|
|
87
|
+
<span class="goal-projection" id="goalCharsProjection">-</span>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<!-- Games Goal -->
|
|
92
|
+
<div class="goal-progress-item">
|
|
93
|
+
<div class="goal-progress-header">
|
|
94
|
+
<div class="goal-progress-label">
|
|
95
|
+
<span class="goal-icon">🎮</span>
|
|
96
|
+
Games
|
|
97
|
+
</div>
|
|
98
|
+
<div class="goal-progress-values">
|
|
99
|
+
<span class="goal-current" id="goalGamesCurrent">-</span>
|
|
100
|
+
<span class="goal-separator">/</span>
|
|
101
|
+
<span class="goal-target" id="goalGamesTarget">-</span>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
<div class="goal-progress-bar">
|
|
105
|
+
<div class="goal-progress-fill" id="goalGamesProgress" data-percentage="0"></div>
|
|
106
|
+
</div>
|
|
107
|
+
<div class="goal-progress-info">
|
|
108
|
+
<span class="goal-percentage" id="goalGamesPercentage">0%</span>
|
|
109
|
+
<span class="goal-projection" id="goalGamesProjection">-</span>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<!-- Loading/Error states -->
|
|
115
|
+
<div class="goal-progress-loading" id="goalProgressLoading" style="display: none;">
|
|
116
|
+
<div class="spinner"></div>
|
|
117
|
+
<span>Loading goal progress...</span>
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<div class="goal-progress-error" id="goalProgressError" style="display: none;">
|
|
121
|
+
<div class="goal-progress-error-icon">⚠️</div>
|
|
122
|
+
<div class="goal-progress-error-message">Failed to load goal progress</div>
|
|
123
|
+
<button class="retry-btn" onclick="loadGoalProgress()">Retry</button>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<!-- Goals Today Card -->
|
|
128
|
+
<div class="dashboard-card today-goals" id="todayGoalsCard" style="margin-bottom: 30px;">
|
|
129
|
+
<div class="dashboard-card-header">
|
|
130
|
+
<h3 class="dashboard-card-title">
|
|
131
|
+
<span class="dashboard-card-icon">📅</span>
|
|
132
|
+
Goals Today
|
|
133
|
+
</h3>
|
|
134
|
+
<p class="dashboard-card-subtitle" id="todayGoalsDate">Loading...</p>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
<div id="noTargetsMessage" class="no-targets-message" style="display: none; text-align: center; padding: 40px 20px; color: var(--text-tertiary); font-style: italic;">
|
|
138
|
+
Set target dates in settings to see your daily goals
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<div class="dashboard-stats-grid" id="todayGoalsStats">
|
|
142
|
+
<div class="dashboard-stat-item goal-stat-item tooltip" data-tooltip="Your progress toward today's hours goal" id="hoursGoalItem" style="display: none;">
|
|
143
|
+
<span class="dashboard-stat-value">
|
|
144
|
+
<span id="todayHoursProgress">-</span>
|
|
145
|
+
<span class="goal-separator">/</span>
|
|
146
|
+
<span id="todayHoursRequired">-</span>
|
|
147
|
+
</span>
|
|
148
|
+
<span class="dashboard-stat-label">Hours Required</span>
|
|
149
|
+
</div>
|
|
150
|
+
<div class="dashboard-stat-item goal-stat-item tooltip" data-tooltip="Your progress toward today's character goal" id="charsGoalItem" style="display: none;">
|
|
151
|
+
<span class="dashboard-stat-value">
|
|
152
|
+
<span id="todayCharsProgress">-</span>
|
|
153
|
+
<span class="goal-separator">/</span>
|
|
154
|
+
<span id="todayCharsRequired">-</span>
|
|
155
|
+
</span>
|
|
156
|
+
<span class="dashboard-stat-label">Characters Required</span>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<div class="dashboard-progress-section" id="todayGoalsProgress" style="display: none;">
|
|
161
|
+
<div class="dashboard-progress-title">Daily Progress</div>
|
|
162
|
+
<div class="dashboard-progress-items">
|
|
163
|
+
<div class="dashboard-progress-item" id="hoursDaysRemaining" style="display: none;">
|
|
164
|
+
<div class="dashboard-progress-value neutral" id="hoursRemainingValue">-</div>
|
|
165
|
+
<div class="dashboard-progress-label">Days Until Hours Goal</div>
|
|
166
|
+
</div>
|
|
167
|
+
<div class="dashboard-progress-item" id="charsDaysRemaining" style="display: none;">
|
|
168
|
+
<div class="dashboard-progress-value neutral" id="charsRemainingValue">-</div>
|
|
169
|
+
<div class="dashboard-progress-label">Days Until Chars Goal</div>
|
|
170
|
+
</div>
|
|
171
|
+
<div class="dashboard-progress-item" id="gamesDaysRemaining" style="display: none;">
|
|
172
|
+
<div class="dashboard-progress-value neutral" id="gamesRemainingValue">-</div>
|
|
173
|
+
<div class="dashboard-progress-label">Days Until Games Goal</div>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
|
|
179
|
+
<!-- Your Stats by Goal Date Card -->
|
|
180
|
+
<div class="dashboard-card projection-card" id="projectionCard" style="margin-bottom: 30px;">
|
|
181
|
+
<div class="dashboard-card-header">
|
|
182
|
+
<h3 class="dashboard-card-title">
|
|
183
|
+
<span class="dashboard-card-icon">📊</span>
|
|
184
|
+
Your Stats by Goal Date
|
|
185
|
+
</h3>
|
|
186
|
+
<p class="dashboard-card-subtitle">Based on your 30-day average reading pace</p>
|
|
187
|
+
</div>
|
|
188
|
+
|
|
189
|
+
<div id="noProjectionsMessage" class="no-targets-message" style="display: none; text-align: center; padding: 40px 20px; color: var(--text-tertiary); font-style: italic;">
|
|
190
|
+
Set target dates in settings to see projections
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
<div class="dashboard-stats-grid" id="projectionStats">
|
|
194
|
+
<div class="dashboard-stat-item tooltip" data-tooltip="Total hours you'll have by your target date" id="hoursProjectionItem" style="display: none;">
|
|
195
|
+
<span class="dashboard-stat-value" id="projectionHoursValue">-</span>
|
|
196
|
+
<span class="dashboard-stat-label">Total Hours by Target</span>
|
|
197
|
+
</div>
|
|
198
|
+
<div class="dashboard-stat-item tooltip" data-tooltip="Total characters you'll have by your target date" id="charsProjectionItem" style="display: none;">
|
|
199
|
+
<span class="dashboard-stat-value" id="projectionCharsValue">-</span>
|
|
200
|
+
<span class="dashboard-stat-label">Total Characters by Target</span>
|
|
201
|
+
</div>
|
|
202
|
+
<div class="dashboard-stat-item tooltip" data-tooltip="Total games you'll have by your target date" id="gamesProjectionItem" style="display: none;">
|
|
203
|
+
<span class="dashboard-stat-value" id="projectionGamesValue">-</span>
|
|
204
|
+
<span class="dashboard-stat-label">Total Games by Target</span>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
|
|
208
|
+
<div class="dashboard-progress-section" id="projectionProgress" style="display: none;">
|
|
209
|
+
<div class="dashboard-progress-title">Projection Summary</div>
|
|
210
|
+
<div class="dashboard-progress-items">
|
|
211
|
+
<div class="dashboard-progress-item" id="hoursProjectionSummary" style="display: none;">
|
|
212
|
+
<div class="dashboard-progress-value positive" id="hoursProjectionStatus">-</div>
|
|
213
|
+
<div class="dashboard-progress-label">Hours Status</div>
|
|
214
|
+
</div>
|
|
215
|
+
<div class="dashboard-progress-item" id="charsProjectionSummary" style="display: none;">
|
|
216
|
+
<div class="dashboard-progress-value positive" id="charsProjectionStatus">-</div>
|
|
217
|
+
<div class="dashboard-progress-label">Characters Status</div>
|
|
218
|
+
</div>
|
|
219
|
+
<div class="dashboard-progress-item" id="gamesProjectionSummary" style="display: none;">
|
|
220
|
+
<div class="dashboard-progress-value positive" id="gamesProjectionStatus">-</div>
|
|
221
|
+
<div class="dashboard-progress-label">Games Status</div>
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
|
|
227
|
+
<!-- Settings Modal -->
|
|
228
|
+
<div id="settingsModal" class="modal">
|
|
229
|
+
<div class="modal-content">
|
|
230
|
+
<div class="modal-header">
|
|
231
|
+
<h3>Goals Settings</h3>
|
|
232
|
+
<span class="close-btn" id="closeSettingsModal">×</span>
|
|
233
|
+
</div>
|
|
234
|
+
<div class="modal-body">
|
|
235
|
+
<p style="color: var(--text-secondary); margin-bottom: 20px;">
|
|
236
|
+
Configure your reading goals and target dates.
|
|
237
|
+
</p>
|
|
238
|
+
<form id="settingsForm">
|
|
239
|
+
<!-- Reading Goals Section -->
|
|
240
|
+
<div style="margin-bottom: 20px;">
|
|
241
|
+
<label
|
|
242
|
+
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
243
|
+
Reading Goals Configuration
|
|
244
|
+
</label>
|
|
245
|
+
<p style="color: var(--text-secondary); margin-bottom: 20px; font-size: 14px;">
|
|
246
|
+
Set your long-term reading targets and deadlines for tracking progress.
|
|
247
|
+
</p>
|
|
248
|
+
|
|
249
|
+
<div style="margin-bottom: 15px;">
|
|
250
|
+
<label for="readingHoursTarget"
|
|
251
|
+
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
252
|
+
Reading Hours Target
|
|
253
|
+
</label>
|
|
254
|
+
<input type="number" id="readingHoursTarget" name="reading_hours_target" min="1"
|
|
255
|
+
max="10000"
|
|
256
|
+
style="width: 90%; padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;"
|
|
257
|
+
placeholder="1500">
|
|
258
|
+
<small
|
|
259
|
+
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
260
|
+
Total reading hours goal (1-10,000 hours) - Default: 1500 hours
|
|
261
|
+
</small>
|
|
262
|
+
</div>
|
|
263
|
+
|
|
264
|
+
<div style="margin-bottom: 15px;">
|
|
265
|
+
<label for="readingHoursTargetDate"
|
|
266
|
+
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
267
|
+
Reading Hours Target Date
|
|
268
|
+
</label>
|
|
269
|
+
<input type="date" id="readingHoursTargetDate" name="reading_hours_target_date"
|
|
270
|
+
style="width: 90%; padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;">
|
|
271
|
+
<small
|
|
272
|
+
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
273
|
+
Target date to achieve your reading hours goal
|
|
274
|
+
</small>
|
|
275
|
+
</div>
|
|
276
|
+
|
|
277
|
+
<div style="margin-bottom: 15px;">
|
|
278
|
+
<label for="characterCountTarget"
|
|
279
|
+
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
280
|
+
Character Count Target
|
|
281
|
+
</label>
|
|
282
|
+
<input type="number" id="characterCountTarget" name="character_count_target" min="1000"
|
|
283
|
+
max="1000000000"
|
|
284
|
+
style="width: 90%; padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;"
|
|
285
|
+
placeholder="25000000">
|
|
286
|
+
<small
|
|
287
|
+
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
288
|
+
Total characters read goal (1,000-1,000,000,000) - Default: 25 million
|
|
289
|
+
</small>
|
|
290
|
+
</div>
|
|
291
|
+
|
|
292
|
+
<div style="margin-bottom: 15px;">
|
|
293
|
+
<label for="characterCountTargetDate"
|
|
294
|
+
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
295
|
+
Character Count Target Date
|
|
296
|
+
</label>
|
|
297
|
+
<input type="date" id="characterCountTargetDate" name="character_count_target_date"
|
|
298
|
+
style="width: 90%; padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;">
|
|
299
|
+
<small
|
|
300
|
+
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
301
|
+
Target date to achieve your character count goal
|
|
302
|
+
</small>
|
|
303
|
+
</div>
|
|
304
|
+
|
|
305
|
+
<div style="margin-bottom: 15px;">
|
|
306
|
+
<label for="gamesTarget"
|
|
307
|
+
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
308
|
+
Games/Visual Novels Target
|
|
309
|
+
</label>
|
|
310
|
+
<input type="number" id="gamesTarget" name="games_target" min="1" max="1000"
|
|
311
|
+
style="width: 90%; padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;"
|
|
312
|
+
placeholder="100">
|
|
313
|
+
<small
|
|
314
|
+
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
315
|
+
Number of games/visual novels to complete (1-1,000) - Default: 100
|
|
316
|
+
</small>
|
|
317
|
+
</div>
|
|
318
|
+
|
|
319
|
+
<div style="margin-bottom: 15px;">
|
|
320
|
+
<label for="gamesTargetDate"
|
|
321
|
+
style="display: block; font-weight: 600; margin-bottom: 8px; color: var(--text-primary);">
|
|
322
|
+
Games/Visual Novels Target Date
|
|
323
|
+
</label>
|
|
324
|
+
<input type="date" id="gamesTargetDate" name="games_target_date"
|
|
325
|
+
style="width: 90%; padding: 10px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-tertiary); color: var(--text-primary); font-size: 14px;"
|
|
326
|
+
data-date-format="yyyy-mm-dd">
|
|
327
|
+
<small
|
|
328
|
+
style="color: var(--text-tertiary); font-size: 12px; margin-top: 4px; display: block;">
|
|
329
|
+
Target date to achieve your games goal (Format: YYYY-MM-DD)
|
|
330
|
+
</small>
|
|
331
|
+
</div>
|
|
332
|
+
</div>
|
|
333
|
+
</form>
|
|
334
|
+
|
|
335
|
+
<div id="settingsError"
|
|
336
|
+
style="display: none; background: var(--danger-color); color: white; padding: 10px; border-radius: 5px; margin-bottom: 15px; font-size: 14px;">
|
|
337
|
+
</div>
|
|
338
|
+
<div id="settingsSuccess"
|
|
339
|
+
style="display: none; background: var(--success-color); color: white; padding: 10px; border-radius: 5px; margin-bottom: 15px; font-size: 14px;">
|
|
340
|
+
</div>
|
|
341
|
+
</div>
|
|
342
|
+
<div class="modal-footer">
|
|
343
|
+
<button id="cancelSettingsBtn" class="cancel-btn">Cancel</button>
|
|
344
|
+
<button id="saveSettingsBtn" class="confirm-delete-btn">Save Settings</button>
|
|
345
|
+
</div>
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
348
|
+
</div>
|
|
349
|
+
|
|
350
|
+
{% set hours_target = stats_config.reading_hours_target | default(1500) %}
|
|
351
|
+
{% set chars_target = stats_config.character_count_target | default(25000000) %}
|
|
352
|
+
{% set games_target = stats_config.games_target | default(100) %}
|
|
353
|
+
{% set hours_target_date = stats_config.reading_hours_target_date | default('') %}
|
|
354
|
+
{% set chars_target_date = stats_config.character_count_target_date | default('') %}
|
|
355
|
+
{% set games_target_date = stats_config.games_target_date | default('') %}
|
|
356
|
+
|
|
357
|
+
{% set stats_config = {
|
|
358
|
+
'readingHoursTarget': hours_target,
|
|
359
|
+
'characterCountTarget': chars_target,
|
|
360
|
+
'gamesTarget': games_target,
|
|
361
|
+
'readingHoursTargetDate': hours_target_date,
|
|
362
|
+
'characterCountTargetDate': chars_target_date,
|
|
363
|
+
'gamesTargetDate': games_target_date
|
|
364
|
+
} %}
|
|
365
|
+
|
|
366
|
+
<!-- Inject stats config values for frontend -->
|
|
367
|
+
<script>
|
|
368
|
+
window.statsConfig = {{ stats_config | tojson }};
|
|
369
|
+
</script>
|
|
370
|
+
<!-- Include shared JavaScript first (required dependency for goals.js) -->
|
|
371
|
+
<script src="/static/js/shared.js"></script>
|
|
372
|
+
<script src="/static/js/goals.js"></script>
|
|
373
|
+
|
|
374
|
+
</body>
|
|
375
|
+
|
|
376
|
+
</html>
|