GameSentenceMiner 2.17.7__py3-none-any.whl → 2.18.1__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.

Potentially problematic release.


This version of GameSentenceMiner might be problematic. Click here for more details.

Files changed (76) hide show
  1. GameSentenceMiner/ai/ai_prompting.py +6 -6
  2. GameSentenceMiner/anki.py +236 -152
  3. GameSentenceMiner/gametext.py +7 -4
  4. GameSentenceMiner/gsm.py +49 -10
  5. GameSentenceMiner/locales/en_us.json +7 -3
  6. GameSentenceMiner/locales/ja_jp.json +8 -4
  7. GameSentenceMiner/locales/zh_cn.json +8 -4
  8. GameSentenceMiner/obs.py +238 -59
  9. GameSentenceMiner/ocr/owocr_helper.py +1 -1
  10. GameSentenceMiner/tools/ss_selector.py +7 -8
  11. GameSentenceMiner/ui/__init__.py +0 -0
  12. GameSentenceMiner/ui/anki_confirmation.py +187 -0
  13. GameSentenceMiner/{config_gui.py → ui/config_gui.py} +100 -35
  14. GameSentenceMiner/ui/screenshot_selector.py +215 -0
  15. GameSentenceMiner/util/configuration.py +124 -22
  16. GameSentenceMiner/util/db.py +22 -13
  17. GameSentenceMiner/util/downloader/download_tools.py +2 -2
  18. GameSentenceMiner/util/ffmpeg.py +24 -30
  19. GameSentenceMiner/util/get_overlay_coords.py +34 -34
  20. GameSentenceMiner/util/gsm_utils.py +31 -1
  21. GameSentenceMiner/util/text_log.py +11 -9
  22. GameSentenceMiner/vad.py +31 -12
  23. GameSentenceMiner/web/database_api.py +742 -123
  24. GameSentenceMiner/web/static/css/dashboard-shared.css +241 -0
  25. GameSentenceMiner/web/static/css/kanji-grid.css +94 -2
  26. GameSentenceMiner/web/static/css/overview.css +850 -0
  27. GameSentenceMiner/web/static/css/popups-shared.css +126 -0
  28. GameSentenceMiner/web/static/css/shared.css +97 -0
  29. GameSentenceMiner/web/static/css/stats.css +192 -597
  30. GameSentenceMiner/web/static/js/anki_stats.js +6 -4
  31. GameSentenceMiner/web/static/js/database.js +209 -5
  32. GameSentenceMiner/web/static/js/goals.js +610 -0
  33. GameSentenceMiner/web/static/js/kanji-grid.js +267 -4
  34. GameSentenceMiner/web/static/js/overview.js +1176 -0
  35. GameSentenceMiner/web/static/js/shared.js +25 -0
  36. GameSentenceMiner/web/static/js/stats.js +154 -1459
  37. GameSentenceMiner/web/stats.py +2 -2
  38. GameSentenceMiner/web/templates/anki_stats.html +5 -0
  39. GameSentenceMiner/web/templates/components/kanji_grid/basic_kanji_book_bkb_v1_v2.json +17 -0
  40. GameSentenceMiner/web/templates/components/kanji_grid/duolingo_kanji.json +29 -0
  41. GameSentenceMiner/web/templates/components/kanji_grid/grade.json +17 -0
  42. GameSentenceMiner/web/templates/components/kanji_grid/hk_primary_learning.json +17 -0
  43. GameSentenceMiner/web/templates/components/kanji_grid/hkscs2016.json +13 -0
  44. GameSentenceMiner/web/templates/components/kanji_grid/hsk_levels.json +33 -0
  45. GameSentenceMiner/web/templates/components/kanji_grid/humanum_frequency_list.json +41 -0
  46. GameSentenceMiner/web/templates/components/kanji_grid/jis_levels.json +25 -0
  47. GameSentenceMiner/web/templates/components/kanji_grid/jlpt_level.json +29 -0
  48. GameSentenceMiner/web/templates/components/kanji_grid/jpdb_kanji_frequency_list.json +37 -0
  49. GameSentenceMiner/web/templates/components/kanji_grid/jpdbv2_kanji_frequency_list.json +161 -0
  50. GameSentenceMiner/web/templates/components/kanji_grid/jun_das_modern_chinese_character_frequency_list.json +13 -0
  51. GameSentenceMiner/web/templates/components/kanji_grid/kanji_in_context_revised_edition.json +37 -0
  52. GameSentenceMiner/web/templates/components/kanji_grid/kanji_kentei_level.json +61 -0
  53. GameSentenceMiner/web/templates/components/kanji_grid/mainland_china_elementary_textbook_characters.json +33 -0
  54. GameSentenceMiner/web/templates/components/kanji_grid/moe_way_quiz.json +47 -0
  55. GameSentenceMiner/web/templates/components/kanji_grid/official_kanji.json +25 -0
  56. GameSentenceMiner/web/templates/components/kanji_grid/remembering_the_kanji.json +25 -0
  57. GameSentenceMiner/web/templates/components/kanji_grid/standard_form_of_national_characters.json +25 -0
  58. GameSentenceMiner/web/templates/components/kanji_grid/table_of_general_standard_chinese_characters.json +21 -0
  59. GameSentenceMiner/web/templates/components/kanji_grid/the_kodansha_kanji_learners_course_klc.json +45 -0
  60. GameSentenceMiner/web/templates/components/kanji_grid/thousand_character_classic.json +13 -0
  61. GameSentenceMiner/web/templates/components/kanji_grid/wanikani_levels.json +249 -0
  62. GameSentenceMiner/web/templates/components/kanji_grid/words_hk_frequency_list.json +33 -0
  63. GameSentenceMiner/web/templates/components/navigation.html +3 -1
  64. GameSentenceMiner/web/templates/database.html +73 -1
  65. GameSentenceMiner/web/templates/goals.html +376 -0
  66. GameSentenceMiner/web/templates/index.html +13 -11
  67. GameSentenceMiner/web/templates/overview.html +416 -0
  68. GameSentenceMiner/web/templates/stats.html +46 -251
  69. GameSentenceMiner/web/texthooking_page.py +18 -0
  70. {gamesentenceminer-2.17.7.dist-info → gamesentenceminer-2.18.1.dist-info}/METADATA +5 -1
  71. gamesentenceminer-2.18.1.dist-info/RECORD +132 -0
  72. gamesentenceminer-2.17.7.dist-info/RECORD +0 -98
  73. {gamesentenceminer-2.17.7.dist-info → gamesentenceminer-2.18.1.dist-info}/WHEEL +0 -0
  74. {gamesentenceminer-2.17.7.dist-info → gamesentenceminer-2.18.1.dist-info}/entry_points.txt +0 -0
  75. {gamesentenceminer-2.17.7.dist-info → gamesentenceminer-2.18.1.dist-info}/licenses/LICENSE +0 -0
  76. {gamesentenceminer-2.17.7.dist-info → gamesentenceminer-2.18.1.dist-info}/top_level.txt +0 -0
@@ -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">&times;</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>