ultimate-jekyll-manager 0.0.130 → 0.0.132
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 +19 -0
- package/README.md +17 -0
- package/dist/assets/js/libs/auth.js +23 -5
- package/dist/assets/js/libs/form-manager.js +6 -0
- package/dist/assets/themes/classy/css/layout/_navigation.scss +2 -1
- package/dist/commands/migrate.js +72 -1
- package/dist/config/_config_default.yml +1 -1
- package/dist/config/_config_development.yml +3 -2
- package/dist/defaults/dist/_includes/core/foot.html +1 -1
- package/dist/defaults/dist/_includes/themes/classy/frontend/sections/nav.html +5 -5
- package/dist/defaults/dist/_layouts/core/root.html +5 -0
- package/dist/defaults/dist/_layouts/modules/utilities/redirect.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +6 -6
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/reset.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signin.html +2 -2
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signup.html +2 -2
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/index.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +4 -3
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/team/index.html +8 -26
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/team/member.html +8 -26
- package/dist/defaults/dist/_team/alex-raeburn.md +39 -0
- package/dist/defaults/dist/_team/alfred-caufy.md +40 -0
- package/dist/defaults/dist/_team/ian-wiedenman.md +46 -0
- package/dist/defaults/dist/_team/james-oconnor.md +39 -0
- package/dist/defaults/dist/_team/marcus-johnson.md +43 -0
- package/dist/defaults/dist/_team/priya-sharma.md +42 -0
- package/dist/defaults/dist/_team/rare-ivy.md +48 -0
- package/dist/defaults/dist/_team/sarah-rodriguez.md +45 -0
- package/dist/defaults/dist/pages/test/libraries/form-manager.html +23 -23
- package/dist/defaults/src/assets/images/team/alex-raeburn/profile.jpg +0 -0
- package/dist/defaults/src/assets/images/team/alfred-caufy/profile.jpg +0 -0
- package/dist/defaults/src/assets/images/team/christina-hill/profile.jpg +0 -0
- package/dist/defaults/src/assets/images/team/james-oconnor/profile.jpg +0 -0
- package/dist/defaults/src/assets/images/team/marcus-johnson/profile.jpg +0 -0
- package/dist/defaults/src/assets/images/team/priya-sharma/profile.jpg +0 -0
- package/dist/defaults/src/assets/images/team/rare-ivy/profile.jpg +0 -0
- package/dist/defaults/src/assets/images/team/sarah-rodriguez/profile.jpg +0 -0
- package/dist/gulp/tasks/jekyll.js +2 -0
- package/dist/gulp/tasks/serve.js +56 -1
- package/firebase-debug.log +392 -0
- package/package.json +2 -2
- package/dist/defaults/dist/_team/alex.md +0 -27
- package/dist/defaults/dist/_team/ian.md +0 -29
- package/dist/defaults/src/assets/images/.gitkeep +0 -0
- package/dist/defaults/src/assets/images/team/alex/profile.jpg +0 -0
- /package/dist/defaults/src/assets/images/team/{ian → ian-wiedenman}/profile.jpg +0 -0
package/CLAUDE.md
CHANGED
|
@@ -779,6 +779,25 @@ Track events directly without existence checks. All three tracking calls should
|
|
|
779
779
|
**Development Mode:**
|
|
780
780
|
In development mode, all tracking calls are intercepted and logged to the console for debugging. See `src/assets/js/libs/dev.js` for implementation.
|
|
781
781
|
|
|
782
|
+
## HTML Element Attributes
|
|
783
|
+
|
|
784
|
+
The `<html>` element has data attributes for JavaScript/CSS targeting:
|
|
785
|
+
|
|
786
|
+
| Attribute | Values |
|
|
787
|
+
|-----------|--------|
|
|
788
|
+
| `data-theme-id` | Theme ID (e.g., `classy`) |
|
|
789
|
+
| `data-theme-target` | `frontend`, `backend`, `docs` |
|
|
790
|
+
| `data-bs-theme` | `light`, `dark` |
|
|
791
|
+
| `data-page-path` | Page permalink (e.g., `/about`) |
|
|
792
|
+
| `data-asset-path` | Custom asset path or empty |
|
|
793
|
+
| `data-environment` | `development`, `production` |
|
|
794
|
+
| `data-platform` | `windows`, `mac`, `linux`, `ios`, `android`, `chromeos`, `unknown` |
|
|
795
|
+
| `data-device` | `mobile` (<768px), `tablet` (768-1199px), `desktop` (>=1200px) |
|
|
796
|
+
| `data-runtime` | `web`, `extension`, `electron`, `node` |
|
|
797
|
+
| `aria-busy` | `true` (loading), `false` (ready) |
|
|
798
|
+
|
|
799
|
+
**Detection source:** `web-manager/src/modules/utilities.js`
|
|
800
|
+
|
|
782
801
|
## Audit Workflow
|
|
783
802
|
|
|
784
803
|
When fixing issues identified by the audit task (`src/gulp/tasks/audit.js`):
|
package/README.md
CHANGED
|
@@ -231,6 +231,23 @@ These utilities are particularly useful for:
|
|
|
231
231
|
- Constraining forms, cards, and modals to reasonable sizes
|
|
232
232
|
- Maintaining design consistency with Bootstrap's grid system
|
|
233
233
|
|
|
234
|
+
### HTML Element Attributes
|
|
235
|
+
|
|
236
|
+
The `<html>` element has data attributes for JavaScript/CSS targeting:
|
|
237
|
+
|
|
238
|
+
| Attribute | Values |
|
|
239
|
+
|-----------|--------|
|
|
240
|
+
| `data-theme-id` | Theme ID (e.g., `classy`) |
|
|
241
|
+
| `data-theme-target` | `frontend`, `backend`, `docs` |
|
|
242
|
+
| `data-bs-theme` | `light`, `dark` |
|
|
243
|
+
| `data-page-path` | Page permalink (e.g., `/about`) |
|
|
244
|
+
| `data-asset-path` | Custom asset path or empty |
|
|
245
|
+
| `data-environment` | `development`, `production` |
|
|
246
|
+
| `data-platform` | `windows`, `mac`, `linux`, `ios`, `android`, `chromeos`, `unknown` |
|
|
247
|
+
| `data-device` | `mobile` (<768px), `tablet` (768-1199px), `desktop` (>=1200px) |
|
|
248
|
+
| `data-runtime` | `web`, `extension`, `electron`, `node` |
|
|
249
|
+
| `aria-busy` | `true` (loading), `false` (ready) |
|
|
250
|
+
|
|
234
251
|
### Page Loading Protection System
|
|
235
252
|
|
|
236
253
|
Ultimate Jekyll includes an automatic protection system that prevents users from clicking buttons before JavaScript is fully loaded, eliminating race conditions and errors.
|
|
@@ -19,17 +19,26 @@ export default function (Manager) {
|
|
|
19
19
|
// Check for authSignout parameter first
|
|
20
20
|
await handleAuthSignout(webManager);
|
|
21
21
|
|
|
22
|
-
// Initialize the appropriate form based on the page (
|
|
22
|
+
// Initialize the appropriate form based on the page (with autoReady: false)
|
|
23
23
|
initializePageForm();
|
|
24
24
|
|
|
25
|
-
// Check for redirect result from OAuth providers
|
|
26
|
-
|
|
25
|
+
// Check for redirect result from OAuth providers BEFORE enabling form
|
|
26
|
+
// This prevents the form from appearing interactive while redirect is processing
|
|
27
|
+
const hasRedirectResult = await handleRedirectResult();
|
|
28
|
+
|
|
29
|
+
// If redirect result was found, don't enable the form - user will be redirected
|
|
30
|
+
if (hasRedirectResult) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
27
33
|
|
|
28
34
|
// Check subdomain auth restrictions and redirect if needed
|
|
29
35
|
if (checkSubdomainAuth()) {
|
|
30
36
|
return;
|
|
31
37
|
}
|
|
32
38
|
|
|
39
|
+
// No redirect pending - enable the form
|
|
40
|
+
formManager.ready();
|
|
41
|
+
|
|
33
42
|
// Update auth return URL in all auth-related links
|
|
34
43
|
updateAuthReturnUrl();
|
|
35
44
|
|
|
@@ -85,6 +94,7 @@ export default function (Manager) {
|
|
|
85
94
|
// Initialize signin form
|
|
86
95
|
function initializeSigninForm() {
|
|
87
96
|
formManager = new FormManager('#signin-form', {
|
|
97
|
+
autoReady: false, // We'll call ready() after checking redirect result
|
|
88
98
|
allowResubmit: false,
|
|
89
99
|
submittingText: 'Signing in...',
|
|
90
100
|
submittedText: 'Signed In!',
|
|
@@ -97,6 +107,7 @@ export default function (Manager) {
|
|
|
97
107
|
// Initialize signup form
|
|
98
108
|
function initializeSignupForm() {
|
|
99
109
|
formManager = new FormManager('#signup-form', {
|
|
110
|
+
autoReady: false, // We'll call ready() after checking redirect result
|
|
100
111
|
allowResubmit: false,
|
|
101
112
|
submittingText: 'Creating account...',
|
|
102
113
|
submittedText: 'Account Created!',
|
|
@@ -109,6 +120,7 @@ export default function (Manager) {
|
|
|
109
120
|
// Initialize reset form
|
|
110
121
|
function initializeResetForm() {
|
|
111
122
|
formManager = new FormManager('#reset-form', {
|
|
123
|
+
autoReady: false, // We'll call ready() after checking redirect result
|
|
112
124
|
allowResubmit: false,
|
|
113
125
|
submittingText: 'Sending...',
|
|
114
126
|
submittedText: 'Email Sent!',
|
|
@@ -129,9 +141,9 @@ export default function (Manager) {
|
|
|
129
141
|
// Log results for debugging
|
|
130
142
|
console.log('Redirect result:', result);
|
|
131
143
|
|
|
132
|
-
// If no result,
|
|
144
|
+
// If no result, return false to indicate no redirect was processed
|
|
133
145
|
if (!result || !result.user) {
|
|
134
|
-
return;
|
|
146
|
+
return false;
|
|
135
147
|
}
|
|
136
148
|
|
|
137
149
|
console.log('Successfully authenticated via redirect:', result.user.email);
|
|
@@ -151,6 +163,9 @@ export default function (Manager) {
|
|
|
151
163
|
trackLogin(providerId, result.user);
|
|
152
164
|
formManager.showSuccess('Successfully signed in!');
|
|
153
165
|
}
|
|
166
|
+
|
|
167
|
+
// Return true to indicate redirect was successfully processed
|
|
168
|
+
return true;
|
|
154
169
|
} catch (error) {
|
|
155
170
|
// Only capture unexpected errors to Sentry
|
|
156
171
|
if (!isUserError(error.code)) {
|
|
@@ -167,6 +182,9 @@ export default function (Manager) {
|
|
|
167
182
|
} else if (error.code && error.code !== 'auth/cancelled-popup-request') {
|
|
168
183
|
formManager.showError(`Authentication error: ${error.message}`);
|
|
169
184
|
}
|
|
185
|
+
|
|
186
|
+
// Return false on error so form becomes interactive for user to try again
|
|
187
|
+
return false;
|
|
170
188
|
}
|
|
171
189
|
}
|
|
172
190
|
|
|
@@ -154,6 +154,12 @@ export class FormManager {
|
|
|
154
154
|
const $autofocusField = this.$form.querySelector('[autofocus]');
|
|
155
155
|
if ($autofocusField && !$autofocusField.disabled) {
|
|
156
156
|
$autofocusField.focus();
|
|
157
|
+
|
|
158
|
+
// Move cursor to end of input if it has existing text
|
|
159
|
+
if (typeof $autofocusField.setSelectionRange === 'function') {
|
|
160
|
+
const len = $autofocusField.value.length;
|
|
161
|
+
$autofocusField.setSelectionRange(len, len);
|
|
162
|
+
}
|
|
157
163
|
}
|
|
158
164
|
}
|
|
159
165
|
|
package/dist/commands/migrate.js
CHANGED
|
@@ -17,9 +17,11 @@ module.exports = async function () {
|
|
|
17
17
|
// Run migration tasks
|
|
18
18
|
await migratePosts();
|
|
19
19
|
await migrateAssets();
|
|
20
|
+
await migrateBlogImages();
|
|
20
21
|
await fixPostsLayout();
|
|
21
22
|
await fixPostFilenames();
|
|
22
23
|
await cleanupOldDirectories();
|
|
24
|
+
await cleanupDeprecatedAuthors();
|
|
23
25
|
|
|
24
26
|
// Log completion
|
|
25
27
|
logger.log(logger.format.green('✓ Migration complete!'));
|
|
@@ -216,6 +218,27 @@ async function migrateAssets() {
|
|
|
216
218
|
}
|
|
217
219
|
}
|
|
218
220
|
|
|
221
|
+
async function migrateBlogImages() {
|
|
222
|
+
const sourcePath = path.join(process.cwd(), 'src', 'assets', '_src', 'images', 'blog', 'posts');
|
|
223
|
+
const targetPath = path.join(process.cwd(), 'src', 'assets', 'images', 'blog');
|
|
224
|
+
|
|
225
|
+
if (!jetpack.exists(sourcePath)) {
|
|
226
|
+
logger.log('No src/assets/_src/images/blog/posts directory found - skipping blog images migration');
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
logger.log('Migrating blog images to src/assets/images/blog...');
|
|
231
|
+
|
|
232
|
+
// Ensure target directory exists
|
|
233
|
+
jetpack.dir(targetPath);
|
|
234
|
+
|
|
235
|
+
// Copy contents (overwrite) then remove source
|
|
236
|
+
jetpack.copy(sourcePath, targetPath, { overwrite: true });
|
|
237
|
+
jetpack.remove(sourcePath);
|
|
238
|
+
|
|
239
|
+
logger.log(logger.format.green('✓ Blog images migrated'));
|
|
240
|
+
}
|
|
241
|
+
|
|
219
242
|
async function fixPostsLayout() {
|
|
220
243
|
const postsPath = path.join(process.cwd(), 'src', '_posts');
|
|
221
244
|
|
|
@@ -290,7 +313,21 @@ async function fixPostsLayout() {
|
|
|
290
313
|
modified = true;
|
|
291
314
|
}
|
|
292
315
|
|
|
293
|
-
// 4.
|
|
316
|
+
// 4. Migrate post.author from old format to new format (first-last)
|
|
317
|
+
const authorMigrations = {
|
|
318
|
+
'alex': 'alex-raeburn',
|
|
319
|
+
'ian': 'ian-wiedenman',
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
Object.entries(authorMigrations).forEach(([oldAuthor, newAuthor]) => {
|
|
323
|
+
const authorRegex = new RegExp(`^(\\s*author:\\s*)(['"]?)${oldAuthor}\\2\\s*$`, 'gm');
|
|
324
|
+
if (frontmatter.match(authorRegex)) {
|
|
325
|
+
frontmatter = frontmatter.replace(authorRegex, `$1${newAuthor}`);
|
|
326
|
+
modified = true;
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// 5. Remove ad unit includes from content
|
|
294
331
|
const adUnitRegex = /{%\s*include\s+\/master\/modules\/adunits\/adsense-in-article\.html\s+index="[^"]*"\s*%}/g;
|
|
295
332
|
const cleanedContent = restOfContent.replace(adUnitRegex, '');
|
|
296
333
|
|
|
@@ -388,6 +425,7 @@ async function cleanupOldDirectories() {
|
|
|
388
425
|
const directoriesToCheck = [
|
|
389
426
|
{ path: path.join(process.cwd(), 'assets'), name: 'assets' },
|
|
390
427
|
{ path: path.join(process.cwd(), '_posts'), name: '_posts' },
|
|
428
|
+
{ path: path.join(process.cwd(), 'src', 'assets', '_src'), name: 'src/assets/_src' },
|
|
391
429
|
];
|
|
392
430
|
|
|
393
431
|
logger.log('Checking for empty old directories to clean up...');
|
|
@@ -422,3 +460,36 @@ async function cleanupOldDirectories() {
|
|
|
422
460
|
logger.log('No empty directories to clean up');
|
|
423
461
|
}
|
|
424
462
|
}
|
|
463
|
+
|
|
464
|
+
async function cleanupDeprecatedAuthors() {
|
|
465
|
+
// Deprecated author directories that used first-name only format
|
|
466
|
+
const deprecatedAuthors = ['ian', 'alex'];
|
|
467
|
+
|
|
468
|
+
const directoriesToDelete = deprecatedAuthors.map((author) => ({
|
|
469
|
+
path: path.join(process.cwd(), 'src', 'assets', 'images', 'team', author),
|
|
470
|
+
name: `team/${author}`,
|
|
471
|
+
}));
|
|
472
|
+
|
|
473
|
+
logger.log('Checking for deprecated author directories to remove...');
|
|
474
|
+
|
|
475
|
+
let deletedCount = 0;
|
|
476
|
+
|
|
477
|
+
directoriesToDelete.forEach(({ path: dirPath, name }) => {
|
|
478
|
+
const exists = jetpack.exists(dirPath);
|
|
479
|
+
|
|
480
|
+
if (!exists) {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Delete the directory and all its contents
|
|
485
|
+
jetpack.remove(dirPath);
|
|
486
|
+
logger.log(` ✓ Deleted deprecated ${name} directory`);
|
|
487
|
+
deletedCount++;
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
if (deletedCount > 0) {
|
|
491
|
+
logger.log(logger.format.green(`✓ Removed ${deletedCount} deprecated author director${deletedCount === 1 ? 'y' : 'ies'}`));
|
|
492
|
+
} else {
|
|
493
|
+
logger.log('No deprecated author directories found');
|
|
494
|
+
}
|
|
495
|
+
}
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
<!-- Configuration -->
|
|
66
66
|
<script type="text/javascript">
|
|
67
67
|
var Configuration = {
|
|
68
|
-
environment: "{{
|
|
68
|
+
environment: "{{ jekyll.environment }}",
|
|
69
69
|
buildTime: {{ site.uj.cache_breaker }},
|
|
70
70
|
brand: {{ page.resolved.brand | jsonify }},
|
|
71
71
|
advertising: {{ page.resolved.advertising | jsonify }},
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{% capture logo_text %}{{ data.logo.text | default: site.brand.name | uj_liquify }}{% endcapture %}
|
|
7
7
|
{% capture logo_class %}{{ data.logo.class }}{% endcapture %}
|
|
8
8
|
|
|
9
|
-
<a class="navbar-brand d-inline-flex align-items-center" href="{{ logo_href }}">
|
|
9
|
+
<a class="navbar-brand d-inline-flex align-items-center py-0" href="{{ logo_href }}">
|
|
10
10
|
{% iftruthy logo_src %}
|
|
11
11
|
<div class="avatar avatar-md me-2 {{ logo_class }}">
|
|
12
12
|
<img src="{{ logo_src }}" alt="{{ logo_text }} Logo"/>
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
<div class="dropdown animation-slide-up ms-2 d-inline-flex" data-wm-bind="@show auth.user" hidden>
|
|
32
32
|
<button class="p-0 border-0 bg-transparent" type="button" data-bs-toggle="dropdown" {{ action_attributes }} aria-expanded="false">
|
|
33
33
|
<span class="d-flex align-items-center">
|
|
34
|
-
<span class="position-relative d-inline-
|
|
34
|
+
<span class="position-relative d-inline-flex">
|
|
35
35
|
<span class="avatar avatar-sm rounded-circle bg-secondary bg-opacity-10 border d-flex align-items-center justify-content-center overflow-hidden d-inline-flex">
|
|
36
36
|
<img src="{{ site.uj.placeholder.src }}" data-wm-bind="@attr src auth.user.photoURL" alt="{{ site.brand.name }} profile picture"/>
|
|
37
37
|
</span>
|
|
38
38
|
<!-- Active status indicator -->
|
|
39
|
-
<span class="position-absolute bottom-0 end-0 p-1 bg-success border border-2 border-white avatar avatar-2xs rounded-circle mb-
|
|
39
|
+
<span class="position-absolute bottom-0 end-0 p-1 bg-success border border-2 border-white avatar avatar-2xs rounded-circle mb-0">
|
|
40
40
|
<span class="visually-hidden">Active status</span>
|
|
41
41
|
</span>
|
|
42
42
|
</span>
|
|
@@ -188,12 +188,12 @@
|
|
|
188
188
|
<div class="dropdown ms-lg-3 animation-slide-up d-inline-flex" data-wm-bind="@show auth.user" hidden>
|
|
189
189
|
<button class="p-0 border-0 bg-transparent" type="button" data-bs-toggle="dropdown" {{ action_attributes }} aria-expanded="false">
|
|
190
190
|
<span class="d-flex align-items-center">
|
|
191
|
-
<span class="position-relative d-inline-
|
|
191
|
+
<span class="position-relative d-inline-flex">
|
|
192
192
|
<span class="avatar avatar-md rounded-circle bg-secondary bg-opacity-10 border d-flex align-items-center justify-content-center overflow-hidden d-inline-flex">
|
|
193
193
|
<img src="{{ site.uj.placeholder.src }}" data-wm-bind="@attr src auth.user.photoURL" alt="{{ site.brand.name }} profile picture"/>
|
|
194
194
|
</span>
|
|
195
195
|
<!-- Active status indicator -->
|
|
196
|
-
<span class="position-absolute bottom-0 end-0 p-1 bg-success border border-2 border-white avatar avatar-2xs rounded-circle mb-
|
|
196
|
+
<span class="position-absolute bottom-0 end-0 p-1 bg-success border border-2 border-white avatar avatar-2xs rounded-circle mb-0">
|
|
197
197
|
<span class="visually-hidden">Active status</span>
|
|
198
198
|
</span>
|
|
199
199
|
</span>
|
|
@@ -17,6 +17,11 @@ layout: null
|
|
|
17
17
|
data-page-path="{{ page.canonical.path }}"
|
|
18
18
|
data-asset-path="{{ page.resolved.asset_path }}"
|
|
19
19
|
|
|
20
|
+
data-environment="{{ jekyll.environment | default: 'development' }}"
|
|
21
|
+
data-platform=""
|
|
22
|
+
data-device=""
|
|
23
|
+
data-runtime=""
|
|
24
|
+
|
|
20
25
|
data-page-loading="true"
|
|
21
26
|
aria-busy="true"
|
|
22
27
|
>
|
|
@@ -65,7 +65,7 @@ meta:
|
|
|
65
65
|
data-querystring="{{ querystring }}"
|
|
66
66
|
data-modifier="{{ modifier }}"
|
|
67
67
|
data-site-url="{{ site.url }}"
|
|
68
|
-
data-environment="{{
|
|
68
|
+
data-environment="{{ jekyll.environment }}">
|
|
69
69
|
</div>
|
|
70
70
|
|
|
71
71
|
<!-- Load redirect module script -->
|
|
@@ -120,12 +120,12 @@ badges:
|
|
|
120
120
|
<div class="container-fluid px-4">
|
|
121
121
|
<div class="d-flex align-items-center justify-content-between py-3">
|
|
122
122
|
<!-- Left: Brand -->
|
|
123
|
-
<
|
|
123
|
+
<a href="/" class="d-flex align-items-center text-decoration-none text-body">
|
|
124
124
|
<span class="avatar avatar-md me-3">
|
|
125
125
|
<img src="{{ site.brand.images.brandmark }}?cb={{ site.uj.cache_breaker }}" alt="{{ site.brand.name }}"/>
|
|
126
126
|
</span>
|
|
127
127
|
<h1 class="h5 mb-0 fw-semibold">{{ site.brand.name }} Account</h1>
|
|
128
|
-
</
|
|
128
|
+
</a>
|
|
129
129
|
|
|
130
130
|
<!-- Right: Close button -->
|
|
131
131
|
<button type="button" class="btn-close" aria-label="Close" onclick="window.location.href='/'"></button>
|
|
@@ -135,7 +135,7 @@ badges:
|
|
|
135
135
|
|
|
136
136
|
<!-- Mobile Navigation Dropdown -->
|
|
137
137
|
<div class="d-lg-none pt-5">
|
|
138
|
-
<div class="container-fluid">
|
|
138
|
+
<div class="container-fluid px-0">
|
|
139
139
|
<div class="card border-0 shadow-sm">
|
|
140
140
|
<div class="card-body p-3">
|
|
141
141
|
<div class="d-flex gap-2">
|
|
@@ -165,7 +165,7 @@ badges:
|
|
|
165
165
|
<div class="row">
|
|
166
166
|
<!-- Desktop Sidebar -->
|
|
167
167
|
<nav class="col-lg-3 d-none d-lg-block px-3 pb-3 pt-0" aria-label="Account navigation">
|
|
168
|
-
<div class="card border-0 shadow-sm position-sticky">
|
|
168
|
+
<div class="card border-0 shadow-sm position-sticky" style="top: 90px;">
|
|
169
169
|
<div class="card-body p-3">
|
|
170
170
|
<ul class="nav nav-pills flex-column" id="account-nav" role="tablist" aria-label="Account sections">
|
|
171
171
|
{% for section in page.resolved.sections %}
|
|
@@ -214,13 +214,13 @@ badges:
|
|
|
214
214
|
<!-- Avatar and Edit Button -->
|
|
215
215
|
<div class="mb-4">
|
|
216
216
|
<div class="d-flex align-items-center">
|
|
217
|
-
<div id="avatar-container" class="me-3 position-relative">
|
|
217
|
+
<div id="avatar-container" class="me-3 position-relative d-flex align-items-center">
|
|
218
218
|
<!-- Avatar always available from getUser() -->
|
|
219
219
|
<div class="avatar avatar-lg rounded-circle overflow-hidden border">
|
|
220
220
|
<img src="{{ site.uj.placeholder.src }}" data-wm-bind="@attr src auth.user.photoURL" class="object-fit-cover w-100 h-100" alt="{{ site.brand.name }} profile picture"/>
|
|
221
221
|
</div>
|
|
222
222
|
<!-- Active status indicator -->
|
|
223
|
-
<span class="position-absolute bottom-0 end-0 p-1 bg-success border border-2 border-white avatar avatar-2xs rounded-circle mb-
|
|
223
|
+
<span class="position-absolute bottom-0 end-0 p-1 bg-success border border-2 border-white avatar avatar-2xs rounded-circle mb-0">
|
|
224
224
|
<span class="visually-hidden">Active status</span>
|
|
225
225
|
</span>
|
|
226
226
|
</div>
|
|
@@ -27,7 +27,7 @@ layout: themes/[ site.theme.id ]/frontend/core/cover
|
|
|
27
27
|
<label for="email" class="form-label fw-semibold">
|
|
28
28
|
Email <span class="text-danger">*</span>
|
|
29
29
|
</label>
|
|
30
|
-
<input type="email" class="form-control form-control-md" id="email" name="email" placeholder="Enter your email" autocomplete="email" autofocus required>
|
|
30
|
+
<input type="email" class="form-control form-control-md" id="email" name="email" placeholder="Enter your email" autocomplete="email" autofocus required disabled>
|
|
31
31
|
</div>
|
|
32
32
|
|
|
33
33
|
<button type="submit" class="btn btn-success _btn-lg w-100 mb-4" data-provider="email" disabled>
|
|
@@ -63,7 +63,7 @@ social_signin:
|
|
|
63
63
|
<label for="email" class="form-label fw-semibold">
|
|
64
64
|
Email <span class="text-danger">*</span>
|
|
65
65
|
</label>
|
|
66
|
-
<input type="email" class="form-control form-control-md" id="email" name="email" placeholder="Enter your email" autocomplete="email" autofocus>
|
|
66
|
+
<input type="email" class="form-control form-control-md" id="email" name="email" placeholder="Enter your email" autocomplete="email" autofocus disabled>
|
|
67
67
|
</div>
|
|
68
68
|
|
|
69
69
|
<div class="mb-3 text-start">
|
|
@@ -71,7 +71,7 @@ social_signin:
|
|
|
71
71
|
Password <span class="text-danger">*</span>
|
|
72
72
|
</label>
|
|
73
73
|
<div class="input-group">
|
|
74
|
-
<input type="password" class="form-control form-control-md" id="password" name="password" placeholder="Enter your password" autocomplete="current-password">
|
|
74
|
+
<input type="password" class="form-control form-control-md" id="password" name="password" placeholder="Enter your password" autocomplete="current-password" disabled>
|
|
75
75
|
<button class="btn border uj-password-toggle px-3" type="button" aria-label="Toggle password visibility">
|
|
76
76
|
<span class="uj-password-show">{% uj_icon "eye", "fa-fw" %}</span>
|
|
77
77
|
<span class="uj-password-hide d-none">{% uj_icon "eye-slash", "fa-fw" %}</span>
|
|
@@ -73,7 +73,7 @@ social_signup:
|
|
|
73
73
|
<label for="email" class="form-label fw-semibold">
|
|
74
74
|
Email <span class="text-danger">*</span>
|
|
75
75
|
</label>
|
|
76
|
-
<input type="email" class="form-control form-control-md" id="email" name="email" placeholder="Enter your email" autocomplete="email" autofocus>
|
|
76
|
+
<input type="email" class="form-control form-control-md" id="email" name="email" placeholder="Enter your email" autocomplete="email" autofocus disabled>
|
|
77
77
|
</div>
|
|
78
78
|
|
|
79
79
|
<div class="mb-3 text-start">
|
|
@@ -81,7 +81,7 @@ social_signup:
|
|
|
81
81
|
Password <span class="text-danger">*</span>
|
|
82
82
|
</label>
|
|
83
83
|
<div class="input-group">
|
|
84
|
-
<input type="password" class="form-control form-control-md" id="password" name="password" placeholder="Create a strong password" autocomplete="new-password">
|
|
84
|
+
<input type="password" class="form-control form-control-md" id="password" name="password" placeholder="Create a strong password" autocomplete="new-password" disabled>
|
|
85
85
|
<button class="btn border uj-password-toggle px-3" type="button" aria-label="Toggle password visibility">
|
|
86
86
|
<span class="uj-password-show">{% uj_icon "eye", "fa-fw" %}</span>
|
|
87
87
|
<span class="uj-password-hide d-none">{% uj_icon "eye-slash", "fa-fw" %}</span>
|
|
@@ -32,7 +32,7 @@ pricing:
|
|
|
32
32
|
- id: "basic"
|
|
33
33
|
name: "Basic"
|
|
34
34
|
tagline: "best for getting started"
|
|
35
|
-
url: "/dashboard" # URL
|
|
35
|
+
url: "/dashboard" # URL to get started
|
|
36
36
|
pricing:
|
|
37
37
|
monthly: 0
|
|
38
38
|
annually: 0
|
|
@@ -206,9 +206,10 @@ faqs:
|
|
|
206
206
|
|
|
207
207
|
<!-- Promo Banner -->
|
|
208
208
|
<div id="pricing-promo-banner" class="position-fixed top-0 start-0 w-100 text-light text-center bg-body animation-slide-down" style="z-index: 1050;" hidden>
|
|
209
|
-
<div class="bg-primary-soft py-2">
|
|
209
|
+
<div class="bg-primary-soft py-2 position-relative">
|
|
210
|
+
<button type="button" class="btn-close btn-close-white position-absolute top-0 end-0 mt-2 me-2" aria-label="Close" onclick="this.closest('#pricing-promo-banner').hidden=true;document.querySelector('.navbar-wrapper').style.marginTop=''"></button>
|
|
210
211
|
<div class="container-fluid">
|
|
211
|
-
<div class="d-flex align-items-center justify-content-center gap-3 flex-wrap">
|
|
212
|
+
<div class="d-flex align-items-center justify-content-center gap-3 flex-wrap pe-4">
|
|
212
213
|
<span id="pricing-promo-badge" class="badge bg-gradient-rainbow px-2 py-1 fs-6 animation-wiggle">
|
|
213
214
|
15% OFF!
|
|
214
215
|
</span>
|
|
@@ -38,8 +38,8 @@ company_values:
|
|
|
38
38
|
<section class="pt-0">
|
|
39
39
|
<div class="container">
|
|
40
40
|
<div class="text-center mb-5">
|
|
41
|
-
<h2 class="h2 mb-3">
|
|
42
|
-
<p class="fs-5 text-muted">
|
|
41
|
+
<h2 class="h2 mb-3">The people behind the <span class="text-accent">magic</span></h2>
|
|
42
|
+
<p class="fs-5 text-muted">Get to know the talented individuals driving {{ site.brand.name }} forward</p>
|
|
43
43
|
</div>
|
|
44
44
|
|
|
45
45
|
<div class="row g-4 justify-content-center">
|
|
@@ -65,31 +65,13 @@ company_values:
|
|
|
65
65
|
|
|
66
66
|
{% iftruthy member.member.links %}
|
|
67
67
|
<div class="d-flex justify-content-center gap-2">
|
|
68
|
-
{%
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
{% for link in member.member.links %}
|
|
69
|
+
{% assign link_icon = link.id %}
|
|
70
|
+
{% if link.id == "website" %}{% assign link_icon = "globe" %}{% endif %}
|
|
71
|
+
<a href="{{ link.url }}" class="btn btn-outline-primary btn-sm avatar avatar-md rounded-circle d-flex align-items-center justify-content-center" target="_blank" rel="nofollow noopener" title="{{ link.title }}">
|
|
72
|
+
{% uj_icon link_icon, "" %}
|
|
71
73
|
</a>
|
|
72
|
-
{%
|
|
73
|
-
{% iftruthy member.member.links.linkedin %}
|
|
74
|
-
<a href="{{ member.member.links.linkedin }}" class="btn btn-outline-primary btn-sm avatar avatar-md rounded-circle d-flex align-items-center justify-content-center" target="_blank" rel="nofollow noopener">
|
|
75
|
-
{% uj_icon "linkedin", "" %}
|
|
76
|
-
</a>
|
|
77
|
-
{% endiftruthy %}
|
|
78
|
-
{% iftruthy member.member.links.instagram %}
|
|
79
|
-
<a href="{{ member.member.links.instagram }}" class="btn btn-outline-primary btn-sm avatar avatar-md rounded-circle d-flex align-items-center justify-content-center" target="_blank" rel="nofollow noopener">
|
|
80
|
-
{% uj_icon "instagram", "" %}
|
|
81
|
-
</a>
|
|
82
|
-
{% endiftruthy %}
|
|
83
|
-
{% iftruthy member.member.links.twitter %}
|
|
84
|
-
<a href="{{ member.member.links.twitter }}" class="btn btn-outline-primary btn-sm avatar avatar-md rounded-circle d-flex align-items-center justify-content-center" target="_blank" rel="nofollow noopener">
|
|
85
|
-
{% uj_icon "twitter", "" %}
|
|
86
|
-
</a>
|
|
87
|
-
{% endiftruthy %}
|
|
88
|
-
{% iftruthy member.member.links.github %}
|
|
89
|
-
<a href="{{ member.member.links.github }}" class="btn btn-outline-primary btn-sm avatar avatar-md rounded-circle d-flex align-items-center justify-content-center" target="_blank" rel="nofollow noopener">
|
|
90
|
-
{% uj_icon "github", "" %}
|
|
91
|
-
</a>
|
|
92
|
-
{% endiftruthy %}
|
|
74
|
+
{% endfor %}
|
|
93
75
|
</div>
|
|
94
76
|
{% endiftruthy %}
|
|
95
77
|
</div>
|
|
@@ -27,31 +27,13 @@ layout: themes/[ site.theme.id ]/frontend/core/base
|
|
|
27
27
|
<!-- Social Links -->
|
|
28
28
|
{% iftruthy page.member.links %}
|
|
29
29
|
<div class="d-flex justify-content-center gap-2 mb-4">
|
|
30
|
-
{%
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
{% for link in page.member.links %}
|
|
31
|
+
{% assign link_icon = link.id %}
|
|
32
|
+
{% if link.id == "website" %}{% assign link_icon = "globe" %}{% endif %}
|
|
33
|
+
<a href="{{ link.url }}" class="btn btn-outline-primary avatar avatar-lg rounded-circle d-flex align-items-center justify-content-center" target="_blank" rel="nofollow noopener" title="{{ link.title }}">
|
|
34
|
+
{% uj_icon link_icon, "" %}
|
|
33
35
|
</a>
|
|
34
|
-
{%
|
|
35
|
-
{% iftruthy page.member.links.linkedin %}
|
|
36
|
-
<a href="{{ page.member.links.linkedin }}" class="btn btn-outline-primary avatar avatar-lg rounded-circle d-flex align-items-center justify-content-center" target="_blank" rel="nofollow noopener">
|
|
37
|
-
{% uj_icon "linkedin", "" %}
|
|
38
|
-
</a>
|
|
39
|
-
{% endiftruthy %}
|
|
40
|
-
{% iftruthy page.member.links.instagram %}
|
|
41
|
-
<a href="{{ page.member.links.instagram }}" class="btn btn-outline-primary avatar avatar-lg rounded-circle d-flex align-items-center justify-content-center" target="_blank" rel="nofollow noopener">
|
|
42
|
-
{% uj_icon "instagram", "" %}
|
|
43
|
-
</a>
|
|
44
|
-
{% endiftruthy %}
|
|
45
|
-
{% iftruthy page.member.links.twitter %}
|
|
46
|
-
<a href="{{ page.member.links.twitter }}" class="btn btn-outline-primary avatar avatar-lg rounded-circle d-flex align-items-center justify-content-center" target="_blank" rel="nofollow noopener">
|
|
47
|
-
{% uj_icon "twitter", "" %}
|
|
48
|
-
</a>
|
|
49
|
-
{% endiftruthy %}
|
|
50
|
-
{% iftruthy page.member.links.github %}
|
|
51
|
-
<a href="{{ page.member.links.github }}" class="btn btn-outline-primary avatar avatar-lg rounded-circle d-flex align-items-center justify-content-center" target="_blank" rel="nofollow noopener">
|
|
52
|
-
{% uj_icon "github", "" %}
|
|
53
|
-
</a>
|
|
54
|
-
{% endiftruthy %}
|
|
36
|
+
{% endfor %}
|
|
55
37
|
</div>
|
|
56
38
|
{% endiftruthy %}
|
|
57
39
|
|
|
@@ -107,7 +89,7 @@ layout: themes/[ site.theme.id ]/frontend/core/base
|
|
|
107
89
|
{% uj_icon "briefcase", "text-light fs-2" %}
|
|
108
90
|
</div>
|
|
109
91
|
<h4 class="mb-2">Skills</h4>
|
|
110
|
-
<p class="text-muted mb-0">{{ page.member.skills }}</p>
|
|
92
|
+
<p class="text-muted mb-0">{{ page.member.skills | join: ", " }}</p>
|
|
111
93
|
</div>
|
|
112
94
|
</div>
|
|
113
95
|
</div>
|
|
@@ -121,7 +103,7 @@ layout: themes/[ site.theme.id ]/frontend/core/base
|
|
|
121
103
|
{% uj_icon "heart", "text-light fs-2" %}
|
|
122
104
|
</div>
|
|
123
105
|
<h4 class="mb-2">Hobbies</h4>
|
|
124
|
-
<p class="text-muted mb-0">{{ page.member.hobbies }}</p>
|
|
106
|
+
<p class="text-muted mb-0">{{ page.member.hobbies | join: ", " }}</p>
|
|
125
107
|
</div>
|
|
126
108
|
</div>
|
|
127
109
|
</div>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
### ALL PAGES ###
|
|
3
|
+
layout: blueprint/team/member
|
|
4
|
+
sitemap:
|
|
5
|
+
include: true
|
|
6
|
+
|
|
7
|
+
### TEAM MEMBER PAGES ###
|
|
8
|
+
member:
|
|
9
|
+
id: alex-raeburn
|
|
10
|
+
name: "Alex Raeburn"
|
|
11
|
+
position: "Social Media Manager"
|
|
12
|
+
description: "Alex is an experienced social media expert from Beverly Hills, CA and is a major contributor to our blog."
|
|
13
|
+
location: "Beverly Hills, CA"
|
|
14
|
+
skills:
|
|
15
|
+
- "Writing"
|
|
16
|
+
- "Blog Management"
|
|
17
|
+
hobbies:
|
|
18
|
+
- "Instagram"
|
|
19
|
+
joined: 2017-10-20
|
|
20
|
+
links:
|
|
21
|
+
- id: "linkedin"
|
|
22
|
+
title: "LinkedIn"
|
|
23
|
+
url: "https://www.linkedin.com/in/alex-raeburn"
|
|
24
|
+
- id: "instagram"
|
|
25
|
+
title: "Instagram"
|
|
26
|
+
url: "https://www.instagram.com/_alexraeburn"
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
Hey everyone, I'm Alex!
|
|
30
|
+
|
|
31
|
+
I was born and raised in Beverly Hills, CA, where the intersection of creativity and culture shaped who I am today. Writing and technology have always been important parts of my life, and I'm thrilled to bring that passion to this team.
|
|
32
|
+
|
|
33
|
+
As Social Media Manager, I oversee our brand's presence across all platforms and contribute regularly to our blog. I believe social media is more than just posting content - it's about building genuine connections with our community and telling stories that resonate with people.
|
|
34
|
+
|
|
35
|
+
Before joining the team, I worked at a boutique marketing agency where I managed accounts for lifestyle brands and influencers. That experience taught me the power of authentic engagement and how the right content at the right time can spark real conversations.
|
|
36
|
+
|
|
37
|
+
I'm fascinated by how technology is transforming the way we communicate. The idea that tools and automation can help us be more present and creative (rather than bogged down in repetitive tasks) really excites me. It's why I love working on products that empower people to do more with less effort.
|
|
38
|
+
|
|
39
|
+
Outside of work, you'll find me curating my Instagram feed - it's become a creative outlet where I experiment with photography and storytelling. I also love exploring LA's food scene and discovering hidden gems to share with my followers.
|