domma-cms 0.55.1 → 0.69.3
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.
- package/CLAUDE.md +194 -3
- package/README.md +18 -14
- package/admin/css/admin.css +1 -1
- package/admin/css/contacts.css +1 -0
- package/admin/dist/domma/domma-tools.css +3 -3
- package/admin/dist/domma/domma-tools.min.js +3 -3
- package/admin/index.html +1 -0
- package/admin/js/api.js +1 -1
- package/admin/js/app.js +4 -4
- package/admin/js/lib/analytics-shape.js +1 -0
- package/admin/js/lib/contacts-arrange.js +1 -0
- package/admin/js/lib/help-popover.js +1 -0
- package/admin/js/lib/notes-arrange.js +1 -0
- package/admin/js/lib/page-picker.js +1 -0
- package/admin/js/lib/plugin-accent.js +1 -0
- package/admin/js/lib/plugin-chrome.js +1 -0
- package/admin/js/lib/shortcode-context-menu.js +2 -2
- package/admin/js/lib/sidebar-grouping.js +1 -1
- package/admin/js/lib/sidebar-grouping.test.js +1 -1
- package/admin/js/lib/sidebar-renderer.js +4 -4
- package/admin/js/lib/slideover-resizable.js +1 -0
- package/admin/js/lib/todo-arrange.js +1 -0
- package/admin/js/lib/tool-kit.js +1 -0
- package/admin/js/templates/analytics.html +138 -0
- package/admin/js/templates/contacts.html +156 -0
- package/admin/js/templates/context-menu-editor.html +212 -0
- package/admin/js/templates/context-menus.html +16 -0
- package/admin/js/templates/notes.html +137 -0
- package/admin/js/templates/plugin-code.html +1 -1
- package/admin/js/templates/plugin-marketplace.html +17 -4
- package/admin/js/templates/plugins.html +13 -7
- package/{plugins/site-search/admin/templates/site-search.html → admin/js/templates/search.html} +50 -4
- package/admin/js/templates/settings.html +16 -97
- package/admin/js/templates/theme.html +211 -0
- package/admin/js/templates/todo.html +113 -0
- package/admin/js/views/analytics.js +62 -0
- package/admin/js/views/contacts.js +174 -0
- package/admin/js/views/context-menu-editor.js +55 -0
- package/admin/js/views/context-menus.js +5 -0
- package/admin/js/views/form-editor.js +7 -7
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/notes.js +104 -0
- package/admin/js/views/plugin-marketplace.js +1 -1
- package/admin/js/views/plugins.js +28 -24
- package/admin/js/views/search.js +1 -0
- package/admin/js/views/settings.js +3 -3
- package/admin/js/views/theme.js +1 -0
- package/admin/js/views/todo.js +96 -0
- package/bin/cli.js +6 -10
- package/bin/lib/plugin-version.js +28 -0
- package/bin/update.js +27 -2
- package/config/menus/admin-sidebar.json +129 -23
- package/config/plugins.json +5 -5
- package/config/search.json +13 -0
- package/config/server.json +3 -1
- package/package.json +14 -10
- package/plugins/_lib/admin/mail/compose-window.js +914 -0
- package/plugins/_lib/admin/mail/contacts.js +301 -0
- package/plugins/_lib/admin/mail/diagnostics-section.js +133 -0
- package/plugins/_lib/admin/mail/folder-tree.js +254 -0
- package/plugins/_lib/admin/mail/identity.js +480 -0
- package/plugins/_lib/admin/mail/image-senders-section.js +131 -0
- package/plugins/_lib/admin/mail/keyboard.js +136 -0
- package/plugins/_lib/admin/mail/mail.css +1 -0
- package/plugins/_lib/admin/mail/mail.html +71 -0
- package/plugins/_lib/admin/mail/panes.js +253 -0
- package/plugins/_lib/admin/mail/reader-view.js +4473 -0
- package/plugins/_lib/admin/mail/resizable.js +26 -0
- package/plugins/_lib/admin/mail/rules.js +343 -0
- package/plugins/_lib/admin/mail/scheduling.js +203 -0
- package/plugins/_lib/admin/mail/section-kit.js +277 -0
- package/plugins/_lib/admin/mail/templates.js +238 -0
- package/plugins/_lib/admin/mail/threads.js +200 -0
- package/plugins/_lib/admin/mail/vacation.js +269 -0
- package/plugins/_lib/admin/ui/help.css +1 -0
- package/plugins/_lib/admin/ui/help.js +174 -0
- package/plugins/_lib/admin/ui/resizable.js +151 -0
- package/plugins/_lib/dataStore.js +117 -0
- package/plugins/_lib/mail/accounts.js +919 -0
- package/plugins/_lib/mail/bodyTokens.js +101 -0
- package/plugins/_lib/mail/compose.js +256 -0
- package/plugins/_lib/mail/defaults.js +57 -0
- package/plugins/_lib/mail/diagnostics.js +154 -0
- package/plugins/_lib/mail/envelope.js +161 -0
- package/plugins/_lib/mail/folders.js +192 -0
- package/plugins/_lib/mail/handoff.js +274 -0
- package/plugins/_lib/mail/imapPool.js +293 -0
- package/plugins/_lib/mail/mbox.js +74 -0
- package/plugins/_lib/mail/pollSchedule.js +79 -0
- package/plugins/_lib/mail/poller.js +135 -0
- package/plugins/_lib/mail/priority.js +138 -0
- package/plugins/_lib/mail/readRoutes.js +680 -0
- package/plugins/_lib/mail/render.js +291 -0
- package/plugins/_lib/mail/ruleRunner.js +152 -0
- package/plugins/_lib/mail/scheduler.js +254 -0
- package/plugins/_lib/mail/secretbox.js +229 -0
- package/plugins/_lib/mail/send.js +396 -0
- package/plugins/_lib/mail/store.js +1022 -0
- package/plugins/_lib/mail/sync.js +292 -0
- package/plugins/_lib/mail/syncPlan.js +126 -0
- package/plugins/_lib/mail/syncSelection.js +82 -0
- package/plugins/_lib/mail/unsubscribe.js +183 -0
- package/plugins/_lib/mail/vacationRunner.js +114 -0
- package/plugins/_lib/mail/write.js +473 -0
- package/plugins/_lib/schemaSync.js +83 -0
- package/plugins/_template/admin/css/index.css +0 -0
- package/plugins/_template/admin/templates/index.html +4 -4
- package/plugins/_template/admin/views/index.js +7 -0
- package/plugins/blog/CLAUDE.md +237 -0
- package/plugins/blog/admin/css/index.css +178 -0
- package/plugins/blog/admin/templates/blog.html +35 -41
- package/plugins/blog/admin/templates/categories.html +19 -6
- package/plugins/blog/admin/templates/comments.html +26 -9
- package/plugins/blog/admin/templates/post-editor.html +63 -40
- package/plugins/blog/admin/templates/settings.html +3 -9
- package/plugins/blog/admin/views/blog.js +288 -159
- package/plugins/blog/admin/views/categories.js +212 -206
- package/plugins/blog/admin/views/comments.js +207 -158
- package/plugins/blog/admin/views/kit.js +372 -0
- package/plugins/blog/admin/views/post-editor.js +306 -39
- package/plugins/blog/admin/views/settings-cog.js +56 -0
- package/plugins/blog/admin/views/settings.js +16 -84
- package/plugins/blog/blocks/blog-card-compact.css +17 -0
- package/plugins/blog/blocks/blog-card-compact.html +8 -0
- package/plugins/blog/blocks/blog-card-row.css +22 -0
- package/plugins/blog/blocks/blog-card-row.html +11 -0
- package/plugins/blog/blocks/blog-card.css +35 -0
- package/plugins/blog/blocks/blog-card.html +16 -0
- package/plugins/blog/blocks/blog-post-classic.css +15 -0
- package/plugins/blog/blocks/blog-post-classic.html +28 -0
- package/plugins/blog/blocks/blog-post-feature.css +20 -0
- package/plugins/blog/blocks/blog-post-feature.html +30 -0
- package/plugins/blog/blocks/blog-post-minimal.css +10 -0
- package/plugins/blog/blocks/blog-post-minimal.html +23 -0
- package/plugins/blog/blocks/blog-post-sidebar.css +22 -0
- package/plugins/blog/blocks/blog-post-sidebar.html +36 -0
- package/plugins/blog/collections/categories/schema.json +7 -6
- package/plugins/blog/collections/comments/schema.json +11 -10
- package/plugins/blog/collections/posts/schema.json +16 -13
- package/plugins/blog/config.js +6 -0
- package/plugins/blog/lib/layouts.js +304 -0
- package/plugins/blog/lib/page.js +158 -0
- package/plugins/blog/lib/render.js +119 -0
- package/plugins/blog/lib/samples.js +234 -0
- package/plugins/blog/plugin.js +259 -26
- package/plugins/blog/plugin.json +21 -73
- package/plugins/blog/plugin.public.js +217 -0
- package/plugins/blog/public/blog.css +177 -0
- package/plugins/blog/public/blog.js +586 -0
- package/plugins/blog/public/samples/aurora.svg +7 -0
- package/plugins/blog/public/samples/dusk.svg +7 -0
- package/plugins/blog/public/samples/ember.svg +7 -0
- package/plugins/blog/public/samples/harbour.svg +7 -0
- package/plugins/blog/public/samples/meadow.svg +7 -0
- package/plugins/blog/public/samples/rosewood.svg +7 -0
- package/plugins/blog/templates/index.html +9 -8
- package/plugins/blog/templates/post.html +4 -17
- package/plugins/blog/tests/layouts.test.js +97 -0
- package/plugins/blog/tests/public.test.js +71 -0
- package/plugins/free-tier.lock.json +74 -0
- package/plugins/mail-reader/CLAUDE.md +78 -0
- package/plugins/mail-reader/admin/views/mail.js +19 -0
- package/plugins/mail-reader/config.js +7 -0
- package/plugins/mail-reader/plugin.js +48 -0
- package/plugins/mail-reader/plugin.json +34 -0
- package/public/css/forms.css +1 -1
- package/public/css/search.css +1 -0
- package/public/css/site.css +1 -1
- package/public/css/theme-switcher.css +1 -0
- package/public/js/analytics.js +1 -0
- package/public/js/collection-context.js +2 -2
- package/public/js/context-menus.js +1 -0
- package/public/js/form-logic-engine.js +1 -1
- package/public/js/forms.js +2 -2
- package/public/js/search.js +1 -0
- package/public/js/site.js +1 -1
- package/public/js/theme-switcher.js +1 -0
- package/scripts/build.js +77 -4
- package/scripts/copy-domma.js +48 -0
- package/scripts/run-tests.mjs +92 -0
- package/scripts/seed.js +1996 -0
- package/{plugins/analytics/plugin.js → server/routes/api/analytics.js} +89 -41
- package/server/routes/api/collections.js +34 -0
- package/server/routes/api/contacts.js +506 -0
- package/server/routes/api/context-menus.js +104 -0
- package/server/routes/api/dashboard.js +8 -2
- package/server/routes/api/forms.js +42 -3
- package/{plugins/notes/plugin.js → server/routes/api/notes.js} +61 -17
- package/server/routes/api/notifications.js +69 -19
- package/server/routes/api/plugin-marketplace.js +78 -23
- package/server/routes/api/plugins.js +198 -9
- package/server/routes/api/search.js +43 -0
- package/server/routes/api/theme.js +69 -0
- package/server/routes/api/todo.js +178 -0
- package/server/routes/public.js +42 -7
- package/server/server.js +135 -1
- package/server/services/adapters/FileAdapter.js +6 -1
- package/server/services/collections.js +13 -3
- package/server/services/content.js +26 -0
- package/server/services/contextMenus.js +477 -0
- package/server/services/managerClient.js +72 -136
- package/server/services/markdown.js +124 -10
- package/server/services/permissionRegistry.js +74 -0
- package/server/services/pluginEntitlement.js +171 -0
- package/server/services/pluginEnvelope.js +242 -0
- package/server/services/pluginFiles.js +52 -11
- package/server/services/pluginInstaller.js +246 -26
- package/server/services/pluginScaffold.js +5 -0
- package/server/services/plugins.js +340 -7
- package/server/services/presetCollections.js +344 -0
- package/server/services/promoted-plugins-migration.js +254 -0
- package/server/services/publicCors.js +46 -0
- package/server/services/renderer.js +224 -22
- package/server/services/roles.js +1 -1
- package/server/services/search-migration.js +82 -0
- package/server/services/search.js +413 -0
- package/server/services/sidebar-migration.js +1 -0
- package/server/services/sidebarBadges.js +37 -0
- package/server/services/siteGitignore.js +307 -0
- package/server/services/themeSettings.js +580 -0
- package/server/services/users.js +8 -0
- package/server/templates/page.html +4 -2
- package/plugins/analytics/admin/templates/analytics.html +0 -61
- package/plugins/analytics/admin/views/analytics.js +0 -176
- package/plugins/analytics/config.js +0 -14
- package/plugins/analytics/plugin.json +0 -57
- package/plugins/analytics/public/inject-body.html +0 -60
- package/plugins/analytics/public/inject-head.html +0 -1
- package/plugins/blog/templates/author.html +0 -9
- package/plugins/blog/templates/category.html +0 -9
- package/plugins/blog/templates/tag.html +0 -9
- package/plugins/contacts/admin/templates/contacts.html +0 -126
- package/plugins/contacts/admin/views/contacts.js +0 -710
- package/plugins/contacts/collections/user-contact-groups/schema.json +0 -35
- package/plugins/contacts/collections/user-contacts/schema.json +0 -71
- package/plugins/contacts/config.js +0 -6
- package/plugins/contacts/data/contacts.json +0 -20
- package/plugins/contacts/plugin.js +0 -291
- package/plugins/contacts/plugin.json +0 -33
- package/plugins/demo-viewer/config.js +0 -4
- package/plugins/demo-viewer/plugin.js +0 -36
- package/plugins/demo-viewer/plugin.json +0 -9
- package/plugins/invoice/admin/templates/editor.html +0 -129
- package/plugins/invoice/admin/templates/index.html +0 -43
- package/plugins/invoice/admin/templates/issuers.html +0 -5
- package/plugins/invoice/admin/templates/receivers.html +0 -5
- package/plugins/invoice/admin/views/editor.js +0 -267
- package/plugins/invoice/admin/views/index.js +0 -155
- package/plugins/invoice/admin/views/issuers.js +0 -23
- package/plugins/invoice/admin/views/party-view.js +0 -148
- package/plugins/invoice/admin/views/receivers.js +0 -22
- package/plugins/invoice/collections/invoice-issuers/schema.json +0 -16
- package/plugins/invoice/collections/invoice-receivers/schema.json +0 -15
- package/plugins/invoice/collections/invoices/schema.json +0 -27
- package/plugins/invoice/config.js +0 -16
- package/plugins/invoice/plugin.js +0 -283
- package/plugins/invoice/plugin.json +0 -85
- package/plugins/invoice/templates/invoice-print.html +0 -213
- package/plugins/notes/admin/templates/notes.html +0 -83
- package/plugins/notes/admin/views/notes.js +0 -281
- package/plugins/notes/collections/user-notes/schema.json +0 -54
- package/plugins/notes/config.js +0 -6
- package/plugins/notes/data/notes.json +0 -1
- package/plugins/notes/plugin.json +0 -33
- package/plugins/site-search/admin/views/site-search.js +0 -116
- package/plugins/site-search/config.js +0 -15
- package/plugins/site-search/plugin.js +0 -188
- package/plugins/site-search/plugin.json +0 -40
- package/plugins/site-search/public/inject-body.html +0 -17
- package/plugins/site-search/public/inject-head.html +0 -1
- package/plugins/site-search/public/search.css +0 -1
- package/plugins/site-search/public/search.js +0 -1
- package/plugins/surveys/admin/templates/audience.html +0 -47
- package/plugins/surveys/admin/templates/results.html +0 -58
- package/plugins/surveys/admin/templates/survey-editor.html +0 -141
- package/plugins/surveys/admin/templates/surveys.html +0 -25
- package/plugins/surveys/admin/views/audience.js +0 -301
- package/plugins/surveys/admin/views/results.js +0 -172
- package/plugins/surveys/admin/views/survey-editor.js +0 -211
- package/plugins/surveys/admin/views/surveys.js +0 -161
- package/plugins/surveys/collections/survey-contacts/schema.json +0 -13
- package/plugins/surveys/collections/survey-groups/schema.json +0 -11
- package/plugins/surveys/collections/survey-invites/schema.json +0 -16
- package/plugins/surveys/collections/surveys/schema.json +0 -23
- package/plugins/surveys/config.js +0 -8
- package/plugins/surveys/plugin.js +0 -174
- package/plugins/surveys/plugin.json +0 -65
- package/plugins/surveys/public/dist-shared.mjs +0 -1
- package/plugins/surveys/public/survey.css +0 -1
- package/plugins/surveys/public/survey.mjs +0 -1
- package/plugins/surveys/templates/survey-page.html +0 -63
- package/plugins/theme-switcher/admin/templates/theme-switcher.html +0 -86
- package/plugins/theme-switcher/admin/views/theme-switcher.js +0 -65
- package/plugins/theme-switcher/config.js +0 -10
- package/plugins/theme-switcher/plugin.js +0 -26
- package/plugins/theme-switcher/plugin.json +0 -74
- package/plugins/theme-switcher/public/inject-body.html +0 -153
- package/plugins/theme-switcher/public/inject-head.html +0 -260
- package/plugins/todo/admin/templates/todo.html +0 -158
- package/plugins/todo/admin/views/todo.js +0 -343
- package/plugins/todo/collections/todos/schema.json +0 -60
- package/plugins/todo/config.js +0 -7
- package/plugins/todo/data/todos.json +0 -1
- package/plugins/todo/plugin.js +0 -102
- package/plugins/todo/plugin.json +0 -33
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
<div class="page-header">
|
|
2
|
+
<h1 id="theme-title"><span data-icon="droplet"></span> Theme</h1>
|
|
3
|
+
<div style="display:flex;gap:.5rem;align-items:center;">
|
|
4
|
+
<a href="/" target="_blank" rel="noopener" class="btn btn-ghost btn-sm">
|
|
5
|
+
<span data-icon="external-link"></span> View site
|
|
6
|
+
</a>
|
|
7
|
+
<button id="theme-save-btn" class="btn btn-primary"><span data-icon="save"></span> Save</button>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<div id="theme-errors" class="alert alert-danger mb-3" style="display:none;"></div>
|
|
12
|
+
|
|
13
|
+
<div class="tabs" id="theme-tabs">
|
|
14
|
+
<div class="tab-list">
|
|
15
|
+
<button class="tab-item active">Themes</button>
|
|
16
|
+
<button class="tab-item">Element Overrides</button>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<!-- ------------------------------------------------------------------ -->
|
|
20
|
+
<!-- Themes -->
|
|
21
|
+
<!-- ------------------------------------------------------------------ -->
|
|
22
|
+
<div class="tab-panel active">
|
|
23
|
+
<div class="card mb-4">
|
|
24
|
+
<div class="card-header"><h2>Site & Admin</h2></div>
|
|
25
|
+
<div class="card-body">
|
|
26
|
+
<div class="row mb-3">
|
|
27
|
+
<div class="col-6">
|
|
28
|
+
<label class="form-label">Front-end Theme</label>
|
|
29
|
+
<select id="theme-frontend" class="form-select"></select>
|
|
30
|
+
<p class="form-hint text-muted" style="margin-top:.4rem;font-size:.8rem;">
|
|
31
|
+
Applied to every public page.</p>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="col-6">
|
|
34
|
+
<label class="form-label">Admin Theme</label>
|
|
35
|
+
<select id="theme-admin" class="form-select"></select>
|
|
36
|
+
<p class="form-hint text-muted" style="margin-top:.4rem;font-size:.8rem;">
|
|
37
|
+
Applied to this admin panel. Takes effect as soon as you save.</p>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="row">
|
|
42
|
+
<div class="col">
|
|
43
|
+
<label class="form-check-label" style="display:flex;align-items:center;gap:.5rem;cursor:pointer;">
|
|
44
|
+
<input id="theme-auto-enabled" type="checkbox" class="form-check">
|
|
45
|
+
Switch automatically between a day and a night theme
|
|
46
|
+
</label>
|
|
47
|
+
<p id="theme-auto-roller-hint" class="form-hint text-muted"
|
|
48
|
+
style="display:none;margin-top:.35rem;font-size:.8rem;">
|
|
49
|
+
Custom themes (Theme Roller) do not support auto-switching.</p>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
<div id="theme-auto-fields" class="row mt-3" style="display:none;">
|
|
53
|
+
<div class="col-6">
|
|
54
|
+
<label class="form-label">Day Theme</label>
|
|
55
|
+
<select id="theme-day" class="form-select"></select>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="col-6">
|
|
58
|
+
<label class="form-label">Night Theme</label>
|
|
59
|
+
<select id="theme-night" class="form-select"></select>
|
|
60
|
+
</div>
|
|
61
|
+
<div class="col-3 mt-3">
|
|
62
|
+
<label class="form-label">Day Starts At</label>
|
|
63
|
+
<input id="theme-day-start" type="time" class="form-input" value="07:00">
|
|
64
|
+
</div>
|
|
65
|
+
<div class="col-3 mt-3">
|
|
66
|
+
<label class="form-label">Night Starts At</label>
|
|
67
|
+
<input id="theme-night-start" type="time" class="form-input" value="19:00">
|
|
68
|
+
</div>
|
|
69
|
+
<div class="col-12 mt-2">
|
|
70
|
+
<p class="form-hint text-muted" style="font-size:.8rem;">Themes switch on each visitor's local
|
|
71
|
+
time. They need not be a light/dark pair.</p>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<div class="card mb-4">
|
|
78
|
+
<div class="card-header"><h2>Theme Switcher</h2></div>
|
|
79
|
+
<div class="card-body">
|
|
80
|
+
<div class="row">
|
|
81
|
+
<div class="col-12">
|
|
82
|
+
<label class="form-check-label">
|
|
83
|
+
<input id="theme-switcher-enabled" type="checkbox" class="form-check">
|
|
84
|
+
Show a theme switcher on the public site
|
|
85
|
+
</label>
|
|
86
|
+
<p class="form-hint text-muted" style="margin-top:.35rem;font-size:.8rem;">
|
|
87
|
+
A floating disc of theme dots that lets a visitor pick their own theme.
|
|
88
|
+
It offers every theme the stylesheet ships.</p>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
<div id="theme-switcher-fields" class="row mt-3" style="display:none;">
|
|
92
|
+
<div class="col-4">
|
|
93
|
+
<label class="form-label">Position</label>
|
|
94
|
+
<select id="theme-switcher-position" class="form-select">
|
|
95
|
+
<option value="right-center">Right, centred</option>
|
|
96
|
+
<option value="left-center">Left, centred</option>
|
|
97
|
+
<option value="bottom-right">Bottom right</option>
|
|
98
|
+
<option value="bottom-left">Bottom left</option>
|
|
99
|
+
<option value="top-right">Top right</option>
|
|
100
|
+
<option value="top-left">Top left</option>
|
|
101
|
+
</select>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="col-4">
|
|
104
|
+
<label class="form-label">Offset X (px)</label>
|
|
105
|
+
<input id="theme-switcher-offset-x" type="number" class="form-input" min="0" max="400">
|
|
106
|
+
</div>
|
|
107
|
+
<div class="col-4">
|
|
108
|
+
<label class="form-label">Offset Y (px)</label>
|
|
109
|
+
<input id="theme-switcher-offset-y" type="number" class="form-input" min="0" max="400">
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div class="card">
|
|
116
|
+
<div class="card-header"><h2>Typography</h2></div>
|
|
117
|
+
<div class="card-body">
|
|
118
|
+
<div class="row">
|
|
119
|
+
<div class="col-6">
|
|
120
|
+
<label class="form-label">Font Family</label>
|
|
121
|
+
<select id="theme-font-family" class="form-select">
|
|
122
|
+
<optgroup label="Sans-serif">
|
|
123
|
+
<option value="Roboto">Roboto (default)</option>
|
|
124
|
+
<option value="Inter">Inter</option>
|
|
125
|
+
<option value="Open Sans">Open Sans</option>
|
|
126
|
+
<option value="Lato">Lato</option>
|
|
127
|
+
<option value="Nunito">Nunito</option>
|
|
128
|
+
<option value="Poppins">Poppins</option>
|
|
129
|
+
<option value="Source Sans 3">Source Sans 3</option>
|
|
130
|
+
<option value="Montserrat">Montserrat</option>
|
|
131
|
+
<option value="Raleway">Raleway</option>
|
|
132
|
+
<option value="DM Sans">DM Sans</option>
|
|
133
|
+
<option value="Work Sans">Work Sans</option>
|
|
134
|
+
</optgroup>
|
|
135
|
+
<optgroup label="Serif">
|
|
136
|
+
<option value="Merriweather">Merriweather</option>
|
|
137
|
+
<option value="Playfair Display">Playfair Display</option>
|
|
138
|
+
<option value="Lora">Lora</option>
|
|
139
|
+
<option value="Roboto Slab">Roboto Slab</option>
|
|
140
|
+
</optgroup>
|
|
141
|
+
<optgroup label="Dyslexia-friendly">
|
|
142
|
+
<option value="Lexend">Lexend</option>
|
|
143
|
+
<option value="Atkinson Hyperlegible">Atkinson Hyperlegible</option>
|
|
144
|
+
<option value="Andika">Andika</option>
|
|
145
|
+
</optgroup>
|
|
146
|
+
<optgroup label="System">
|
|
147
|
+
<option value="system-ui">System UI (no web font)</option>
|
|
148
|
+
</optgroup>
|
|
149
|
+
</select>
|
|
150
|
+
<p class="form-hint text-muted" style="margin-top:.4rem;font-size:.8rem;">Public site body text.
|
|
151
|
+
The dyslexia-friendly group uses wider letterforms and spacing.</p>
|
|
152
|
+
</div>
|
|
153
|
+
<div class="col-3">
|
|
154
|
+
<label class="form-label">Font Size</label>
|
|
155
|
+
<select id="theme-font-size" class="form-select">
|
|
156
|
+
<option value="13">13px - Compact</option>
|
|
157
|
+
<option value="14">14px - Small</option>
|
|
158
|
+
<option value="15">15px - Slightly small</option>
|
|
159
|
+
<option value="16">16px - Default</option>
|
|
160
|
+
<option value="17">17px - Slightly large</option>
|
|
161
|
+
<option value="18">18px - Large</option>
|
|
162
|
+
<option value="20">20px - Extra large</option>
|
|
163
|
+
</select>
|
|
164
|
+
<p class="form-hint text-muted" style="margin-top:.4rem;font-size:.8rem;">Root font size. Every
|
|
165
|
+
rem value scales with it.</p>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
<!-- ------------------------------------------------------------------ -->
|
|
173
|
+
<!-- Element overrides -->
|
|
174
|
+
<!-- ------------------------------------------------------------------ -->
|
|
175
|
+
<div class="tab-panel">
|
|
176
|
+
<div class="card mb-4">
|
|
177
|
+
<div class="card-body">
|
|
178
|
+
<p class="text-muted" style="margin:0 0 .75rem;">
|
|
179
|
+
An override re-themes one region of the page. Give it a CSS selector, then either adopt another
|
|
180
|
+
theme wholesale or set individual design tokens. Everything inside that region follows - including
|
|
181
|
+
components rendered later - because a Domma theme is nothing but a block of
|
|
182
|
+
<code>--dm-*</code> values.
|
|
183
|
+
</p>
|
|
184
|
+
<button id="theme-add-override" class="btn btn-ghost btn-sm" type="button">
|
|
185
|
+
<span data-icon="plus"></span> Add override
|
|
186
|
+
</button>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
|
|
190
|
+
<div id="theme-overrides"></div>
|
|
191
|
+
<p id="theme-overrides-empty" class="text-muted" style="text-align:center;padding:2rem 0;">
|
|
192
|
+
No overrides yet. The whole site uses the front-end theme.
|
|
193
|
+
</p>
|
|
194
|
+
|
|
195
|
+
<div class="card mt-4">
|
|
196
|
+
<div class="card-header">
|
|
197
|
+
<h2>Generated CSS</h2>
|
|
198
|
+
<button id="theme-refresh-css" class="btn btn-ghost btn-sm" type="button">
|
|
199
|
+
<span data-icon="refresh-cw"></span> Refresh
|
|
200
|
+
</button>
|
|
201
|
+
</div>
|
|
202
|
+
<div class="card-body">
|
|
203
|
+
<p class="text-muted" style="margin-top:0;font-size:.85rem;">
|
|
204
|
+
Exactly what is injected into every public page, ahead of your custom CSS.
|
|
205
|
+
</p>
|
|
206
|
+
<pre id="theme-css-preview" class="p-3"
|
|
207
|
+
style="max-height:320px;overflow:auto;background:var(--dm-surface-raised);border-radius:var(--dm-radius-md);font-size:.8rem;margin:0;">(nothing yet)</pre>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<!-- No heading: the banner above (admin/js/lib/plugin-chrome.js) is the title.
|
|
2
|
+
Everything that changes is bound (M.applyBindings) - see admin/js/views/todo.js, which also
|
|
3
|
+
inserts the row template: the router renders this file through _.render, eating any {{…}}. -->
|
|
4
|
+
<div class="todo-tool">
|
|
5
|
+
|
|
6
|
+
<!-- Quick add: type and press Enter. -->
|
|
7
|
+
<form class="todo-add" data-on-submit="add">
|
|
8
|
+
<input type="text" class="form-input todo-add-text" placeholder="Add a task and press Enter…"
|
|
9
|
+
aria-label="New task" autocomplete="off" data-model="draft.value" data-focus="addFocus.value">
|
|
10
|
+
<select class="form-input todo-add-priority" aria-label="Priority" data-model="draftPriority.value">
|
|
11
|
+
<option value="highest">Highest</option>
|
|
12
|
+
<option value="high">High</option>
|
|
13
|
+
<option value="medium">Medium</option>
|
|
14
|
+
<option value="low">Low</option>
|
|
15
|
+
<option value="lowest">Lowest</option>
|
|
16
|
+
</select>
|
|
17
|
+
<input type="date" class="form-input todo-add-due" aria-label="Due date (optional)" title="Due date (optional)"
|
|
18
|
+
data-model="draftDue.value">
|
|
19
|
+
<button type="submit" class="btn btn-sm btn-primary" data-bind-disabled="cannotAdd.value">
|
|
20
|
+
<span data-icon="plus" data-icon-size="14"></span> Add
|
|
21
|
+
</button>
|
|
22
|
+
<span data-help-title="Adding tasks"
|
|
23
|
+
data-help="Type and press Enter. Priority and due date are optional - the priority starts at the default from settings (the cog above). Press N anywhere on this screen to jump here."></span>
|
|
24
|
+
</form>
|
|
25
|
+
|
|
26
|
+
<div class="todo-bar">
|
|
27
|
+
<label class="todo-search">
|
|
28
|
+
<span data-icon="search" data-icon-size="14"></span>
|
|
29
|
+
<input type="search" class="form-input" placeholder="Search tasks…" aria-label="Search tasks"
|
|
30
|
+
data-model="query.value" data-focus="searchFocus.value">
|
|
31
|
+
</label>
|
|
32
|
+
<select class="form-input todo-filter" aria-label="Show" data-options="filterOptions.value"
|
|
33
|
+
data-options-text="label" data-options-value="value" data-model="filter.value"></select>
|
|
34
|
+
<span data-help-title="Working with tasks"
|
|
35
|
+
data-help="Tick a task to complete it. Right-click a task (or its ⋮, or click its status or priority) to change status, priority or due date, edit, or delete it. Completed tasks always sit at the bottom. Press / to search."></span>
|
|
36
|
+
<span class="todo-count" data-bind-text="countText.value"></span>
|
|
37
|
+
<button type="button" class="btn btn-sm btn-ghost todo-clear" data-if="counts.value.completed"
|
|
38
|
+
data-on-click="clearCompleted" title="Delete every completed task">
|
|
39
|
+
<span data-icon="trash" data-icon-size="13"></span> Clear completed
|
|
40
|
+
</button>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<p class="todo-state" data-if="loading.value">Loading tasks…</p>
|
|
44
|
+
<p class="todo-state" data-if="isEmpty.value" data-bind-text="emptyText.value"></p>
|
|
45
|
+
|
|
46
|
+
<div class="todo-list">
|
|
47
|
+
<div class="todo-rows" data-each="rows.value key=id"></div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<style>
|
|
52
|
+
.todo-tool { display: flex; flex-direction: column; gap: .75rem; }
|
|
53
|
+
.todo-add, .todo-bar { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin: 0; }
|
|
54
|
+
.todo-add .form-input, .todo-bar .form-input { height: 2rem; }
|
|
55
|
+
.todo-add-text { flex: 1 1 240px; }
|
|
56
|
+
.todo-add-priority { width: 7.5rem; padding-top: 0; padding-bottom: 0; }
|
|
57
|
+
.todo-add-due { width: 9.5rem; }
|
|
58
|
+
.todo-search { position: relative; flex: 1 1 180px; max-width: 280px; margin: 0; }
|
|
59
|
+
.todo-search > svg, .todo-search > [data-icon] {
|
|
60
|
+
position: absolute; left: .6rem; top: 50%; transform: translateY(-50%); color: var(--dm-text-muted); pointer-events: none;
|
|
61
|
+
}
|
|
62
|
+
.todo-search .form-input { padding-left: 1.9rem; }
|
|
63
|
+
.todo-filter { width: auto; min-width: 10rem; padding-top: 0; padding-bottom: 0; }
|
|
64
|
+
.todo-count { font-size: var(--dm-text-xs); color: var(--dm-text-muted); white-space: nowrap; }
|
|
65
|
+
.todo-clear { margin-left: auto; color: var(--dm-text-muted); }
|
|
66
|
+
.todo-state { margin: 1.5rem 0; text-align: center; color: var(--dm-text-muted); }
|
|
67
|
+
|
|
68
|
+
.todo-rows { display: flex; flex-direction: column; border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); overflow: hidden; }
|
|
69
|
+
.todo-rows:empty { display: none; }
|
|
70
|
+
.todo-row {
|
|
71
|
+
display: flex; align-items: center; gap: .65rem; padding: .45rem .5rem .45rem .75rem;
|
|
72
|
+
border-bottom: 1px solid var(--dm-border);
|
|
73
|
+
}
|
|
74
|
+
.todo-row:last-child { border-bottom: 0; }
|
|
75
|
+
.todo-row:hover, .todo-row:focus-within { background: var(--dm-surface-hover, rgba(127,127,127,.08)); }
|
|
76
|
+
.todo-row .todo-check { flex: 0 0 auto; width: 1rem; height: 1rem; cursor: pointer; margin: 0; }
|
|
77
|
+
.todo-text { flex: 1; min-width: 0; font-size: var(--dm-text-sm); overflow-wrap: anywhere; cursor: pointer; }
|
|
78
|
+
.todo-row.is-done .todo-text { text-decoration: line-through; opacity: .5; }
|
|
79
|
+
.todo-due { flex: 0 0 auto; font-size: var(--dm-text-xs); padding: .05rem .45rem; border-radius: 999px; white-space: nowrap;
|
|
80
|
+
background: var(--dm-surface-hover, rgba(127,127,127,.15)); color: var(--dm-text-muted); }
|
|
81
|
+
.todo-due:empty { display: none; }
|
|
82
|
+
.todo-due.is-today { color: var(--dm-warning, #d97706); }
|
|
83
|
+
.todo-due.is-overdue { background: color-mix(in srgb, var(--dm-danger, #dc2626) 16%, transparent); color: var(--dm-danger, #dc2626); }
|
|
84
|
+
.todo-pill {
|
|
85
|
+
flex: 0 0 auto; border: 0; cursor: pointer; font: inherit; font-size: var(--dm-text-xs); font-weight: 500;
|
|
86
|
+
padding: .1rem .55rem; border-radius: 999px; white-space: nowrap;
|
|
87
|
+
}
|
|
88
|
+
.todo-kebab { flex: 0 0 auto; border: 0; background: none; cursor: pointer; font-size: var(--dm-text-lg); line-height: 1.2;
|
|
89
|
+
color: var(--dm-text-muted); border-radius: var(--dm-radius-sm); padding: 0 .3rem; }
|
|
90
|
+
.todo-kebab:hover { color: var(--dm-primary); background: var(--dm-surface-hover, rgba(127,127,127,.15)); }
|
|
91
|
+
@media (max-width: 640px) { .todo-pill[data-kind="status"] { display: none; } }
|
|
92
|
+
|
|
93
|
+
/* Pills take the theme's own tokens, so they read in dark mode too. */
|
|
94
|
+
.todo-pill[data-value="not-started"] { background: var(--dm-surface-hover, rgba(127,127,127,.15)); color: var(--dm-text-muted); }
|
|
95
|
+
.todo-pill[data-value="in-progress"] { background: color-mix(in srgb, var(--dm-primary) 18%, transparent); color: var(--dm-primary); }
|
|
96
|
+
.todo-pill[data-value="completed"] { background: color-mix(in srgb, var(--dm-success, #16a34a) 18%, transparent); color: var(--dm-success, #16a34a); }
|
|
97
|
+
.todo-pill[data-value="highest"] { background: color-mix(in srgb, var(--dm-danger, #dc2626) 20%, transparent); color: var(--dm-danger, #dc2626); }
|
|
98
|
+
.todo-pill[data-value="high"] { background: color-mix(in srgb, #ea580c 18%, transparent); color: #ea580c; }
|
|
99
|
+
.todo-pill[data-value="medium"] { background: color-mix(in srgb, var(--dm-warning, #d97706) 18%, transparent); color: var(--dm-warning, #d97706); }
|
|
100
|
+
.todo-pill[data-value="low"] { background: color-mix(in srgb, var(--dm-primary) 14%, transparent); color: var(--dm-primary); }
|
|
101
|
+
.todo-pill[data-value="lowest"] { background: var(--dm-surface-hover, rgba(127,127,127,.15)); color: var(--dm-text-muted); }
|
|
102
|
+
|
|
103
|
+
/* Editor and settings slideovers */
|
|
104
|
+
.todo-panel { display: flex; flex-direction: column; gap: 1rem; padding: .25rem 0 .5rem; }
|
|
105
|
+
.todo-panel .form-label { display: flex; align-items: center; font-weight: 500; margin-bottom: .3rem; }
|
|
106
|
+
.todo-panel textarea { min-height: 90px; resize: vertical; font-family: inherit; }
|
|
107
|
+
.todo-panel-row { display: grid; grid-template-columns: 1fr 1fr; gap: .75rem; }
|
|
108
|
+
.todo-setting-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
|
|
109
|
+
.todo-panel-meta { font-size: var(--dm-text-xs); color: var(--dm-text-muted); }
|
|
110
|
+
.todo-panel-actions { display: flex; align-items: center; gap: .5rem; padding-top: .75rem; border-top: 1px solid var(--dm-border); }
|
|
111
|
+
.todo-panel-actions .spacer { flex: 1; }
|
|
112
|
+
.todo-quick-due { display: flex; gap: .35rem; flex-wrap: wrap; margin-top: .35rem; }
|
|
113
|
+
</style>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import{apiRequest as v,getToken as Z,refreshAccessToken as Q}from"../api.js";import{addBannerAction as X}from"../lib/plugin-chrome.js";import{helpPopovers as V}from"../lib/help-popover.js";import{onceClosed as ee,openMenuAt as te,settingsStore as ae,sidebarCount as se,viewLifetime as ne}from"../lib/tool-kit.js";import{DEFAULT_SETTINGS as oe,journeyRows as le,kpis as ie,LIMITS as re,normaliseSettings as O,RANGE_LABEL as B,RANGES as ce,seriesRange as de,topRows as pe}from"../lib/analytics-shape.js";const ue="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js",me=3e4,q=ae("analytics.settings",O),ve=`
|
|
2
|
+
<div class="an-row" data-url="{{url}}">
|
|
3
|
+
<span class="an-bar-fill" style="width: {{bar}}"></span>
|
|
4
|
+
<span class="an-rank">{{rank}}</span>
|
|
5
|
+
<span class="an-url" title="{{url}}">{{url}}</span>
|
|
6
|
+
<span class="an-num">{{hitsText}}</span>
|
|
7
|
+
<span class="an-share">{{share}}</span>
|
|
8
|
+
<button type="button" class="an-kebab" aria-label="Page actions" title="Actions">\u22EE</button>
|
|
9
|
+
</div>`,A=`
|
|
10
|
+
<div class="an-row" data-url="{{url}}">
|
|
11
|
+
<span class="an-bar-fill" style="width: {{bar}}"></span>
|
|
12
|
+
<span class="an-url" title="{{label}}">{{label}}</span>
|
|
13
|
+
<span class="an-num">{{count}}</span>
|
|
14
|
+
<button type="button" class="an-kebab" aria-label="Page actions" title="Actions">\u22EE</button>
|
|
15
|
+
</div>`,be=`
|
|
16
|
+
<div class="an-row" data-url="{{url}}">
|
|
17
|
+
<span class="an-url" title="{{url}}">{{url}}</span>
|
|
18
|
+
<span class="an-num" title="Views per hour today, against the usual {{baseline}}">{{hits}}/h</span>
|
|
19
|
+
<span class="an-share">\xD7{{ratio}}</span>
|
|
20
|
+
<button type="button" class="an-kebab" aria-label="Page actions" title="Actions">\u22EE</button>
|
|
21
|
+
</div>`;function he(){return window.Chart?Promise.resolve():new Promise((r,s)=>{const t=document.createElement("script");t.src=ue,t.async=!0,t.onload=()=>r(),t.onerror=()=>s(new Error("chart.js load failed")),document.head.appendChild(t)})}function fe(r){const s=document.createElement("template");return s.innerHTML=r.trim(),s.content.firstElementChild}async function ye(r){const s=b=>fetch("/api/analytics/export.csv?range="+encodeURIComponent(r),{headers:b?{Authorization:"Bearer "+b}:{}});let t=await s(Z());if(t.status===401&&(t=await s(await Q())),!t.ok)throw new Error("export failed");const c=await t.blob(),d=(t.headers.get("Content-Disposition")||"").match(/filename="?([^"]+)"?/),u=URL.createObjectURL(c),i=document.createElement("a");i.href=u,i.download=d?d[1]:"analytics.csv",document.body.appendChild(i),i.click(),i.remove(),URL.revokeObjectURL(u)}const l=ne(/^#\/analytics\b/);export const analyticsView={templateUrl:"/admin/js/templates/analytics.html",async onMount(r){l.reset();const s=r.get(0),t=M.observable(q.read()),c=M.observable(t.peek().range),d=M.observable("pages"),u=M.observable(""),i=M.observable(null),b=M.observable([]),y=M.observable(null),S=M.observable([]),g=M.observable(null),x=M.observable([]),j=M.observable("");l.add(M.effect(()=>{const e=i.value,{rows:a,matched:n}=pe(e?.top,{filter:u.value,limit:t.value.limit,total:e?.total});x.value=a,j.value=e?e.top.length?n?n>a.length?`Showing ${a.length} of ${n} pages - the cog changes how many.`:"":"No pages match that filter.":"No page views recorded in this range yet.":"Loading\u2026"}));const P=M.observable([]),U=M.observable([]),$=M.observable([]);l.add(M.effect(()=>{const e=le(y.value);P.value=e.entry,U.value=e.exit,$.value=e.paths}));const G={range:c,section:d,filter:u,spikes:S,pageRows:x,pagesNote:j,entryRows:P,exitRows:U,pathRows:$,kpi:M.computed(()=>ie(i.value,y.value)),isAllTime:M.computed(()=>c.value==="all"),sessionsCount:M.computed(()=>y.value?.totalSessions??0),liveText:M.computed(()=>g.value===null?"Active now: -":`${g.value} active now`),liveClass:M.computed(()=>g.value?"is-on":""),liveTitle:M.computed(()=>t.value.live?"Refreshes every 30 seconds":"Live refresh is off - see settings")};l.add(M.effect(()=>q.write(t.value)));const W=(e,a)=>{t.value=O({...t.peek(),[e]:a})};let k=0;async function w(){const e=c.peek(),a=++k;try{const[n,p,m,f]=await Promise.all([v("/analytics/stats?range="+encodeURIComponent(e)),v("/analytics/series?range="+encodeURIComponent(de(e))),v("/analytics/journeys?range="+encodeURIComponent(e)),v("/analytics/spikes")]);if(a!==k)return;i.value=n,b.value=p?.series??[],y.value=m,S.value=(f?.items??[]).map(o=>({...o,key:o.url}))}catch{a===k&&E.toast("Could not load analytics.",{type:"error"})}}async function C(){try{g.value=(await v("/analytics/realtime"))?.activeSessions??0,se("#/analytics")}catch{}}let _=!0;l.add(M.effect(()=>{if(c.value,_){_=!1;return}w()}));let L=null;l.add(M.effect(()=>{clearInterval(L),L=t.value.live?setInterval(()=>{document.hidden||C()},me):null})),l.add(()=>clearInterval(L));const H=s.querySelector(".an-chart");let R=null;l.add(()=>{R?.destroy(),R=null}),l.add(M.effect(()=>{const e=b.value,a=t.value.chart;if(!window.Chart||!H.isConnected)return;const n=getComputedStyle(document.documentElement),p=n.getPropertyValue("--dm-primary").trim()||"rgb(99, 102, 241)",m=n.getPropertyValue("--dm-text-muted").trim()||"#888",f=`color-mix(in srgb, ${n.getPropertyValue("--dm-border").trim()||"#888"} 45%, transparent)`;R?.destroy(),R=new window.Chart(H,{type:a,data:{labels:e.map(o=>D(o.date).format("D MMM")),datasets:[{label:"Page views",data:e.map(o=>o.hits),borderColor:p,backgroundColor:a==="bar"?p:`color-mix(in srgb, ${p} 18%, transparent)`,fill:a==="line",tension:.3,borderWidth:2,pointRadius:e.length>40?0:2,borderRadius:3}]},options:{responsive:!0,maintainAspectRatio:!1,animation:!1,plugins:{legend:{display:!1}},scales:{y:{beginAtZero:!0,ticks:{precision:0,color:m},grid:{color:f}},x:{ticks:{maxRotation:0,autoSkip:!0,maxTicksLimit:10,color:m},grid:{display:!1}}}}})}));function J(){const e=E.slideover({title:"Analytics settings",size:"sm",position:"right"}),a=fe(`
|
|
22
|
+
<div class="an-panel-form">
|
|
23
|
+
<div>
|
|
24
|
+
<label class="form-label" for="an-set-range">Open on</label>
|
|
25
|
+
<select id="an-set-range" class="form-input" data-model="range.value">
|
|
26
|
+
${ce.map(o=>`<option value="${o}">${B[o]}</option>`).join("")}
|
|
27
|
+
</select>
|
|
28
|
+
</div>
|
|
29
|
+
<div>
|
|
30
|
+
<label class="form-label" for="an-set-limit">Top pages shown
|
|
31
|
+
<span data-help="How many pages the Top pages list shows. The filter still searches all of them, and the CSV export always has every page."></span>
|
|
32
|
+
</label>
|
|
33
|
+
<select id="an-set-limit" class="form-input" data-model="limit.value">
|
|
34
|
+
${re.map(o=>`<option value="${o}">${o||"All"}</option>`).join("")}
|
|
35
|
+
</select>
|
|
36
|
+
</div>
|
|
37
|
+
<div>
|
|
38
|
+
<label class="form-label" for="an-set-chart">Chart</label>
|
|
39
|
+
<select id="an-set-chart" class="form-input" data-model="chart.value">
|
|
40
|
+
<option value="line">Line</option>
|
|
41
|
+
<option value="bar">Bars</option>
|
|
42
|
+
</select>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="an-setting-row">
|
|
45
|
+
<label class="form-label" for="an-set-live" style="margin:0">Live "active now"
|
|
46
|
+
<span data-help="Refresh the active-visitor count every 30 seconds while this screen is open and visible."></span>
|
|
47
|
+
</label>
|
|
48
|
+
<input id="an-set-live" type="checkbox" class="form-switch" data-model="live.value">
|
|
49
|
+
</div>
|
|
50
|
+
<div class="an-setting-row">
|
|
51
|
+
<label class="form-label" for="an-set-confirm" style="margin:0">Confirm before resetting
|
|
52
|
+
<span data-help="Reset deletes every counter this site has. Leave this on."></span>
|
|
53
|
+
</label>
|
|
54
|
+
<input id="an-set-confirm" type="checkbox" class="form-switch" data-model="confirmReset.value">
|
|
55
|
+
</div>
|
|
56
|
+
<small class="an-panel-meta">Saved in this browser as you change them.</small>
|
|
57
|
+
<div class="an-panel-actions">
|
|
58
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="reset">Reset to defaults</button>
|
|
59
|
+
<span class="spacer"></span>
|
|
60
|
+
<button type="button" class="btn btn-sm btn-primary" data-on-click="done">Done</button>
|
|
61
|
+
</div>
|
|
62
|
+
</div>`),n=(o,K=T=>T)=>M.computed({read:()=>t.value[o],write:T=>W(o,K(T))}),p={range:n("range"),limit:n("limit",Number),chart:n("chart"),live:n("live"),confirmReset:n("confirmReset")};e.element.appendChild(a);const m=V(a),f=M.applyBindings(p,a,{methods:{done:()=>e.close(),reset:()=>{t.value={...oe}}}});ee(e,()=>{f.dispose(),m()}),e.open()}X(r,{id:"analytics-settings",icon:"settings",title:"Analytics settings",onClick:J});const h=[...s.querySelectorAll(".an-list")];h[0].innerHTML=ve,h[1].innerHTML=A,h[2].innerHTML=A,h[3].innerHTML=A,h[4].innerHTML=be,l.add(V(s,{position:"bottom"}));const z=M.applyBindings(G,s,{methods:{refresh:()=>{w(),C()},showPages:()=>{d.value="pages"},showJourneys:()=>{d.value="journeys"},showSpikes:()=>{d.value="spikes"}}});l.add(()=>z.dispose());const N=e=>new URL(e,location.origin).href,Y=E.contextMenu(s,{match:".an-row",inherit:!1,density:"compact",items:e=>{const a=e.dataset.url;return[{label:"Open on the site",icon:"external-link",action:()=>window.open(N(a),"_blank","noopener")},{label:"Copy address",icon:"copy",action:async()=>{try{await navigator.clipboard.writeText(N(a)),E.toast("Address copied",{type:"success"})}catch{E.toast("The browser would not allow copying",{type:"error"})}}},{label:"Show only this page",icon:"filter",action:()=>{d.value="pages",u.value=a}}]}});l.add(()=>Y?.destroy?.());const F=E.contextMenu(s.querySelector(".an-bar-end"),{match:".an-more",inherit:!1,density:"compact",items:()=>[{label:`Export ${B[c.peek()].toLowerCase()} as CSV`,icon:"download",action:async()=>{try{await ye(c.peek())}catch{E.toast("Export failed.",{type:"error"})}}},{type:"divider"},{label:"Reset all statistics\u2026",icon:"trash",danger:!0,action:async()=>{if(!(t.peek().confirmReset&&!await E.confirm("Delete every analytics counter for this site? This cannot be undone.")))try{await v("/analytics/stats",{method:"DELETE"}),E.toast("Analytics reset.",{type:"success"}),w()}catch{E.toast("Reset failed.",{type:"error"})}}}]});l.add(()=>F?.destroy?.()),s.addEventListener("click",e=>{const a=e.target.closest(".an-kebab, .an-more");a&&te(a)}),I.scan(s);try{await he()}catch{E.toast("The chart library could not be loaded; figures still work.",{type:"warning"})}await Promise.all([w(),C()])}};
|