ultimate-jekyll-manager 1.6.4 → 1.6.6
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 +25 -0
- package/dist/assets/css/pages/admin/calendar/index.scss +23 -9
- package/dist/assets/js/pages/account/sections/notifications.js +88 -0
- package/dist/assets/js/pages/admin/calendar/calendar-core.js +80 -14
- package/dist/assets/js/pages/admin/calendar/calendar-events.js +166 -48
- package/dist/assets/js/pages/admin/calendar/calendar-renderer.js +120 -16
- package/dist/defaults/dist/_layouts/blueprint/admin/calendar/index.html +84 -53
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +30 -0
- package/dist/gulp/tasks/imagemin.js +12 -12
- package/dist/gulp/tasks/translation.js +95 -158
- package/dist/service-worker.js +21 -0
- package/package.json +2 -2
|
@@ -60,6 +60,7 @@ prerender_icons:
|
|
|
60
60
|
- name: "wifi"
|
|
61
61
|
- name: "battery-full"
|
|
62
62
|
- name: "table-list"
|
|
63
|
+
- name: "vial"
|
|
63
64
|
---
|
|
64
65
|
|
|
65
66
|
<!-- Calendar Root -->
|
|
@@ -79,6 +80,7 @@ prerender_icons:
|
|
|
79
80
|
<h5 class="modal-title" id="campaign-modal-title">
|
|
80
81
|
{% uj_icon "plus", "fa-md me-2" %}
|
|
81
82
|
<span id="campaign-modal-title-text">Create campaign</span>
|
|
83
|
+
<small class="text-muted fw-normal ms-2 d-none" id="campaign-modal-id" style="font-size: 0.6rem"></small>
|
|
82
84
|
</h5>
|
|
83
85
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
84
86
|
</div>
|
|
@@ -87,7 +89,7 @@ prerender_icons:
|
|
|
87
89
|
|
|
88
90
|
<!-- Campaign Type -->
|
|
89
91
|
<h6 class="mb-3">
|
|
90
|
-
{% uj_icon "bullhorn", "
|
|
92
|
+
{% uj_icon "bullhorn", "me-2 text-info" %}
|
|
91
93
|
Campaign type
|
|
92
94
|
</h6>
|
|
93
95
|
<div class="row mb-4">
|
|
@@ -186,9 +188,8 @@ prerender_icons:
|
|
|
186
188
|
<div class="col-md-6">
|
|
187
189
|
<label for="campaign-template" class="form-label">Template</label>
|
|
188
190
|
<select class="form-select" id="campaign-template" name="campaign.template">
|
|
189
|
-
<option value="
|
|
190
|
-
<option value="
|
|
191
|
-
<option value="main/basic/plain">Plain</option>
|
|
191
|
+
<option value="card" selected>Card</option>
|
|
192
|
+
<option value="plain">Plain</option>
|
|
192
193
|
</select>
|
|
193
194
|
</div>
|
|
194
195
|
<div class="col-md-6">
|
|
@@ -201,6 +202,18 @@ prerender_icons:
|
|
|
201
202
|
</select>
|
|
202
203
|
</div>
|
|
203
204
|
</div>
|
|
205
|
+
|
|
206
|
+
<div class="mb-3">
|
|
207
|
+
<label for="campaign-discount-code" class="form-label">
|
|
208
|
+
Discount code
|
|
209
|
+
<small class="text-muted fw-normal ms-1">(optional — resolves {discount.code} and {discount.percent})</small>
|
|
210
|
+
</label>
|
|
211
|
+
<input type="text"
|
|
212
|
+
class="form-control"
|
|
213
|
+
id="campaign-discount-code"
|
|
214
|
+
name="campaign.discountCode"
|
|
215
|
+
placeholder="e.g. UPGRADE15">
|
|
216
|
+
</div>
|
|
204
217
|
</div>
|
|
205
218
|
|
|
206
219
|
<!-- Push-only fields -->
|
|
@@ -271,19 +284,6 @@ prerender_icons:
|
|
|
271
284
|
</div>
|
|
272
285
|
</div>
|
|
273
286
|
|
|
274
|
-
<!-- Discount Code -->
|
|
275
|
-
<div class="mb-3">
|
|
276
|
-
<label for="campaign-discount-code" class="form-label">
|
|
277
|
-
Discount code
|
|
278
|
-
<small class="text-muted fw-normal ms-1">(optional)</small>
|
|
279
|
-
</label>
|
|
280
|
-
<input type="text"
|
|
281
|
-
class="form-control"
|
|
282
|
-
id="campaign-discount-code"
|
|
283
|
-
name="campaign.discountCode"
|
|
284
|
-
placeholder="e.g. UPGRADE15">
|
|
285
|
-
</div>
|
|
286
|
-
|
|
287
287
|
<!-- Test Mode -->
|
|
288
288
|
<div class="form-check mb-4">
|
|
289
289
|
<input class="form-check-input"
|
|
@@ -300,12 +300,12 @@ prerender_icons:
|
|
|
300
300
|
|
|
301
301
|
<!-- Schedule -->
|
|
302
302
|
<h6 class="mb-3 mt-4">
|
|
303
|
-
{% uj_icon "clock", "
|
|
303
|
+
{% uj_icon "clock", "me-2 text-info" %}
|
|
304
304
|
Schedule
|
|
305
305
|
<small class="text-muted fw-normal ms-1">(UTC)</small>
|
|
306
306
|
</h6>
|
|
307
307
|
|
|
308
|
-
<div class="row mb-
|
|
308
|
+
<div class="row mb-2">
|
|
309
309
|
<div class="col-md-5">
|
|
310
310
|
<label for="campaign-date" class="form-label">
|
|
311
311
|
Date (UTC) <span class="text-danger">*</span>
|
|
@@ -330,16 +330,19 @@ prerender_icons:
|
|
|
330
330
|
<div class="invalid-feedback">Time is required</div>
|
|
331
331
|
</div>
|
|
332
332
|
<div class="col-md-3 d-flex align-items-end">
|
|
333
|
-
<button type="button" class="btn btn-
|
|
334
|
-
{% uj_icon "
|
|
335
|
-
|
|
333
|
+
<button type="button" class="btn btn-md btn-outline-primary w-100" id="btn-send-now">
|
|
334
|
+
{% uj_icon "clock", "fa-sm me-1" %}
|
|
335
|
+
Set now
|
|
336
336
|
</button>
|
|
337
337
|
</div>
|
|
338
338
|
</div>
|
|
339
|
+
<div class="mb-3" id="campaign-local-time-row" style="display:none">
|
|
340
|
+
<span class="badge bg-body-secondary text-body-secondary" id="campaign-time-local"></span>
|
|
341
|
+
</div>
|
|
339
342
|
|
|
340
343
|
<!-- Recurrence -->
|
|
341
344
|
<h6 class="mb-3 mt-4">
|
|
342
|
-
{% uj_icon "repeat", "
|
|
345
|
+
{% uj_icon "repeat", "me-2 text-info" %}
|
|
343
346
|
Recurrence
|
|
344
347
|
<small class="text-muted fw-normal ms-1">(optional)</small>
|
|
345
348
|
</h6>
|
|
@@ -361,20 +364,32 @@ prerender_icons:
|
|
|
361
364
|
<select class="form-select" id="campaign-recurrence-pattern" name="campaign.recurrence.pattern">
|
|
362
365
|
<option value="daily">Daily</option>
|
|
363
366
|
<option value="weekly">Weekly</option>
|
|
364
|
-
<option value="monthly" selected>Monthly</option>
|
|
367
|
+
<option value="monthly" selected>Monthly (day of month)</option>
|
|
368
|
+
<option value="monthly-weekday">Monthly (Nth weekday)</option>
|
|
365
369
|
<option value="quarterly">Quarterly</option>
|
|
366
370
|
<option value="yearly">Yearly</option>
|
|
367
371
|
</select>
|
|
368
372
|
</div>
|
|
369
373
|
<div class="col-md-4">
|
|
370
374
|
<label for="campaign-recurrence-hour" class="form-label">Hour (UTC)</label>
|
|
371
|
-
<
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
375
|
+
<div class="input-group">
|
|
376
|
+
<input type="number"
|
|
377
|
+
class="form-control"
|
|
378
|
+
id="campaign-recurrence-hour"
|
|
379
|
+
name="campaign.recurrence.hour"
|
|
380
|
+
value="14"
|
|
381
|
+
min="0"
|
|
382
|
+
max="23">
|
|
383
|
+
<span class="input-group-text">:</span>
|
|
384
|
+
<input type="number"
|
|
385
|
+
class="form-control"
|
|
386
|
+
id="campaign-recurrence-minute"
|
|
387
|
+
name="campaign.recurrence.minute"
|
|
388
|
+
value="0"
|
|
389
|
+
min="0"
|
|
390
|
+
max="59"
|
|
391
|
+
placeholder="Min">
|
|
392
|
+
</div>
|
|
378
393
|
</div>
|
|
379
394
|
<div class="col-md-4">
|
|
380
395
|
<label for="campaign-recurrence-day" class="form-label">
|
|
@@ -391,6 +406,18 @@ prerender_icons:
|
|
|
391
406
|
</div>
|
|
392
407
|
</div>
|
|
393
408
|
|
|
409
|
+
<div class="row mb-3 d-none" id="recurrence-nth-row">
|
|
410
|
+
<div class="col-md-4">
|
|
411
|
+
<label for="campaign-recurrence-nth" class="form-label">Occurrence</label>
|
|
412
|
+
<select class="form-select" id="campaign-recurrence-nth" name="campaign.recurrence.nth">
|
|
413
|
+
<option value="1">1st</option>
|
|
414
|
+
<option value="2" selected>2nd</option>
|
|
415
|
+
<option value="3">3rd</option>
|
|
416
|
+
<option value="4">4th</option>
|
|
417
|
+
</select>
|
|
418
|
+
</div>
|
|
419
|
+
</div>
|
|
420
|
+
|
|
394
421
|
<div class="row mb-3 d-none" id="recurrence-month-row">
|
|
395
422
|
<div class="col-md-4">
|
|
396
423
|
<label for="campaign-recurrence-month" class="form-label">Month</label>
|
|
@@ -418,7 +445,7 @@ prerender_icons:
|
|
|
418
445
|
|
|
419
446
|
<!-- Targeting -->
|
|
420
447
|
<h6 class="mb-3 mt-4">
|
|
421
|
-
{% uj_icon "users", "
|
|
448
|
+
{% uj_icon "users", "me-2 text-success" %}
|
|
422
449
|
Targeting
|
|
423
450
|
</h6>
|
|
424
451
|
|
|
@@ -472,32 +499,33 @@ prerender_icons:
|
|
|
472
499
|
|
|
473
500
|
<div class="mb-3">
|
|
474
501
|
<label for="campaign-segments" class="form-label">
|
|
475
|
-
|
|
476
|
-
<small class="text-muted fw-normal ms-1">(
|
|
502
|
+
Include segments
|
|
503
|
+
<small class="text-muted fw-normal ms-1">(AND — contacts must match ALL listed segments)</small>
|
|
477
504
|
</label>
|
|
478
505
|
<input type="text"
|
|
479
506
|
class="form-control"
|
|
480
507
|
id="campaign-segments"
|
|
481
508
|
name="campaign.segments"
|
|
482
|
-
placeholder="e.g.
|
|
509
|
+
placeholder="e.g. subscription_free, lifecycle_30d">
|
|
510
|
+
<small class="form-text text-muted">SSOT keys: subscription_free, subscription_paid, subscription_trialing, subscription_cancelled, subscription_churned_trial, subscription_churned_paid, lifecycle_7d, lifecycle_30d, engagement_active_30d, engagement_inactive_90d, etc.</small>
|
|
483
511
|
</div>
|
|
484
512
|
|
|
485
513
|
<div class="mb-3">
|
|
486
514
|
<label for="campaign-exclude-segments" class="form-label">
|
|
487
515
|
Exclude segments
|
|
488
|
-
<small class="text-muted fw-normal ms-1">(
|
|
516
|
+
<small class="text-muted fw-normal ms-1">(AND — contacts matching ANY excluded segment are removed)</small>
|
|
489
517
|
</label>
|
|
490
518
|
<input type="text"
|
|
491
519
|
class="form-control"
|
|
492
520
|
id="campaign-exclude-segments"
|
|
493
521
|
name="campaign.excludeSegments"
|
|
494
|
-
placeholder="e.g.
|
|
522
|
+
placeholder="e.g. subscription_paid, subscription_trialing">
|
|
495
523
|
</div>
|
|
496
524
|
|
|
497
525
|
<!-- Advanced Settings (collapsible) -->
|
|
498
526
|
<h6 class="mb-3 mt-4">
|
|
499
527
|
<a class="text-decoration-none" data-bs-toggle="collapse" href="#advanced-settings" role="button" aria-expanded="false">
|
|
500
|
-
{% uj_icon "sliders", "
|
|
528
|
+
{% uj_icon "sliders", "me-2 text-info" %}
|
|
501
529
|
Advanced settings
|
|
502
530
|
<small class="text-muted fw-normal ms-1">(optional)</small>
|
|
503
531
|
</a>
|
|
@@ -548,23 +576,26 @@ prerender_icons:
|
|
|
548
576
|
</div>
|
|
549
577
|
</div>
|
|
550
578
|
|
|
579
|
+
<div class="modal-footer d-flex justify-content-between">
|
|
580
|
+
<div>
|
|
581
|
+
<button type="submit" name="action" value="delete" formnovalidate class="btn btn-outline-danger d-none" id="btn-delete-campaign">
|
|
582
|
+
{% uj_icon "trash", "fa-sm me-1" %}
|
|
583
|
+
<span class="button-text">Delete</span>
|
|
584
|
+
</button>
|
|
585
|
+
</div>
|
|
586
|
+
<div class="d-flex gap-2">
|
|
587
|
+
<button type="submit" name="action" value="test" formnovalidate class="btn btn-outline-warning" id="btn-send-test">
|
|
588
|
+
{% uj_icon "vial", "fa-sm me-1" %}
|
|
589
|
+
<span class="button-text">Send test</span>
|
|
590
|
+
</button>
|
|
591
|
+
<button type="submit" name="action" value="save" class="btn btn-adaptive" id="btn-save-campaign">
|
|
592
|
+
{% uj_icon "paper-plane", "fa-sm me-1" %}
|
|
593
|
+
<span class="button-text">Save campaign</span>
|
|
594
|
+
</button>
|
|
595
|
+
</div>
|
|
596
|
+
</div>
|
|
551
597
|
</form>
|
|
552
598
|
</div>
|
|
553
|
-
<div class="modal-footer d-flex justify-content-between">
|
|
554
|
-
<div>
|
|
555
|
-
<button type="button" class="btn btn-outline-danger d-none" id="btn-delete-campaign">
|
|
556
|
-
{% uj_icon "trash", "fa-sm me-1" %}
|
|
557
|
-
Delete
|
|
558
|
-
</button>
|
|
559
|
-
</div>
|
|
560
|
-
<div class="d-flex gap-2">
|
|
561
|
-
<button type="button" class="btn btn-outline-adaptive" data-bs-dismiss="modal">Cancel</button>
|
|
562
|
-
<button type="submit" form="campaign-editor-form" class="btn btn-adaptive" id="btn-save-campaign">
|
|
563
|
-
{% uj_icon "paper-plane", "fa-sm me-1" %}
|
|
564
|
-
<span class="button-text">Save campaign</span>
|
|
565
|
-
</button>
|
|
566
|
-
</div>
|
|
567
|
-
</div>
|
|
568
599
|
</div>
|
|
569
600
|
</div>
|
|
570
601
|
</div>
|
|
@@ -1277,6 +1277,36 @@ badges:
|
|
|
1277
1277
|
</form>
|
|
1278
1278
|
</div>
|
|
1279
1279
|
</div>
|
|
1280
|
+
<div class="card mt-3">
|
|
1281
|
+
<div class="card-body">
|
|
1282
|
+
<div class="d-flex justify-content-between align-items-center mb-1">
|
|
1283
|
+
<h5 class="card-title mb-0">Push notifications</h5>
|
|
1284
|
+
<span id="push-notification-status"><span class="badge bg-secondary">Checking...</span></span>
|
|
1285
|
+
</div>
|
|
1286
|
+
<p class="text-muted small mb-3">Receive push notifications in your browser for important updates.</p>
|
|
1287
|
+
|
|
1288
|
+
<form id="push-subscribe-form" novalidate onsubmit="return false" style="display:none">
|
|
1289
|
+
<button type="submit" class="btn btn-adaptive btn-sm" id="push-subscribe-btn">
|
|
1290
|
+
{% uj_icon "bell", "me-1" %}
|
|
1291
|
+
<span class="button-text">Enable push notifications</span>
|
|
1292
|
+
</button>
|
|
1293
|
+
</form>
|
|
1294
|
+
|
|
1295
|
+
<div class="mt-3 pt-3 border-top">
|
|
1296
|
+
<a class="small text-muted text-decoration-none d-flex align-items-center" data-bs-toggle="collapse" href="#push-token-details" role="button" aria-expanded="false">
|
|
1297
|
+
{% uj_icon "code", "fa-xs me-1" %} Token details
|
|
1298
|
+
</a>
|
|
1299
|
+
<div class="collapse mt-2" id="push-token-details">
|
|
1300
|
+
<div class="input-group input-group-sm">
|
|
1301
|
+
<input type="text" class="form-control font-monospace bg-body-tertiary" id="push-token-value" readonly value="No token" style="font-size: 0.65rem;">
|
|
1302
|
+
<button type="button" class="btn btn-outline-adaptive" id="copy-push-token-btn">
|
|
1303
|
+
{% uj_icon "copy" %}
|
|
1304
|
+
</button>
|
|
1305
|
+
</div>
|
|
1306
|
+
</div>
|
|
1307
|
+
</div>
|
|
1308
|
+
</div>
|
|
1309
|
+
</div>
|
|
1280
1310
|
</section>
|
|
1281
1311
|
|
|
1282
1312
|
<!-- API Keys Section -->
|
|
@@ -17,8 +17,8 @@ const ujmConfig = Manager.getUJMConfig();
|
|
|
17
17
|
// Settings
|
|
18
18
|
const CACHE_DIR = '.temp/cache/imagemin';
|
|
19
19
|
const CACHE_BRANCH = 'cache-uj-imagemin';
|
|
20
|
-
const
|
|
21
|
-
const
|
|
20
|
+
const IMAGE_MAX_DIMENSION = 2048;
|
|
21
|
+
const IMAGE_JPEG_QUALITY = 80;
|
|
22
22
|
|
|
23
23
|
// Variables
|
|
24
24
|
let githubCache;
|
|
@@ -129,7 +129,7 @@ async function imagemin(complete) {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
// Optionally rewrite oversized source images on disk (opt-in via UJ_IMAGEMIN_REWRITE_SOURCES=true).
|
|
132
|
-
// Caps longest dimension at
|
|
132
|
+
// Caps longest dimension at IMAGE_MAX_DIMENSION so gulp-responsive-modern + sharp don't stall
|
|
133
133
|
// on huge inputs. Runs BEFORE determineFilesToProcess so cached-but-oversized images get
|
|
134
134
|
// rewritten too; the new on-disk content hashes differently than the stored meta hash, so
|
|
135
135
|
// determineFilesToProcess naturally picks the rewritten image up for re-optimization.
|
|
@@ -305,7 +305,7 @@ module.exports = series(
|
|
|
305
305
|
// Helper Functions
|
|
306
306
|
// ============================================================================
|
|
307
307
|
|
|
308
|
-
// Rewrite oversized source images in place, capping longest dimension at
|
|
308
|
+
// Rewrite oversized source images in place, capping longest dimension at IMAGE_MAX_DIMENSION.
|
|
309
309
|
// Only affects files whose decoded longest side exceeds the cap. Cache invalidation is implicit:
|
|
310
310
|
// the new content hashes differently than the previously-cached entry, so determineFilesToProcess
|
|
311
311
|
// will pick affected files up for re-optimization on its own.
|
|
@@ -315,14 +315,14 @@ async function rewriteOversizedSources(files) {
|
|
|
315
315
|
return;
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
-
logger.log(`🔍 Checking ${responsiveFiles.length} source images for oversize (>${
|
|
318
|
+
logger.log(`🔍 Checking ${responsiveFiles.length} source images for oversize (>${IMAGE_MAX_DIMENSION}px longest side)...`);
|
|
319
319
|
|
|
320
320
|
let rewritten = 0;
|
|
321
321
|
for (const file of responsiveFiles) {
|
|
322
322
|
const metadata = await sharp(file).metadata();
|
|
323
323
|
const longest = Math.max(metadata.width || 0, metadata.height || 0);
|
|
324
324
|
|
|
325
|
-
if (longest <=
|
|
325
|
+
if (longest <= IMAGE_MAX_DIMENSION) {
|
|
326
326
|
continue;
|
|
327
327
|
}
|
|
328
328
|
|
|
@@ -331,15 +331,15 @@ async function rewriteOversizedSources(files) {
|
|
|
331
331
|
|
|
332
332
|
// Resize, encode to a buffer (sharp can't write back to its own input file directly), then overwrite.
|
|
333
333
|
const pipeline = sharp(file).resize({
|
|
334
|
-
width:
|
|
335
|
-
height:
|
|
334
|
+
width: IMAGE_MAX_DIMENSION,
|
|
335
|
+
height: IMAGE_MAX_DIMENSION,
|
|
336
336
|
fit: 'inside',
|
|
337
337
|
withoutEnlargement: true,
|
|
338
338
|
});
|
|
339
339
|
|
|
340
340
|
const buffer = ext === 'png'
|
|
341
|
-
? await pipeline.png({ quality:
|
|
342
|
-
: await pipeline.jpeg({ quality:
|
|
341
|
+
? await pipeline.png({ quality: IMAGE_JPEG_QUALITY }).toBuffer()
|
|
342
|
+
: await pipeline.jpeg({ quality: IMAGE_JPEG_QUALITY, progressive: true, mozjpeg: true }).toBuffer();
|
|
343
343
|
|
|
344
344
|
jetpack.write(file, buffer);
|
|
345
345
|
const sizeAfter = buffer.length;
|
|
@@ -350,11 +350,11 @@ async function rewriteOversizedSources(files) {
|
|
|
350
350
|
// with the new hash when determineFilesToProcess() runs.
|
|
351
351
|
|
|
352
352
|
rewritten++;
|
|
353
|
-
logger.log(`✂️ Rewrote ${path.relative(rootPathProject, file)}: ${metadata.width}x${metadata.height} → max ${
|
|
353
|
+
logger.log(`✂️ Rewrote ${path.relative(rootPathProject, file)}: ${metadata.width}x${metadata.height} → max ${IMAGE_MAX_DIMENSION}px, ${formatBytes(sizeBefore)} → ${formatBytes(sizeAfter)}`);
|
|
354
354
|
}
|
|
355
355
|
|
|
356
356
|
if (rewritten === 0) {
|
|
357
|
-
logger.log(`✅ No oversized sources found (all within ${
|
|
357
|
+
logger.log(`✅ No oversized sources found (all within ${IMAGE_MAX_DIMENSION}px)`);
|
|
358
358
|
} else {
|
|
359
359
|
logger.log(`✂️ Rewrote ${rewritten} oversized source image(s)`);
|
|
360
360
|
}
|