ultimate-jekyll-manager 1.0.18 → 1.0.20
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/CHANGELOG.md +24 -0
- package/CLAUDE.md +66 -8
- package/dist/assets/css/pages/download/index.scss +82 -10
- package/dist/assets/css/pages/extension/installed/index.scss +128 -68
- package/dist/assets/css/pages/payment/checkout/index.scss +4 -2
- package/dist/assets/js/core/appearance.js +2 -4
- package/dist/assets/js/core/auth.js +6 -8
- package/dist/assets/js/core/complete.js +1 -3
- package/dist/assets/js/core/cookieconsent.js +3 -3
- package/dist/assets/js/core/exit-popup.js +2 -3
- package/dist/assets/js/core/initialize.js +1 -4
- package/dist/assets/js/core/lazy-loading.js +3 -4
- package/dist/assets/js/core/query-strings.js +3 -4
- package/dist/assets/js/core/service-worker.js +1 -4
- package/dist/assets/js/core/social-sharing.js +3 -3
- package/dist/assets/js/libs/admin-helpers.js +0 -6
- package/dist/assets/js/libs/auth.js +6 -10
- package/dist/assets/js/libs/authorized-fetch.js +0 -3
- package/dist/assets/js/libs/dev.js +5 -10
- package/dist/assets/js/libs/form-manager.js +4 -3
- package/dist/assets/js/modules/vert.js +5 -4
- package/dist/assets/js/pages/404/index.js +2 -4
- package/dist/assets/js/pages/account/index.js +3 -6
- package/dist/assets/js/pages/account/sections/api-keys.js +2 -4
- package/dist/assets/js/pages/account/sections/billing.js +9 -9
- package/dist/assets/js/pages/account/sections/connections.js +4 -5
- package/dist/assets/js/pages/account/sections/data-request.js +2 -3
- package/dist/assets/js/pages/account/sections/delete.js +2 -3
- package/dist/assets/js/pages/account/sections/notifications.js +33 -27
- package/dist/assets/js/pages/account/sections/profile.js +2 -3
- package/dist/assets/js/pages/account/sections/referrals.js +3 -5
- package/dist/assets/js/pages/account/sections/refund.js +2 -4
- package/dist/assets/js/pages/account/sections/security.js +7 -8
- package/dist/assets/js/pages/account/sections/team.js +49 -29
- package/dist/assets/js/pages/admin/calendar/calendar-core.js +4 -4
- package/dist/assets/js/pages/admin/calendar/calendar-events.js +18 -19
- package/dist/assets/js/pages/admin/calendar/calendar-renderer.js +6 -6
- package/dist/assets/js/pages/admin/calendar/campaign-preview.js +8 -8
- package/dist/assets/js/pages/admin/calendar/index.js +4 -9
- package/dist/assets/js/pages/admin/dashboard/index.js +11 -13
- package/dist/assets/js/pages/admin/firebase/index.js +10 -13
- package/dist/assets/js/pages/admin/users/index.js +6 -8
- package/dist/assets/js/pages/admin/users/new/index.js +2 -4
- package/dist/assets/js/pages/alternatives/alternative/index.js +2 -5
- package/dist/assets/js/pages/app/index.js +2 -4
- package/dist/assets/js/pages/blog/index.js +3 -7
- package/dist/assets/js/pages/blog/post.js +2 -5
- package/dist/assets/js/pages/contact/index.js +3 -7
- package/dist/assets/js/pages/download/index.js +6 -7
- package/dist/assets/js/pages/extension/index.js +2 -5
- package/dist/assets/js/pages/extension/installed/index.js +135 -0
- package/dist/assets/js/pages/feedback/index.js +3 -7
- package/dist/assets/js/pages/index.js +3 -5
- package/dist/assets/js/pages/oauth2/index.js +2 -5
- package/dist/assets/js/pages/payment/checkout/index.js +12 -14
- package/dist/assets/js/pages/payment/checkout/modules/api.js +6 -5
- package/dist/assets/js/pages/payment/checkout/modules/discount.js +2 -10
- package/dist/assets/js/pages/payment/checkout/modules/recaptcha.js +3 -1
- package/dist/assets/js/pages/payment/checkout/modules/state.js +2 -1
- package/dist/assets/js/pages/payment/confirmation/index.js +4 -7
- package/dist/assets/js/pages/payment/confirmation/modules/celebration.js +2 -1
- package/dist/assets/js/pages/payment/confirmation/modules/tracking.js +2 -1
- package/dist/assets/js/pages/portal/email-preferences/index.js +2 -6
- package/dist/assets/js/pages/pricing/index.js +2 -6
- package/dist/assets/js/pages/reset/index.js +2 -6
- package/dist/assets/js/pages/signin/index.js +2 -6
- package/dist/assets/js/pages/signup/index.js +2 -6
- package/dist/assets/js/pages/status/index.js +12 -23
- package/dist/assets/js/pages/test/libraries/appearance/index.js +2 -5
- package/dist/assets/js/pages/test/libraries/bootstrap-components/index.js +4 -5
- package/dist/assets/js/pages/test/libraries/form-manager/index.js +2 -6
- package/dist/assets/js/pages/token/index.js +21 -12
- package/dist/assets/js/ultimate-jekyll-manager.js +13 -13
- package/dist/config/_config_default.yml +3 -0
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/alternatives/alternative.html +0 -22
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/contact.html +3 -4
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +49 -21
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/extension/installed.html +69 -61
- package/dist/defaults/src/assets/js/main.js +0 -3
- package/dist/defaults/src/assets/js/pages/index.js +3 -5
- package/dist/index.js +5 -8
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,30 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
|
14
14
|
- `Fixed` for any bug fixes.
|
|
15
15
|
- `Security` in case of vulnerabilities.
|
|
16
16
|
|
|
17
|
+
---
|
|
18
|
+
## [1.0.20] - 2026-04-03
|
|
19
|
+
### Fixed
|
|
20
|
+
- Fix contact form sending `user: map[]` to Slapform by replacing nested `user` object with flat `uid` string field
|
|
21
|
+
- Autofill visible email input from auth state via `data-wm-bind="@value auth.user.email"` for logged-in users
|
|
22
|
+
- Remove redundant hidden `auth.user.email` field
|
|
23
|
+
|
|
24
|
+
## [1.0.19] - 2026-04-02
|
|
25
|
+
### Security
|
|
26
|
+
- Comprehensive XSS hardening: escape all dynamic data in innerHTML with `webManager.utilities().escapeHTML()`
|
|
27
|
+
- Remove all local `escapeHtml` implementations — single source of truth via web-manager
|
|
28
|
+
- Rebuild `showToast()` and `showNotification()` to use `textContent` instead of `innerHTML`
|
|
29
|
+
- Add `javascript:` protocol blocking in web-manager `@attr` binding directive
|
|
30
|
+
- Add URL scheme validation for vert.js postMessage handler
|
|
31
|
+
- Fix double-escaping in `showSuccess()`/`showError()`/`showNotification()` callers
|
|
32
|
+
- Document zero-trust XSS policy in CLAUDE.md and skills
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
- Refactor webManager from passed parameter to direct singleton import across all modules
|
|
36
|
+
- Remove `init(wm)` pattern and Manager parameter passing throughout page modules
|
|
37
|
+
- Calendar core/events/renderer use direct imports instead of constructor injection
|
|
38
|
+
- Fix file structure and spacing across all JS files (consistent Libraries/Module pattern)
|
|
39
|
+
- Fix alternatives layout markdown code block rendering issue
|
|
40
|
+
|
|
17
41
|
---
|
|
18
42
|
## [1.0.18] - 2026-03-30
|
|
19
43
|
### Changed
|
package/CLAUDE.md
CHANGED
|
@@ -360,14 +360,11 @@ All page modules must follow this standardized pattern:
|
|
|
360
360
|
*/
|
|
361
361
|
|
|
362
362
|
// Libraries
|
|
363
|
-
|
|
363
|
+
import webManager from 'web-manager';
|
|
364
364
|
|
|
365
365
|
// Module
|
|
366
|
-
export default (
|
|
366
|
+
export default () => {
|
|
367
367
|
return new Promise(async function (resolve) {
|
|
368
|
-
// Shortcuts
|
|
369
|
-
webManager = Manager.webManager;
|
|
370
|
-
|
|
371
368
|
// Initialize when DOM is ready
|
|
372
369
|
await webManager.dom().ready();
|
|
373
370
|
|
|
@@ -386,9 +383,63 @@ function helper1() {
|
|
|
386
383
|
```
|
|
387
384
|
|
|
388
385
|
**Key Points:**
|
|
386
|
+
- `web-manager` is a singleton — `import webManager from 'web-manager'` returns the same initialized instance everywhere. No need to receive it via params or store in module-level variables.
|
|
389
387
|
- Helpers are defined outside the main export function
|
|
390
|
-
- Use `webManager` shortcuts for common operations
|
|
391
388
|
- Always wait for DOM ready before manipulating elements
|
|
389
|
+
- Use `webManager.utilities().escapeHTML()` for XSS prevention — do NOT write your own escape function
|
|
390
|
+
|
|
391
|
+
## XSS Prevention (ZERO TRUST — MANDATORY)
|
|
392
|
+
|
|
393
|
+
**TREAT ALL DYNAMIC DATA AS UNTRUSTED.** This is a zero-trust policy: any value that did not come directly from a hardcoded literal in the source file MUST be escaped before being inserted into the DOM via `innerHTML` or attribute interpolation.
|
|
394
|
+
|
|
395
|
+
This includes — but is not limited to:
|
|
396
|
+
- Firestore document fields (user names, emails, IDs, descriptions, etc.)
|
|
397
|
+
- API response data
|
|
398
|
+
- URL parameters (`location.search`, `URLSearchParams`)
|
|
399
|
+
- User input from form fields
|
|
400
|
+
- OAuth-provided values (displayName, email from Google/GitHub)
|
|
401
|
+
- Any variable whose origin is not a hardcoded source-code constant
|
|
402
|
+
|
|
403
|
+
### The Rule
|
|
404
|
+
```javascript
|
|
405
|
+
// ✅ ALWAYS escape dynamic data before innerHTML
|
|
406
|
+
$el.innerHTML = `<p>${webManager.utilities().escapeHTML(data.title)}</p>`;
|
|
407
|
+
$el.innerHTML = `<a href="${webManager.utilities().escapeHTML(url)}">${webManager.utilities().escapeHTML(label)}</a>`;
|
|
408
|
+
|
|
409
|
+
// ✅ textContent is always safe — no escaping needed
|
|
410
|
+
$el.textContent = data.title;
|
|
411
|
+
|
|
412
|
+
// ❌ NEVER inject dynamic data raw into innerHTML
|
|
413
|
+
$el.innerHTML = `<p>${data.title}</p>`;
|
|
414
|
+
$el.innerHTML = `<a href="${url}">${label}</a>`;
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### NEVER Write Your Own Escape Function
|
|
418
|
+
Do NOT create a local `escapeHtml` function or any variant. The ONLY allowed escape method is:
|
|
419
|
+
```javascript
|
|
420
|
+
webManager.utilities().escapeHTML(str)
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### When Building DOM Programmatically
|
|
424
|
+
Prefer `document.createElement` + `textContent` for plain text nodes — it is inherently safe:
|
|
425
|
+
```javascript
|
|
426
|
+
const $el = document.createElement('div');
|
|
427
|
+
$el.textContent = data.message; // Safe — no escaping needed
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Only use `innerHTML` when you need actual HTML structure (tags, classes, etc.), and escape every dynamic value in it.
|
|
431
|
+
|
|
432
|
+
### Do NOT Escape Values Passed to textContent-Based APIs
|
|
433
|
+
`showNotification()`, `formManager.showSuccess()`, `formManager.showError()`, and `textContent` assignments use safe text insertion internally. Pre-escaping these causes double-encoding (e.g., `We'll` displays as `We'll`).
|
|
434
|
+
|
|
435
|
+
```javascript
|
|
436
|
+
// ✅ CORRECT — these APIs use textContent internally, so they're already safe
|
|
437
|
+
webManager.utilities().showNotification('Thank you! We\'ll be in touch.', 'success');
|
|
438
|
+
formManager.showSuccess('Message sent successfully!');
|
|
439
|
+
|
|
440
|
+
// ❌ WRONG — double-escapes
|
|
441
|
+
webManager.utilities().showNotification(webManager.utilities().escapeHTML(message), 'success');
|
|
442
|
+
```
|
|
392
443
|
|
|
393
444
|
## Layouts and Pages
|
|
394
445
|
|
|
@@ -976,15 +1027,22 @@ webManager.uj().appearance.clear(); // Clear saved preference
|
|
|
976
1027
|
|
|
977
1028
|
### WebManager
|
|
978
1029
|
|
|
979
|
-
Custom library for site management functionality.
|
|
1030
|
+
Custom library for site management functionality. **It's a singleton** — import it directly from any file:
|
|
1031
|
+
|
|
1032
|
+
```javascript
|
|
1033
|
+
import webManager from 'web-manager';
|
|
1034
|
+
```
|
|
1035
|
+
|
|
1036
|
+
This returns the same initialized instance everywhere. Do NOT pass it via params, store in module-level variables, or create new instances.
|
|
980
1037
|
|
|
981
1038
|
**Documentation:** `/Users/ian/Developer/Repositories/ITW-Creative-Works/web-manager/README.md`
|
|
982
1039
|
|
|
983
1040
|
**Available Utilities:**
|
|
984
1041
|
- `webManager.auth()` - Authentication management
|
|
985
|
-
- `webManager.utilities()` - Utility functions
|
|
1042
|
+
- `webManager.utilities()` - Utility functions (escapeHTML, clipboardCopy, etc.)
|
|
986
1043
|
- `webManager.sentry()` - Error tracking
|
|
987
1044
|
- `webManager.dom()` - DOM manipulation
|
|
1045
|
+
- `webManager.utilities().escapeHTML(text)` - **XSS prevention** — use this instead of writing your own escape function
|
|
988
1046
|
|
|
989
1047
|
**Important:** Always check the source code or README before assuming a function exists. Do not guess at API methods.
|
|
990
1048
|
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
// Mac platform folder styling
|
|
30
|
-
[data-platform="mac"] .folder-icon {
|
|
30
|
+
.platform-instructions[data-platform="mac"] .folder-icon {
|
|
31
31
|
background: linear-gradient(135deg, #6BB6FF 0%, #4A9FFF 100%);
|
|
32
32
|
|
|
33
33
|
&::before {
|
|
@@ -245,22 +245,94 @@
|
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
+
// Folder/app double-click animation (step 1)
|
|
249
|
+
.folder-click-target {
|
|
250
|
+
.pointer-icon {
|
|
251
|
+
animation: folder-mouse-move 3s ease-in-out infinite;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.click-pulse {
|
|
255
|
+
animation: folder-click-pulse 3s ease-in-out infinite;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
@keyframes folder-mouse-move {
|
|
260
|
+
0% {
|
|
261
|
+
transform: translate(60px, -20px);
|
|
262
|
+
}
|
|
263
|
+
20%, 80% {
|
|
264
|
+
transform: translate(0, 0);
|
|
265
|
+
}
|
|
266
|
+
81%, 100% {
|
|
267
|
+
transform: translate(60px, -20px);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
@keyframes folder-click-pulse {
|
|
272
|
+
0%, 25% {
|
|
273
|
+
opacity: 0;
|
|
274
|
+
transform: scale(0.5);
|
|
275
|
+
}
|
|
276
|
+
// First click
|
|
277
|
+
30%, 38% {
|
|
278
|
+
opacity: 0.8;
|
|
279
|
+
transform: scale(1.3);
|
|
280
|
+
}
|
|
281
|
+
42% {
|
|
282
|
+
opacity: 0;
|
|
283
|
+
transform: scale(0.5);
|
|
284
|
+
}
|
|
285
|
+
// Second click
|
|
286
|
+
48%, 56% {
|
|
287
|
+
opacity: 0.8;
|
|
288
|
+
transform: scale(1.3);
|
|
289
|
+
}
|
|
290
|
+
62%, 100% {
|
|
291
|
+
opacity: 0;
|
|
292
|
+
transform: scale(0.5);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
248
296
|
// Instruction step container
|
|
249
297
|
.instruction-step-container {
|
|
250
298
|
min-height: 200px;
|
|
251
299
|
}
|
|
252
300
|
|
|
253
|
-
// Steps slideshow
|
|
301
|
+
// Steps slideshow — uses a grid stack so all slides overlap in the same cell,
|
|
302
|
+
// making the container always the height of the tallest slide (no jitter).
|
|
254
303
|
.steps-slideshow {
|
|
255
304
|
position: relative;
|
|
256
305
|
|
|
257
|
-
.
|
|
258
|
-
display:
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
306
|
+
.steps-slideshow-slides {
|
|
307
|
+
display: grid;
|
|
308
|
+
|
|
309
|
+
> .step-slide {
|
|
310
|
+
grid-area: 1 / 1;
|
|
311
|
+
text-align: center;
|
|
312
|
+
visibility: hidden;
|
|
313
|
+
opacity: 0;
|
|
314
|
+
transition: opacity 0.35s ease-out;
|
|
315
|
+
display: flex;
|
|
316
|
+
flex-direction: column;
|
|
317
|
+
|
|
318
|
+
&.active {
|
|
319
|
+
visibility: visible;
|
|
320
|
+
opacity: 1;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.step-number-badge,
|
|
324
|
+
.step-title {
|
|
325
|
+
align-self: center;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// The last child (visual content area) grows to fill remaining space
|
|
329
|
+
// and centers its content vertically
|
|
330
|
+
> :last-child {
|
|
331
|
+
flex: 1;
|
|
332
|
+
display: flex;
|
|
333
|
+
flex-direction: column;
|
|
334
|
+
justify-content: center;
|
|
335
|
+
}
|
|
264
336
|
}
|
|
265
337
|
}
|
|
266
338
|
}
|
|
@@ -283,7 +355,7 @@
|
|
|
283
355
|
// Step title
|
|
284
356
|
.step-title {
|
|
285
357
|
font-weight: 600;
|
|
286
|
-
margin-bottom:
|
|
358
|
+
margin-bottom: 1rem;
|
|
287
359
|
}
|
|
288
360
|
|
|
289
361
|
// Navigation bar
|
|
@@ -6,10 +6,6 @@
|
|
|
6
6
|
animation: success-appear 0.6s ease-out;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
body {
|
|
10
|
-
color: red !important;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
9
|
@keyframes success-appear {
|
|
14
10
|
0% {
|
|
15
11
|
transform: scale(0);
|
|
@@ -24,67 +20,6 @@ body {
|
|
|
24
20
|
}
|
|
25
21
|
}
|
|
26
22
|
|
|
27
|
-
// Arrow container positioning and animation
|
|
28
|
-
.extension-arrow-container {
|
|
29
|
-
top: 80px;
|
|
30
|
-
right: 40px;
|
|
31
|
-
animation: arrow-container-appear 0.5s ease-out 0.3s both;
|
|
32
|
-
|
|
33
|
-
@media (max-width: 991px) {
|
|
34
|
-
right: 20px;
|
|
35
|
-
top: 70px;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
@media (max-width: 576px) {
|
|
39
|
-
right: 10px;
|
|
40
|
-
top: 60px;
|
|
41
|
-
|
|
42
|
-
.extension-arrow svg {
|
|
43
|
-
width: 50px;
|
|
44
|
-
height: 70px;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@keyframes arrow-container-appear {
|
|
50
|
-
0% {
|
|
51
|
-
opacity: 0;
|
|
52
|
-
transform: translateY(20px);
|
|
53
|
-
}
|
|
54
|
-
100% {
|
|
55
|
-
opacity: 1;
|
|
56
|
-
transform: translateY(0);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Arrow bounce animation
|
|
61
|
-
.extension-arrow {
|
|
62
|
-
animation: arrow-bounce 1.5s ease-in-out infinite;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
@keyframes arrow-bounce {
|
|
66
|
-
0%, 100% {
|
|
67
|
-
transform: translateY(0);
|
|
68
|
-
}
|
|
69
|
-
50% {
|
|
70
|
-
transform: translateY(-8px);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Label glow animation
|
|
75
|
-
.extension-arrow-label {
|
|
76
|
-
animation: label-glow 2s ease-in-out infinite;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
@keyframes label-glow {
|
|
80
|
-
0%, 100% {
|
|
81
|
-
box-shadow: 0 4px 15px rgba(var(--bs-primary-rgb), 0.4);
|
|
82
|
-
}
|
|
83
|
-
50% {
|
|
84
|
-
box-shadow: 0 4px 25px rgba(var(--bs-primary-rgb), 0.7);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
23
|
// URL bar min width
|
|
89
24
|
.extension-url-bar {
|
|
90
25
|
min-width: 100px;
|
|
@@ -111,6 +46,13 @@ body {
|
|
|
111
46
|
object-fit: contain;
|
|
112
47
|
}
|
|
113
48
|
|
|
49
|
+
// Toolbar brandmark (pinned state in step 4)
|
|
50
|
+
.extension-toolbar-brandmark {
|
|
51
|
+
width: 16px;
|
|
52
|
+
height: 16px;
|
|
53
|
+
object-fit: contain;
|
|
54
|
+
}
|
|
55
|
+
|
|
114
56
|
// ============================================================================
|
|
115
57
|
// Click Indicator Animation (same pattern as download page)
|
|
116
58
|
// ============================================================================
|
|
@@ -188,15 +130,15 @@ body {
|
|
|
188
130
|
}
|
|
189
131
|
}
|
|
190
132
|
|
|
191
|
-
// Step
|
|
133
|
+
// Step 3: Pin button - mouse moves to target, clicks, snaps back
|
|
192
134
|
.extension-pin-target {
|
|
193
135
|
.click-indicator {
|
|
194
136
|
.pointer-icon {
|
|
195
|
-
animation: pin-mouse-move 2.5s ease-out infinite
|
|
137
|
+
animation: pin-mouse-move 2.5s ease-out infinite;
|
|
196
138
|
}
|
|
197
139
|
|
|
198
140
|
.click-pulse {
|
|
199
|
-
animation: pin-click-pulse 2.5s ease-out infinite
|
|
141
|
+
animation: pin-click-pulse 2.5s ease-out infinite;
|
|
200
142
|
}
|
|
201
143
|
}
|
|
202
144
|
}
|
|
@@ -238,3 +180,121 @@ body {
|
|
|
238
180
|
transform: translate(-5px, -12px) scale(0.5);
|
|
239
181
|
}
|
|
240
182
|
}
|
|
183
|
+
|
|
184
|
+
// ============================================================================
|
|
185
|
+
// Steps Slideshow (mirrored from download page)
|
|
186
|
+
// ============================================================================
|
|
187
|
+
|
|
188
|
+
// Instruction step container
|
|
189
|
+
.instruction-step-container {
|
|
190
|
+
min-height: 200px;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Steps slideshow — uses a grid stack so all slides overlap in the same cell,
|
|
194
|
+
// making the container always the height of the tallest slide (no jitter).
|
|
195
|
+
.steps-slideshow {
|
|
196
|
+
position: relative;
|
|
197
|
+
|
|
198
|
+
.steps-slideshow-slides {
|
|
199
|
+
display: grid;
|
|
200
|
+
|
|
201
|
+
> .step-slide {
|
|
202
|
+
grid-area: 1 / 1;
|
|
203
|
+
text-align: center;
|
|
204
|
+
visibility: hidden;
|
|
205
|
+
opacity: 0;
|
|
206
|
+
transition: opacity 0.35s ease-out;
|
|
207
|
+
display: flex;
|
|
208
|
+
flex-direction: column;
|
|
209
|
+
|
|
210
|
+
&.active {
|
|
211
|
+
visibility: visible;
|
|
212
|
+
opacity: 1;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.step-number-badge,
|
|
216
|
+
.step-title {
|
|
217
|
+
align-self: center;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// The last child (visual content area) grows to fill remaining space
|
|
221
|
+
// and centers its content vertically
|
|
222
|
+
> :last-child {
|
|
223
|
+
flex: 1;
|
|
224
|
+
display: flex;
|
|
225
|
+
flex-direction: column;
|
|
226
|
+
justify-content: center;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Big step number badge
|
|
233
|
+
.step-number-badge {
|
|
234
|
+
display: inline-flex;
|
|
235
|
+
align-items: center;
|
|
236
|
+
justify-content: center;
|
|
237
|
+
width: 56px;
|
|
238
|
+
height: 56px;
|
|
239
|
+
border-radius: 50%;
|
|
240
|
+
background: var(--bs-primary);
|
|
241
|
+
color: #fff;
|
|
242
|
+
font-size: 1.5rem;
|
|
243
|
+
font-weight: 700;
|
|
244
|
+
margin-bottom: 0.75rem;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Step title
|
|
248
|
+
.step-title {
|
|
249
|
+
font-weight: 600;
|
|
250
|
+
margin-bottom: 1rem;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Navigation bar
|
|
254
|
+
.steps-slideshow-nav {
|
|
255
|
+
display: flex;
|
|
256
|
+
align-items: center;
|
|
257
|
+
justify-content: space-between;
|
|
258
|
+
margin-top: 1.25rem;
|
|
259
|
+
padding-top: 1rem;
|
|
260
|
+
border-top: 1px solid var(--bs-border-color);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Progress dots
|
|
264
|
+
.steps-dots {
|
|
265
|
+
display: flex;
|
|
266
|
+
gap: 8px;
|
|
267
|
+
align-items: center;
|
|
268
|
+
|
|
269
|
+
.step-dot {
|
|
270
|
+
width: 10px;
|
|
271
|
+
height: 10px;
|
|
272
|
+
border-radius: 50%;
|
|
273
|
+
background: var(--bs-border-color);
|
|
274
|
+
border: none;
|
|
275
|
+
padding: 0;
|
|
276
|
+
cursor: pointer;
|
|
277
|
+
transition: background 0.2s, transform 0.2s;
|
|
278
|
+
|
|
279
|
+
&.active {
|
|
280
|
+
background: var(--bs-primary);
|
|
281
|
+
transform: scale(1.3);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
&:hover:not(.active) {
|
|
285
|
+
background: var(--bs-secondary);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Slide fade-in animation
|
|
291
|
+
@keyframes step-fade-in {
|
|
292
|
+
from {
|
|
293
|
+
opacity: 0;
|
|
294
|
+
transform: translateX(20px);
|
|
295
|
+
}
|
|
296
|
+
to {
|
|
297
|
+
opacity: 1;
|
|
298
|
+
transform: translateX(0);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
@@ -37,10 +37,12 @@
|
|
|
37
37
|
overflow: visible;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
// Extra :checked specificity to beat classy theme's
|
|
41
|
+
// .btn-check:checked:checked + [class*="btn-outline-"] { background: var(--bs-btn-active-bg) !important }
|
|
42
|
+
.btn-check:checked:checked + .btn {
|
|
41
43
|
border-color: var(--bs-primary) !important;
|
|
42
44
|
color: var(--bs-primary) !important;
|
|
43
|
-
background
|
|
45
|
+
background: transparent !important;
|
|
44
46
|
|
|
45
47
|
// Checkmark circle turns primary when selected
|
|
46
48
|
.rounded-circle {
|
|
@@ -2,19 +2,17 @@
|
|
|
2
2
|
* Appearance Module
|
|
3
3
|
* Handles theme appearance switching (dark, light, system)
|
|
4
4
|
*/
|
|
5
|
+
import webManager from 'web-manager';
|
|
5
6
|
|
|
6
7
|
// Constants
|
|
7
8
|
const STORAGE_KEY = 'appearance.preference';
|
|
8
9
|
const VALID_VALUES = ['dark', 'light', 'system'];
|
|
9
10
|
|
|
10
11
|
// Module state
|
|
11
|
-
let webManager = null;
|
|
12
12
|
let mediaQuery = null;
|
|
13
13
|
|
|
14
14
|
// Module
|
|
15
|
-
export default (
|
|
16
|
-
// Shortcuts
|
|
17
|
-
webManager = Manager.webManager;
|
|
15
|
+
export default () => {
|
|
18
16
|
|
|
19
17
|
// Create appearance API
|
|
20
18
|
const appearanceAPI = {
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js';
|
|
2
|
+
import webManager from 'web-manager';
|
|
2
3
|
|
|
3
4
|
// Constants
|
|
4
5
|
const SIGNUP_MAX_AGE = 5 * 60 * 1000;
|
|
5
6
|
|
|
6
7
|
// Auth Module
|
|
7
|
-
export default function (
|
|
8
|
-
// Shortcuts
|
|
9
|
-
const { webManager } = Manager;
|
|
10
|
-
|
|
8
|
+
export default function () {
|
|
11
9
|
// Get auth policy
|
|
12
10
|
const config = webManager.config.auth.config;
|
|
13
11
|
const policy = config.policy;
|
|
@@ -47,7 +45,7 @@ export default function (Manager, options) {
|
|
|
47
45
|
console.log('[Auth] state changed:', state);
|
|
48
46
|
|
|
49
47
|
// Set user ID for analytics tracking
|
|
50
|
-
setAnalyticsUserId(user
|
|
48
|
+
setAnalyticsUserId(user);
|
|
51
49
|
|
|
52
50
|
// Check if we're in the process of signing out
|
|
53
51
|
if (authSignout === 'true' && user) {
|
|
@@ -61,7 +59,7 @@ export default function (Manager, options) {
|
|
|
61
59
|
// User is authenticated
|
|
62
60
|
|
|
63
61
|
// Send user signup metadata if account is new
|
|
64
|
-
await sendUserSignupMetadata(user
|
|
62
|
+
await sendUserSignupMetadata(user);
|
|
65
63
|
|
|
66
64
|
// Check if page requires user to be unauthenticated (e.g., signin page)
|
|
67
65
|
if (policy === 'unauthenticated') {
|
|
@@ -160,7 +158,7 @@ function updateAuthLinks() {
|
|
|
160
158
|
});
|
|
161
159
|
}
|
|
162
160
|
|
|
163
|
-
function setAnalyticsUserId(user
|
|
161
|
+
function setAnalyticsUserId(user) {
|
|
164
162
|
const userId = user?.uid;
|
|
165
163
|
const email = user?.email;
|
|
166
164
|
const metaPixelId = webManager.config.analytics?.meta;
|
|
@@ -206,7 +204,7 @@ function setAnalyticsUserId(user, webManager) {
|
|
|
206
204
|
}
|
|
207
205
|
|
|
208
206
|
// Send user metadata to server (affiliate, UTM params, etc.)
|
|
209
|
-
async function sendUserSignupMetadata(user
|
|
207
|
+
async function sendUserSignupMetadata(user) {
|
|
210
208
|
try {
|
|
211
209
|
// Skip on auth pages to avoid blocking redirect (metadata will be sent on destination page)
|
|
212
210
|
const pagePath = document.documentElement.getAttribute('data-page-path');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import webManager from 'web-manager';
|
|
2
|
+
|
|
1
3
|
// Cookie Consent Module
|
|
2
|
-
export default function (
|
|
3
|
-
// Shortcuts
|
|
4
|
-
const { webManager } = Manager;
|
|
4
|
+
export default function () {
|
|
5
5
|
|
|
6
6
|
// Check if user has already consented
|
|
7
7
|
const hasConsented = webManager.storage().get('cookies.consent.accepted') === true;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
// Libraries
|
|
2
2
|
import merge from 'lodash/merge.js';
|
|
3
|
+
import webManager from 'web-manager';
|
|
3
4
|
|
|
4
5
|
// Exit Popup Module
|
|
5
|
-
export default function (
|
|
6
|
-
// Shortcuts
|
|
7
|
-
const { webManager } = Manager;
|
|
6
|
+
export default function () {
|
|
8
7
|
|
|
9
8
|
// Get config
|
|
10
9
|
const config = webManager.config.exitPopup.config;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
export default function (Manager, options) {
|
|
3
|
-
// Shortcuts
|
|
4
|
-
const { webManager } = Manager;
|
|
1
|
+
import webManager from 'web-manager';
|
|
5
2
|
|
|
3
|
+
// Lazy Loading Module
|
|
4
|
+
export default function () {
|
|
6
5
|
// Constants
|
|
7
6
|
const TRANSPARENT_PLACEHOLDER = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
|
8
7
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
export default function (Manager, options) {
|
|
3
|
-
// Shortcuts
|
|
4
|
-
const { webManager } = Manager;
|
|
1
|
+
import webManager from 'web-manager';
|
|
5
2
|
|
|
3
|
+
// Query Strings Module
|
|
4
|
+
export default function () {
|
|
6
5
|
// Process query strings when DOM is ready
|
|
7
6
|
webManager.dom().ready().then(() => {
|
|
8
7
|
processQueryStrings();
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
// Service Worker Core Library
|
|
2
|
-
export default function (
|
|
3
|
-
// Shortcuts
|
|
4
|
-
const { webManager } = Manager;
|
|
5
|
-
|
|
2
|
+
export default function ({ options } = {}) {
|
|
6
3
|
// Cache visited pages
|
|
7
4
|
if (!('serviceWorker' in navigator) || !navigator.serviceWorker.controller) {
|
|
8
5
|
console.warn('Service Worker not available or not controlled by a Service Worker.');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import webManager from 'web-manager';
|
|
2
|
+
|
|
1
3
|
// Social Sharing Module
|
|
2
|
-
export default function (
|
|
3
|
-
// Shortcuts
|
|
4
|
-
const { webManager } = Manager;
|
|
4
|
+
export default function () {
|
|
5
5
|
|
|
6
6
|
// Configuration with defaults merged with supplied config
|
|
7
7
|
const config = webManager.config.socialSharing.config;
|
|
@@ -33,12 +33,6 @@ export function capitalize(str) {
|
|
|
33
33
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
export function escapeHtml(str) {
|
|
37
|
-
const div = document.createElement('div');
|
|
38
|
-
div.textContent = str;
|
|
39
|
-
return div.innerHTML;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
36
|
export function setStatValue(id, result) {
|
|
43
37
|
const $el = document.getElementById(id);
|
|
44
38
|
if (!$el) {
|