ultimate-jekyll-manager 1.3.12 → 1.4.1
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 +31 -0
- package/CLAUDE.md +2 -2
- package/README.md +4 -0
- package/dist/assets/js/core/auth.js +14 -0
- package/dist/assets/js/libs/auth.js +62 -2
- package/dist/assets/js/libs/form-manager.js +10 -0
- package/dist/assets/themes/classy/css/components/_forms.scss +25 -1
- package/dist/defaults/dist/_alternatives/example-competitor.md +2 -2
- package/dist/defaults/dist/_includes/admin/sections/sidebar.json +1 -1
- package/dist/defaults/dist/_layouts/blueprint/admin/calendar/index.html +4 -4
- package/dist/defaults/dist/_layouts/blueprint/admin/firebase/index.html +2 -2
- package/dist/defaults/dist/_layouts/blueprint/admin/users/index.html +5 -5
- package/dist/defaults/dist/_layouts/blueprint/admin/users/new.html +3 -3
- package/dist/defaults/dist/_layouts/blueprint/legal/cookies.md +6 -6
- package/dist/defaults/dist/_layouts/blueprint/legal/terms.md +1 -1
- package/dist/defaults/dist/_layouts/blueprint/portal/email-preferences.html +2 -2
- package/dist/defaults/dist/_layouts/themes/classy/backend/pages/dashboard/index.html +5 -5
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/404.html +2 -2
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/about.html +3 -3
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +22 -22
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/alternatives/alternative.html +11 -11
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/alternatives/index.html +10 -10
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/app.html +4 -4
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/oauth2.html +3 -3
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/reset.html +3 -3
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signin.html +10 -9
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signup.html +8 -8
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/categories/category.html +2 -2
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/categories/index.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/tags/index.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/tags/tag.html +2 -2
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/contact.html +13 -13
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +13 -13
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/extension/index.html +7 -7
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/extension/installed.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/feedback.html +3 -3
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/index.html +29 -29
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/payment/checkout.html +16 -16
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/payment/confirmation.html +5 -5
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/portal/email-preferences.html +4 -4
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +40 -20
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/status.html +2 -2
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/team/index.html +10 -10
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/team/member.html +1 -1
- package/dist/defaults/dist/pages/test/account/dashboard.html +1 -1
- package/dist/defaults/dist/pages/test/components/hero-demo-custom.html +2 -2
- package/dist/defaults/dist/pages/test/components/hero-demo-form.html +4 -4
- package/dist/defaults/dist/pages/test/components/hero-demo-input.html +3 -3
- package/dist/defaults/dist/pages/test/components/hero-demo-side.html +2 -2
- package/dist/defaults/dist/pages/test/components/hero-demo-video.html +2 -2
- package/dist/defaults/dist/pages/test/index.md +2 -2
- package/dist/defaults/dist/pages/test/libraries/appearance.html +6 -6
- package/dist/defaults/dist/pages/test/libraries/bootstrap.html +99 -99
- package/dist/defaults/dist/pages/test/libraries/cover.html +4 -4
- package/dist/defaults/dist/pages/test/libraries/error.html +5 -5
- package/dist/defaults/dist/pages/test/libraries/firestore.html +2 -2
- package/dist/defaults/dist/pages/test/libraries/form-manager.html +9 -9
- package/dist/defaults/dist/pages/test/libraries/lazy-loading.html +9 -9
- package/dist/defaults/dist/pages/test/redirect/external.md +2 -2
- package/dist/defaults/dist/pages/test/redirect/internal.md +2 -2
- package/dist/defaults/dist/pages/test/translation/index.md +3 -3
- package/dist/defaults/src/_includes/backend/sections/sidebar.json +3 -3
- package/dist/defaults/src/_includes/frontend/sections/footer.json +5 -5
- package/dist/defaults/src/_includes/frontend/sections/nav.json +1 -1
- package/dist/defaults/src/_includes/global/sections/account.json +2 -2
- package/dist/gulp/main.js +5 -0
- package/dist/gulp/tasks/imagemin.js +160 -79
- package/dist/utils/attach-log-file.js +78 -0
- package/docs/images.md +27 -0
- package/docs/local-development.md +11 -0
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,37 @@ 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.4.1] - 2026-05-27
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **Bumped `puppeteer` `^24.43.1` → `^25.1.0`.** Puppeteer 25 is ESM-only and requires Node 22+; UJM's existing `require('puppeteer')` calls in [src/test/runners/boot.js](src/test/runners/boot.js) and [src/test/runners/chromium.js](src/test/runners/chromium.js) keep working via Node 22's native ESM-require interop.
|
|
23
|
+
- **Bumped `html-validate` `^10.17.0` → `^11.4.0`.** Used by [src/gulp/tasks/audit.js](src/gulp/tasks/audit.js); audit suite still passes.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
## [1.4.0] - 2026-05-27
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- **`UJ_IMAGEMIN_REWRITE_SOURCES=true` flag** (opt-in, off by default) — when set, the `imagemin` gulp task scans every image scheduled for processing and rewrites in place any whose longest dimension exceeds 4096px. Uses `sharp` with `fit: 'inside'` (aspect-preserving), JPEG quality 80 / mozjpeg / progressive, PNG quality 80. Cache hashes for affected files are updated so the new content becomes the new cache key. Intended as a one-off cleanup for repos with pre-existing oversized source images that silently stall `gulp-responsive-modern`/`sharp`. See [docs/images.md](docs/images.md#cleanup-for-existing-oversized-sources-uj_imagemin_rewrite_sources).
|
|
31
|
+
- **Log-file tee** (`src/utils/attach-log-file.js`): every line of stdout/stderr produced by the gulp pipeline is duplicated to `logs/dev.log` (during `npm start`) or `logs/build.log` (during `npm run build`) in the consumer project root. ANSI color codes are stripped from the file output; terminal output is unchanged. Files truncate fresh on each run. Skipped when `UJ_IS_SERVER=true` (CI/cloud) — no `logs/` directory is created in workspace contexts. Attached at the top of `src/gulp/main.js`. See [docs/local-development.md](docs/local-development.md#log-files).
|
|
32
|
+
- **Pricing page: 7-day money-back guarantee badge** under the billing toggle and per-card on each paid plan; free plan shows "Upgrade any time" with a rocket icon.
|
|
33
|
+
- **Pricing page: trial-aware CTA copy** — buttons now read "Get free trial" only when the plan's `trial.days > 0`, otherwise "Get started". Free plan stays "Get started". Avoids misleading users into thinking they need a trial for a free plan or that every paid plan offers one.
|
|
34
|
+
- **Auth: field-level error rendering.** New `isPasswordError()` and `passwordErrorMessage()` helpers in `src/assets/js/libs/auth.js` route Firebase password errors (`auth/weak-password`, `auth/missing-password`, `auth/wrong-password`, `auth/password-does-not-meet-requirements`) onto the password input via `FormManager.throwFieldErrors()` instead of the form-level banner. Signin: `auth/invalid-credential` | `auth/wrong-password` | `auth/user-not-found` highlight both email + password with "Incorrect email or password" (Firebase intentionally collapses these to prevent email enumeration). `auth/invalid-email` highlights the email field. Signup: when the email already exists and auto-signin fails, the message lands inline on the email field rather than throwing a generic banner error.
|
|
35
|
+
- **Dev-only consent-guard warning** in `src/assets/js/core/auth.js` `sendUserSignupMetadata` catch block: shows a `webManager.utilities().showNotification()` with the exact wall-clock time the consent guard will sign the user out (and remaining mm:ss) when the metadata POST fails. Wrapped in `/* @dev-only:start */` blocks so production builds strip it.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- **Sentence-case copy normalization** across ~60 layouts, pages, and section configs. Examples: "Sign Out" → "Sign out", "API Keys" → "API keys", "Save Changes" → "Save changes", "Contact Us" → "Contact us", "Main Menu" → "Main menu", "All Items" → "All items", "Admin Panel" → "Admin panel", "Sign Up" → "Sign up". Touches frontend pages (account, auth, contact, download, extension, index, payment, pricing, team, etc.), blueprint admin/legal/portal pages, test pages, and nav/footer/sidebar/account JSON section configs.
|
|
40
|
+
- **FormManager: `.has-validation` on input-group when a field is marked invalid.** Bootstrap requires this class on the wrapping `.input-group` so the trailing element (e.g. a password-visibility toggle) keeps its border-radius once a sibling `.invalid-feedback` is appended.
|
|
41
|
+
- **Classy theme forms SCSS:** restored rounded right corners on `.input-group.has-validation > *:nth-last-child(2)` so the visually-last interactive element keeps its `$classy-radius-lg`. Also added `.form-control.is-invalid:focus` override to keep the danger (red) focus ring instead of the brand-blue ring the classy theme was applying.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- **`imagemin` gulp task race condition (build mode):** the task was declared `async function imagemin(complete)` and returned a stream directly. Async functions wrap their return value in a Promise, so gulp resolved the task on the (already-resolved) Promise instead of waiting for the stream's `'finish'` event. Downstream tasks (jekyll, audit, minifyHtml) then started while imagemin was still writing to `dist/`, and jekyll would snapshot `_site/` before late images landed. Builds reported success while silently shipping a partial site. Fixed by explicitly `await`ing stream completion via `new Promise((resolve, reject) => { ... .on('finish', resolve).on('error', reject) })` before moving to the cache-push step, then `return complete()`. The wait only ever runs in build mode (dev mode short-circuits earlier in the task), so `npm start` startup is unaffected.
|
|
46
|
+
- **Oversized source images silently failing to land in `_site/`.** Source images with very large dimensions (10000px+ longest side) decode into hundreds of MB per worker in `sharp`, which can stall the `gulp-responsive-modern` stream so quietly that gulp reports the task complete. The build appears successful but some images never reach `_site/`. Documented the constraint and the new `UJ_IMAGEMIN_REWRITE_SOURCES` cleanup flag in [docs/images.md](docs/images.md). Recommended fix is to cap images at the upload step; the rewrite flag is a fallback for cleaning up existing repos.
|
|
47
|
+
|
|
17
48
|
---
|
|
18
49
|
## [1.3.12] - 2026-05-25
|
|
19
50
|
|
package/CLAUDE.md
CHANGED
|
@@ -192,13 +192,13 @@ Deep references live in `docs/`. Treat docs as a first-class deliverable. **When
|
|
|
192
192
|
### Project & dev environment
|
|
193
193
|
|
|
194
194
|
- [docs/project-structure.md](docs/project-structure.md) — UJM repo layout and consuming-project layout
|
|
195
|
-
- [docs/local-development.md](docs/local-development.md) — browsersync URL, Firebase emulator connect, PurgeCSS safelist
|
|
195
|
+
- [docs/local-development.md](docs/local-development.md) — browsersync URL, Firebase emulator connect, PurgeCSS safelist, log files (`logs/dev.log`, `logs/build.log`)
|
|
196
196
|
- [docs/assets.md](docs/assets.md) — UJM vs consumer file layout, section config (nav/footer/account), frontmatter-driven page customization, webpack aliases, page module pattern
|
|
197
197
|
|
|
198
198
|
### Pages, layouts, content
|
|
199
199
|
|
|
200
200
|
- [docs/layouts-and-pages.md](docs/layouts-and-pages.md) — page types, layout chain, `asset_path` frontmatter
|
|
201
|
-
- [docs/images.md](docs/images.md) — `@post/` shortcut for blog post images, BEM admin/post image handling
|
|
201
|
+
- [docs/images.md](docs/images.md) — `@post/` shortcut for blog post images, BEM admin/post image handling, imagemin pipeline + source-size constraints + `UJ_IMAGEMIN_REWRITE_SOURCES` cleanup flag
|
|
202
202
|
- [docs/icons.md](docs/icons.md) — Font Awesome conventions, `{% uj_icon %}` vs prerendered icons in JS, size reference
|
|
203
203
|
- [docs/seo.md](docs/seo.md) — Alternatives collection (competitor comparison pages) + Schema/JSON-LD (`SoftwareApplication`, `FAQPage`)
|
|
204
204
|
|
package/README.md
CHANGED
|
@@ -113,6 +113,8 @@ npm start -- --all-posts
|
|
|
113
113
|
### Other ENV variables
|
|
114
114
|
```bash
|
|
115
115
|
UJ_PURGECSS=true # Enables PurgeCSS to remove unused CSS (normally only happens in production builds)
|
|
116
|
+
UJ_IMAGEMIN_CACHE=false # Disables the GitHub-backed imagemin cache (forces local processing)
|
|
117
|
+
UJ_IMAGEMIN_REWRITE_SOURCES=true # One-off cleanup: shrinks oversized source images (>4096px) in place. See docs/images.md
|
|
116
118
|
```
|
|
117
119
|
|
|
118
120
|
## Running Specific Tasks
|
|
@@ -168,6 +170,8 @@ The imagemin task will:
|
|
|
168
170
|
- Cache processed images in `cache-imagemin` branch (when using GitHub cache)
|
|
169
171
|
- Skip already processed images on subsequent runs
|
|
170
172
|
|
|
173
|
+
**Keep sources reasonably sized.** Source images larger than ~4096px on the longest side can stall `sharp`/`gulp-responsive-modern` in a way gulp can't detect, causing them to silently fail to land in `_site/`. Cap images at the upload step where possible. For one-off cleanup of an existing repo, run with `UJ_IMAGEMIN_REWRITE_SOURCES=true npm run build` — see [docs/images.md](docs/images.md#cleanup-for-existing-oversized-sources-uj_imagemin_rewrite_sources) for details.
|
|
174
|
+
|
|
171
175
|
<!-- Developing -->
|
|
172
176
|
## 🛠 Developing
|
|
173
177
|
1. Clone the repo to your local machine.
|
|
@@ -320,6 +320,20 @@ async function sendUserSignupMetadata(user) {
|
|
|
320
320
|
} catch (error) {
|
|
321
321
|
console.error('[Auth] Error sending user metadata:', error);
|
|
322
322
|
// Don't throw - we don't want to block the signup flow
|
|
323
|
+
|
|
324
|
+
/* @dev-only:start */
|
|
325
|
+
{
|
|
326
|
+
const accountAge = Date.now() - new Date(user.metadata.creationTime).getTime();
|
|
327
|
+
const msRemaining = Math.max(0, SIGNUP_MAX_AGE - accountAge);
|
|
328
|
+
const signoutAt = new Date(Date.now() + msRemaining).toLocaleTimeString();
|
|
329
|
+
const minutes = Math.floor(msRemaining / 1000 / 60);
|
|
330
|
+
const seconds = Math.floor((msRemaining / 1000) % 60);
|
|
331
|
+
webManager.utilities().showNotification(
|
|
332
|
+
`[DEV] Failed to send signup metadata. User will be signed out by consent guard at ${signoutAt} (in ${minutes}m ${seconds}s) unless retried.`,
|
|
333
|
+
{ type: 'warning', timeout: 0 }
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
/* @dev-only:end */
|
|
323
337
|
}
|
|
324
338
|
}
|
|
325
339
|
|
|
@@ -530,8 +530,9 @@ export default function () {
|
|
|
530
530
|
formManager.showSuccess('Successfully signed in!');
|
|
531
531
|
return;
|
|
532
532
|
} catch (signInError) {
|
|
533
|
-
//
|
|
534
|
-
|
|
533
|
+
// Couldn't auto-sign-them-in — surface inline on the email field so
|
|
534
|
+
// the user sees exactly which input is the problem.
|
|
535
|
+
formManager.throwFieldErrors({ email: 'An account with this email already exists' });
|
|
535
536
|
}
|
|
536
537
|
}
|
|
537
538
|
|
|
@@ -542,6 +543,12 @@ export default function () {
|
|
|
542
543
|
throw new Error(blockingMessage);
|
|
543
544
|
}
|
|
544
545
|
|
|
546
|
+
// Password-specific Firebase errors should land on the password field, not
|
|
547
|
+
// the form-level banner — gives the user a clear "fix this input" signal.
|
|
548
|
+
if (isPasswordError(error.code)) {
|
|
549
|
+
formManager.throwFieldErrors({ password: passwordErrorMessage(error) });
|
|
550
|
+
}
|
|
551
|
+
|
|
545
552
|
// Re-throw the error to be handled by the form handler
|
|
546
553
|
throw error;
|
|
547
554
|
}
|
|
@@ -573,6 +580,27 @@ export default function () {
|
|
|
573
580
|
if (blockingMessage) {
|
|
574
581
|
throw new Error(blockingMessage);
|
|
575
582
|
}
|
|
583
|
+
|
|
584
|
+
// Firebase intentionally collapses wrong-email and wrong-password into a
|
|
585
|
+
// single `auth/invalid-credential` to prevent email enumeration. Since we
|
|
586
|
+
// don't know which field is wrong, highlight both with a shared message.
|
|
587
|
+
if (error.code === 'auth/invalid-credential' || error.code === 'auth/wrong-password' || error.code === 'auth/user-not-found') {
|
|
588
|
+
formManager.throwFieldErrors({
|
|
589
|
+
email: 'Incorrect email or password',
|
|
590
|
+
password: 'Incorrect email or password',
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Password-format errors on the password field (e.g. missing).
|
|
595
|
+
if (isPasswordError(error.code)) {
|
|
596
|
+
formManager.throwFieldErrors({ password: passwordErrorMessage(error) });
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Bad email format → email field.
|
|
600
|
+
if (error.code === 'auth/invalid-email') {
|
|
601
|
+
formManager.throwFieldErrors({ email: 'Please enter a valid email address' });
|
|
602
|
+
}
|
|
603
|
+
|
|
576
604
|
throw error;
|
|
577
605
|
}
|
|
578
606
|
}
|
|
@@ -794,6 +822,38 @@ export default function () {
|
|
|
794
822
|
});
|
|
795
823
|
}
|
|
796
824
|
|
|
825
|
+
// Firebase password-related auth error codes — these belong on the password
|
|
826
|
+
// field, not the form-level error banner.
|
|
827
|
+
function isPasswordError(errorCode) {
|
|
828
|
+
return [
|
|
829
|
+
'auth/weak-password',
|
|
830
|
+
'auth/missing-password',
|
|
831
|
+
'auth/wrong-password',
|
|
832
|
+
'auth/password-does-not-meet-requirements',
|
|
833
|
+
].includes(errorCode);
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// Map a Firebase password error to a short, field-appropriate message.
|
|
837
|
+
function passwordErrorMessage(error) {
|
|
838
|
+
if (error?.code === 'auth/weak-password') {
|
|
839
|
+
return 'Password is too weak. Use at least 6 characters.';
|
|
840
|
+
}
|
|
841
|
+
if (error?.code === 'auth/missing-password') {
|
|
842
|
+
return 'Password is required';
|
|
843
|
+
}
|
|
844
|
+
if (error?.code === 'auth/wrong-password') {
|
|
845
|
+
return 'Incorrect password';
|
|
846
|
+
}
|
|
847
|
+
if (error?.code === 'auth/password-does-not-meet-requirements') {
|
|
848
|
+
// Firebase message looks like: "Firebase: Missing password requirements:
|
|
849
|
+
// [Password must contain at least 8 characters] (auth/...)." Pull the
|
|
850
|
+
// bracketed list so the user sees the actual rule(s) they missed.
|
|
851
|
+
const match = error?.message?.match(/\[([^\]]+)\]/);
|
|
852
|
+
return match ? match[1] : 'Password does not meet the requirements';
|
|
853
|
+
}
|
|
854
|
+
return error?.message || 'Invalid password';
|
|
855
|
+
}
|
|
856
|
+
|
|
797
857
|
// Helper function to determine if an error is a user error
|
|
798
858
|
function isUserError(errorCode) {
|
|
799
859
|
const userErrors = [
|
|
@@ -595,6 +595,16 @@ export class FormManager {
|
|
|
595
595
|
// Add invalid class to field
|
|
596
596
|
$field.classList.add('is-invalid');
|
|
597
597
|
|
|
598
|
+
// Bootstrap requires `.has-validation` on the wrapping `.input-group` so the
|
|
599
|
+
// trailing element (e.g. a password-visibility toggle button) keeps its
|
|
600
|
+
// border-radius once a sibling `.invalid-feedback` is rendered. Without
|
|
601
|
+
// this, the appended feedback makes the trailing button no longer
|
|
602
|
+
// `:last-child` and Bootstrap strips its right corners to 0.
|
|
603
|
+
const $inputGroup = $field.closest('.input-group');
|
|
604
|
+
if ($inputGroup) {
|
|
605
|
+
$inputGroup.classList.add('has-validation');
|
|
606
|
+
}
|
|
607
|
+
|
|
598
608
|
// Find or create feedback element
|
|
599
609
|
let $feedback = $field.parentElement.querySelector('.invalid-feedback');
|
|
600
610
|
if (!$feedback) {
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
// Input Groups
|
|
6
6
|
// ============================================
|
|
7
7
|
.input-group {
|
|
8
|
-
> .form-control
|
|
8
|
+
> .form-control,
|
|
9
|
+
> .form-control.is-invalid {
|
|
9
10
|
border-radius: $classy-radius-lg;
|
|
10
11
|
|
|
11
12
|
&:not(:last-child) {
|
|
@@ -60,6 +61,21 @@
|
|
|
60
61
|
border-bottom-left-radius: 0;
|
|
61
62
|
}
|
|
62
63
|
}
|
|
64
|
+
|
|
65
|
+
// When FormManager appends a sibling `.invalid-feedback` inside the
|
|
66
|
+
// input-group, the trailing button/input-group-text is no longer
|
|
67
|
+
// `:last-child` and the rules above strip its right border-radius.
|
|
68
|
+
// Bootstrap signals this layout with `.has-validation` on the input-group;
|
|
69
|
+
// restore the rounded right corners for the visually-last interactive
|
|
70
|
+
// element (the `:nth-last-child(2)` — i.e. the element before the feedback).
|
|
71
|
+
&.has-validation {
|
|
72
|
+
> .btn:nth-last-child(2),
|
|
73
|
+
> .input-group-text:nth-last-child(2),
|
|
74
|
+
> .form-control:nth-last-child(2) {
|
|
75
|
+
border-top-right-radius: $classy-radius-lg;
|
|
76
|
+
border-bottom-right-radius: $classy-radius-lg;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
63
79
|
}
|
|
64
80
|
|
|
65
81
|
// ============================================
|
|
@@ -78,6 +94,14 @@
|
|
|
78
94
|
background-color: var(--bs-body-bg);
|
|
79
95
|
}
|
|
80
96
|
|
|
97
|
+
// Keep danger styling visible when an invalid field is focused. Without this
|
|
98
|
+
// override the classy `:focus` rule above wins on specificity and the user
|
|
99
|
+
// sees the brand-blue ring instead of the red one Bootstrap normally applies.
|
|
100
|
+
&.is-invalid:focus {
|
|
101
|
+
border-color: $danger;
|
|
102
|
+
box-shadow: 0 0 0 0.25rem rgba($danger, 0.25);
|
|
103
|
+
}
|
|
104
|
+
|
|
81
105
|
// // Override Chrome/Safari autofill background color with subtle indicator
|
|
82
106
|
&:-webkit-autofill,
|
|
83
107
|
&:-webkit-autofill:hover,
|
|
@@ -42,13 +42,13 @@ alternative:
|
|
|
42
42
|
value: "Full REST API"
|
|
43
43
|
theirs:
|
|
44
44
|
value: "Limited"
|
|
45
|
-
- name: "Custom
|
|
45
|
+
- name: "Custom branding"
|
|
46
46
|
icon: "palette"
|
|
47
47
|
ours:
|
|
48
48
|
value: true
|
|
49
49
|
theirs:
|
|
50
50
|
value: false
|
|
51
|
-
- name: "Priority
|
|
51
|
+
- name: "Priority support"
|
|
52
52
|
icon: "headset"
|
|
53
53
|
ours:
|
|
54
54
|
value: "24/7"
|
|
@@ -78,7 +78,7 @@ prerender_icons:
|
|
|
78
78
|
<div class="modal-header">
|
|
79
79
|
<h5 class="modal-title" id="campaign-modal-title">
|
|
80
80
|
{% uj_icon "plus", "fa-md me-2" %}
|
|
81
|
-
<span id="campaign-modal-title-text">Create
|
|
81
|
+
<span id="campaign-modal-title-text">Create campaign</span>
|
|
82
82
|
</h5>
|
|
83
83
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
84
84
|
</div>
|
|
@@ -561,7 +561,7 @@ prerender_icons:
|
|
|
561
561
|
<button type="button" class="btn btn-outline-adaptive" data-bs-dismiss="modal">Cancel</button>
|
|
562
562
|
<button type="submit" form="campaign-editor-form" class="btn btn-adaptive" id="btn-save-campaign">
|
|
563
563
|
{% uj_icon "paper-plane", "fa-sm me-1" %}
|
|
564
|
-
<span class="button-text">Save
|
|
564
|
+
<span class="button-text">Save campaign</span>
|
|
565
565
|
</button>
|
|
566
566
|
</div>
|
|
567
567
|
</div>
|
|
@@ -576,7 +576,7 @@ prerender_icons:
|
|
|
576
576
|
<div class="modal-header">
|
|
577
577
|
<h5 class="modal-title" id="campaign-results-title">
|
|
578
578
|
{% uj_icon "eye", "fa-md me-2" %}
|
|
579
|
-
<span id="campaign-results-title-text">Campaign
|
|
579
|
+
<span id="campaign-results-title-text">Campaign details</span>
|
|
580
580
|
</h5>
|
|
581
581
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
582
582
|
</div>
|
|
@@ -586,7 +586,7 @@ prerender_icons:
|
|
|
586
586
|
<div class="modal-footer">
|
|
587
587
|
<button type="button" class="btn btn-outline-danger d-none" id="btn-retry-campaign">
|
|
588
588
|
{% uj_icon "rotate-right", "fa-sm me-1" %}
|
|
589
|
-
Retry (Create
|
|
589
|
+
Retry (Create new)
|
|
590
590
|
</button>
|
|
591
591
|
<button type="button" class="btn btn-outline-adaptive" data-bs-dismiss="modal">Close</button>
|
|
592
592
|
</div>
|
|
@@ -56,7 +56,7 @@ prerender_icons:
|
|
|
56
56
|
<h6 class="mb-0">{% uj_icon "database", "fa-sm me-2" %} Collections</h6>
|
|
57
57
|
</div>
|
|
58
58
|
<div class="card-body p-2">
|
|
59
|
-
<!-- Quick
|
|
59
|
+
<!-- Quick access -->
|
|
60
60
|
<div class="nav flex-column collection-nav" id="collection-links">
|
|
61
61
|
<a href="#" class="nav-link px-2 py-1 d-flex justify-content-between align-items-center" data-collection="users">
|
|
62
62
|
{% uj_icon "folder", "fa-sm me-2" %} users
|
|
@@ -127,7 +127,7 @@ prerender_icons:
|
|
|
127
127
|
</div>
|
|
128
128
|
<button type="submit" class="btn btn-sm btn-adaptive w-100">
|
|
129
129
|
{% uj_icon "magnifying-glass", "fa-sm me-2" %}
|
|
130
|
-
<span class="button-text">Run
|
|
130
|
+
<span class="button-text">Run query</span>
|
|
131
131
|
</button>
|
|
132
132
|
</form>
|
|
133
133
|
<button class="btn btn-sm btn-outline-adaptive w-100 mt-2 d-none" id="btn-clear-query">
|
|
@@ -84,7 +84,7 @@ prerender_icons:
|
|
|
84
84
|
</div>
|
|
85
85
|
</div>
|
|
86
86
|
|
|
87
|
-
<!-- Active
|
|
87
|
+
<!-- Active users (30d) -->
|
|
88
88
|
<div class="col-lg-4 col-md-6">
|
|
89
89
|
<div class="card h-100">
|
|
90
90
|
<div class="card-body text-center">
|
|
@@ -164,7 +164,7 @@ prerender_icons:
|
|
|
164
164
|
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
|
165
165
|
<div class="modal-content">
|
|
166
166
|
<div class="modal-header">
|
|
167
|
-
<h6 class="modal-title" id="user-detail-modal-label">User
|
|
167
|
+
<h6 class="modal-title" id="user-detail-modal-label">User details</h6>
|
|
168
168
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
169
169
|
</div>
|
|
170
170
|
<div class="modal-body p-0">
|
|
@@ -185,7 +185,7 @@ prerender_icons:
|
|
|
185
185
|
</div>
|
|
186
186
|
</div>
|
|
187
187
|
|
|
188
|
-
<!-- Sign
|
|
188
|
+
<!-- Sign in as user modal -->
|
|
189
189
|
<div class="modal fade" id="signin-as-modal" tabindex="-1" aria-labelledby="signin-as-modal-label" aria-hidden="true">
|
|
190
190
|
<div class="modal-dialog modal-dialog-centered">
|
|
191
191
|
<div class="modal-content">
|
|
@@ -248,7 +248,7 @@ prerender_icons:
|
|
|
248
248
|
<div class="modal-dialog">
|
|
249
249
|
<div class="modal-content">
|
|
250
250
|
<div class="modal-header">
|
|
251
|
-
<h6 class="modal-title" id="user-edit-modal-label">Edit
|
|
251
|
+
<h6 class="modal-title" id="user-edit-modal-label">Edit user</h6>
|
|
252
252
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
253
253
|
</div>
|
|
254
254
|
<div class="modal-body">
|
|
@@ -292,7 +292,7 @@ prerender_icons:
|
|
|
292
292
|
<button type="button" class="btn btn-sm btn-outline-adaptive" data-bs-dismiss="modal">Cancel</button>
|
|
293
293
|
<button type="submit" class="btn btn-sm btn-adaptive">
|
|
294
294
|
{% uj_icon "check", "fa-sm me-1" %}
|
|
295
|
-
<span class="button-text">Save
|
|
295
|
+
<span class="button-text">Save changes</span>
|
|
296
296
|
</button>
|
|
297
297
|
</div>
|
|
298
298
|
</form>
|
|
@@ -36,12 +36,12 @@ meta:
|
|
|
36
36
|
<div class="col-lg-7">
|
|
37
37
|
<div class="card">
|
|
38
38
|
<div class="card-header">
|
|
39
|
-
<h5 class="mb-0">Create
|
|
39
|
+
<h5 class="mb-0">Create new user</h5>
|
|
40
40
|
</div>
|
|
41
41
|
<div class="card-body">
|
|
42
42
|
<form id="create-user-form" novalidate onsubmit="return false">
|
|
43
43
|
<div class="mb-3">
|
|
44
|
-
<label for="email" class="form-label">Email
|
|
44
|
+
<label for="email" class="form-label">Email address <span class="text-danger">*</span></label>
|
|
45
45
|
<input type="email" class="form-control" id="email" name="user.email" required autofocus>
|
|
46
46
|
</div>
|
|
47
47
|
<div class="row">
|
|
@@ -61,7 +61,7 @@ meta:
|
|
|
61
61
|
<a href="/admin/users" class="btn btn-outline-adaptive">Cancel</a>
|
|
62
62
|
<button type="submit" class="btn btn-adaptive">
|
|
63
63
|
{% uj_icon "check", "fa-md me-2" %}
|
|
64
|
-
<span class="button-text">Create
|
|
64
|
+
<span class="button-text">Create user</span>
|
|
65
65
|
</button>
|
|
66
66
|
</div>
|
|
67
67
|
</form>
|
|
@@ -25,7 +25,7 @@ web_manager:
|
|
|
25
25
|
</p>
|
|
26
26
|
|
|
27
27
|
<p>
|
|
28
|
-
<strong>What
|
|
28
|
+
<strong>What are cookies</strong>
|
|
29
29
|
</p>
|
|
30
30
|
|
|
31
31
|
<p>
|
|
@@ -38,7 +38,7 @@ web_manager:
|
|
|
38
38
|
</p>
|
|
39
39
|
|
|
40
40
|
<p>
|
|
41
|
-
<strong>How
|
|
41
|
+
<strong>How we use cookies</strong>
|
|
42
42
|
</p>
|
|
43
43
|
|
|
44
44
|
<p>
|
|
@@ -47,7 +47,7 @@ web_manager:
|
|
|
47
47
|
</p>
|
|
48
48
|
|
|
49
49
|
<p>
|
|
50
|
-
<strong>Disabling
|
|
50
|
+
<strong>Disabling cookies</strong>
|
|
51
51
|
</p>
|
|
52
52
|
|
|
53
53
|
<p>
|
|
@@ -57,7 +57,7 @@ web_manager:
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
<p>
|
|
60
|
-
<strong>The
|
|
60
|
+
<strong>The cookies we set</strong>
|
|
61
61
|
</p>
|
|
62
62
|
|
|
63
63
|
<ul>
|
|
@@ -133,7 +133,7 @@ web_manager:
|
|
|
133
133
|
</ul>
|
|
134
134
|
|
|
135
135
|
<p>
|
|
136
|
-
<strong>Third
|
|
136
|
+
<strong>Third party cookies</strong>
|
|
137
137
|
</p>
|
|
138
138
|
|
|
139
139
|
<p>
|
|
@@ -191,7 +191,7 @@ web_manager:
|
|
|
191
191
|
{{ content | uj_content_format }}
|
|
192
192
|
|
|
193
193
|
<p>
|
|
194
|
-
<strong>More
|
|
194
|
+
<strong>More information</strong>
|
|
195
195
|
</p>
|
|
196
196
|
|
|
197
197
|
<p>
|
|
@@ -122,7 +122,7 @@ Upon cancellation, you will not be charged any further subscription fees. No pay
|
|
|
122
122
|
|
|
123
123
|
Any other purchases, including one-time payments, add-ons, or other sales on our site that do not include a free trial period are final and non-refundable once processed.
|
|
124
124
|
|
|
125
|
-
Should you request a refund, we will determine the eligibility of your refund. If approved, you will be refunded via the same payment method you originally used. Requests can be made using our [refund request form](
|
|
125
|
+
Should you request a refund, we will determine the eligibility of your refund. If approved, you will be refunded via the same payment method you originally used. Requests can be made using our [refund request form]({{ site.url }}/account#refund).
|
|
126
126
|
|
|
127
127
|
### Debt Collection
|
|
128
128
|
In the event of an outstanding balance on your account, we reserve the right to engage debt collection agencies to recover the unpaid amount.
|
|
@@ -4,9 +4,9 @@ layout: themes/[ site.theme.id ]/frontend/pages/portal/email-preferences
|
|
|
4
4
|
|
|
5
5
|
### REGULAR PAGES ###
|
|
6
6
|
meta:
|
|
7
|
-
title: "Email
|
|
7
|
+
title: "Email preferences - {{ site.brand.name }}"
|
|
8
8
|
description: "Manage your email preferences for {{ site.brand.name }}."
|
|
9
|
-
breadcrumb: "Email
|
|
9
|
+
breadcrumb: "Email preferences"
|
|
10
10
|
|
|
11
11
|
### MISC ###
|
|
12
12
|
sitemap:
|
|
@@ -101,7 +101,7 @@ recent_activity:
|
|
|
101
101
|
|
|
102
102
|
quick_actions:
|
|
103
103
|
- id: "create_project"
|
|
104
|
-
label: "Create
|
|
104
|
+
label: "Create new project"
|
|
105
105
|
icon: "plus"
|
|
106
106
|
style: "primary"
|
|
107
107
|
href: "#"
|
|
@@ -113,7 +113,7 @@ quick_actions:
|
|
|
113
113
|
href: "#"
|
|
114
114
|
|
|
115
115
|
- id: "invite_members"
|
|
116
|
-
label: "Invite
|
|
116
|
+
label: "Invite team members"
|
|
117
117
|
icon: "users"
|
|
118
118
|
style: "outline-adaptive"
|
|
119
119
|
href: "#"
|
|
@@ -176,7 +176,7 @@ progress_items:
|
|
|
176
176
|
<div class="col-lg-8">
|
|
177
177
|
<div class="card">
|
|
178
178
|
<div class="card-body">
|
|
179
|
-
<h5 class="mb-3">Recent
|
|
179
|
+
<h5 class="mb-3">Recent activity</h5>
|
|
180
180
|
<div class="list-group list-group-flush">
|
|
181
181
|
{% for activity in page.resolved.recent_activity %}
|
|
182
182
|
<div class="list-group-item bg-body-tertiary px-0">
|
|
@@ -205,7 +205,7 @@ progress_items:
|
|
|
205
205
|
<div class="col-lg-4">
|
|
206
206
|
<div class="card">
|
|
207
207
|
<div class="card-body">
|
|
208
|
-
<h5 class="mb-3">Quick
|
|
208
|
+
<h5 class="mb-3">Quick actions</h5>
|
|
209
209
|
<div class="d-grid gap-2">
|
|
210
210
|
{% for action in page.resolved.quick_actions %}
|
|
211
211
|
{% if action.href %}
|
|
@@ -227,7 +227,7 @@ progress_items:
|
|
|
227
227
|
<!-- Progress Overview -->
|
|
228
228
|
<div class="card mt-3">
|
|
229
229
|
<div class="card-body">
|
|
230
|
-
<h5 class="mb-3">Progress
|
|
230
|
+
<h5 class="mb-3">Progress overview</h5>
|
|
231
231
|
{% for item in page.resolved.progress_items %}
|
|
232
232
|
<div class="mb-3">
|
|
233
233
|
<div class="d-flex justify-content-between mb-1">
|
|
@@ -45,11 +45,11 @@ suggested_pages:
|
|
|
45
45
|
<div class="d-grid gap-2 d-sm-block text-center mb-4">
|
|
46
46
|
<a href="{{ site.url }}" class="btn btn-adaptive btn-lg mb-2 mb-sm-0 me-sm-2">
|
|
47
47
|
{% uj_icon "house", "me-2" %}
|
|
48
|
-
Back to
|
|
48
|
+
Back to home
|
|
49
49
|
</a>
|
|
50
50
|
<button class="btn btn-outline-adaptive btn-lg mb-2 mb-sm-0" onclick="window.history.back()">
|
|
51
51
|
{% uj_icon "arrow-left", "me-2" %}
|
|
52
|
-
Go
|
|
52
|
+
Go back
|
|
53
53
|
</button>
|
|
54
54
|
</div>
|
|
55
55
|
|
|
@@ -58,10 +58,10 @@ stats:
|
|
|
58
58
|
label: "Founded"
|
|
59
59
|
icon: "calendar"
|
|
60
60
|
- number: "50+"
|
|
61
|
-
label: "Team
|
|
61
|
+
label: "Team members"
|
|
62
62
|
icon: "users"
|
|
63
63
|
- number: "1M+"
|
|
64
|
-
label: "Happy
|
|
64
|
+
label: "Happy customers"
|
|
65
65
|
icon: "smile"
|
|
66
66
|
- number: "120+"
|
|
67
67
|
label: "Countries"
|
|
@@ -98,7 +98,7 @@ team_cta:
|
|
|
98
98
|
headline_accent: "team"
|
|
99
99
|
subheadline: "Get to know the passionate individuals behind {{ site.brand.name }} who work every day to make your experience exceptional"
|
|
100
100
|
button:
|
|
101
|
-
text: "Meet the
|
|
101
|
+
text: "Meet the team"
|
|
102
102
|
icon: "arrow-right"
|
|
103
103
|
href: "/team"
|
|
104
104
|
---
|