ultimate-jekyll-manager 0.0.131 → 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 +57 -0
- 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 +3 -1
- package/dist/defaults/dist/_team/alex-raeburn.md +11 -5
- package/dist/defaults/dist/_team/alfred-caufy.md +11 -6
- package/dist/defaults/dist/_team/ian-wiedenman.md +15 -5
- package/dist/defaults/dist/_team/james-oconnor.md +2 -2
- package/dist/defaults/dist/_team/marcus-johnson.md +4 -4
- package/dist/defaults/dist/_team/priya-sharma.md +3 -3
- package/dist/defaults/dist/_team/rare-ivy.md +5 -5
- package/dist/defaults/dist/_team/sarah-rodriguez.md +6 -3
- 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/gulp/tasks/jekyll.js +2 -0
- package/dist/gulp/tasks/serve.js +56 -1
- package/firebase-debug.log +364 -0
- package/package.json +2 -2
- package/dist/defaults/src/assets/images/.gitkeep +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
|
|
|
@@ -402,6 +425,7 @@ async function cleanupOldDirectories() {
|
|
|
402
425
|
const directoriesToCheck = [
|
|
403
426
|
{ path: path.join(process.cwd(), 'assets'), name: 'assets' },
|
|
404
427
|
{ path: path.join(process.cwd(), '_posts'), name: '_posts' },
|
|
428
|
+
{ path: path.join(process.cwd(), 'src', 'assets', '_src'), name: 'src/assets/_src' },
|
|
405
429
|
];
|
|
406
430
|
|
|
407
431
|
logger.log('Checking for empty old directories to clean up...');
|
|
@@ -436,3 +460,36 @@ async function cleanupOldDirectories() {
|
|
|
436
460
|
logger.log('No empty directories to clean up');
|
|
437
461
|
}
|
|
438
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>
|
|
@@ -28,8 +28,10 @@ layout: themes/[ site.theme.id ]/frontend/core/base
|
|
|
28
28
|
{% iftruthy page.member.links %}
|
|
29
29
|
<div class="d-flex justify-content-center gap-2 mb-4">
|
|
30
30
|
{% for link in page.member.links %}
|
|
31
|
+
{% assign link_icon = link.id %}
|
|
32
|
+
{% if link.id == "website" %}{% assign link_icon = "globe" %}{% endif %}
|
|
31
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 }}">
|
|
32
|
-
{% uj_icon
|
|
34
|
+
{% uj_icon link_icon, "" %}
|
|
33
35
|
</a>
|
|
34
36
|
{% endfor %}
|
|
35
37
|
</div>
|
|
@@ -20,14 +20,20 @@ member:
|
|
|
20
20
|
links:
|
|
21
21
|
- id: "linkedin"
|
|
22
22
|
title: "LinkedIn"
|
|
23
|
-
url: "https://www.linkedin.com/in/
|
|
23
|
+
url: "https://www.linkedin.com/in/alex-raeburn"
|
|
24
24
|
- id: "instagram"
|
|
25
25
|
title: "Instagram"
|
|
26
|
-
url: "https://www.instagram.com/
|
|
26
|
+
url: "https://www.instagram.com/_alexraeburn"
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
-
Hey everyone, I'm Alex
|
|
29
|
+
Hey everyone, I'm Alex!
|
|
30
30
|
|
|
31
|
-
I
|
|
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
32
|
|
|
33
|
-
I
|
|
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.
|
|
@@ -9,7 +9,7 @@ member:
|
|
|
9
9
|
id: alfred-caufy
|
|
10
10
|
name: "Alfred Caufy"
|
|
11
11
|
position: "Lead Developer"
|
|
12
|
-
description: "Alfred
|
|
12
|
+
description: "Alfred leads our development team and is dedicated to crafting elegant solutions to complex problems."
|
|
13
13
|
location: "San Francisco, CA"
|
|
14
14
|
skills:
|
|
15
15
|
- "JavaScript"
|
|
@@ -25,11 +25,16 @@ member:
|
|
|
25
25
|
- id: "linkedin"
|
|
26
26
|
title: "LinkedIn"
|
|
27
27
|
url: "https://www.linkedin.com/in/alfred-caufy"
|
|
28
|
-
- id: "github"
|
|
29
|
-
title: "GitHub"
|
|
30
|
-
url: "https://github.com/alfred-caufy"
|
|
31
28
|
---
|
|
32
29
|
|
|
33
|
-
|
|
30
|
+
Hey there, I'm Alfred!
|
|
34
31
|
|
|
35
|
-
|
|
32
|
+
I bring a wealth of technical expertise and leadership to our team. With a background in computer science from Stanford University, I've spent over 8 years building scalable web applications and leading engineering teams at several tech startups before joining this incredible team.
|
|
33
|
+
|
|
34
|
+
My journey into software development started in high school when I built my first website. That spark turned into a full-blown obsession with understanding how things work under the hood. I love diving deep into complex systems and finding elegant solutions that stand the test of time.
|
|
35
|
+
|
|
36
|
+
As Lead Developer, I'm passionate about clean code, best practices, and establishing development standards that help the entire team succeed. I believe great software is built by great teams, so mentorship and knowledge sharing are core to how I work. There's nothing more rewarding than watching a junior developer have that "aha" moment.
|
|
37
|
+
|
|
38
|
+
When I'm not coding, you'll find me contributing to open-source projects - I believe in giving back to the community that taught me so much. I'm also an avid chess player (always looking for a worthy opponent!) and love exploring the hiking trails around the Bay Area. There's something about being in nature that helps me think through tough technical problems.
|
|
39
|
+
|
|
40
|
+
I'm excited to be part of this team and can't wait to see what we build together.
|
|
@@ -16,6 +16,7 @@ member:
|
|
|
16
16
|
- "Business Management"
|
|
17
17
|
hobbies:
|
|
18
18
|
- "Music"
|
|
19
|
+
- "DJing"
|
|
19
20
|
joined: 2017-04-20
|
|
20
21
|
links:
|
|
21
22
|
- id: "website"
|
|
@@ -23,14 +24,23 @@ member:
|
|
|
23
24
|
url: "https://ianwiedenman.com"
|
|
24
25
|
- id: "linkedin"
|
|
25
26
|
title: "LinkedIn"
|
|
26
|
-
url: "https://www.linkedin.com/in/
|
|
27
|
+
url: "https://www.linkedin.com/in/ian-wiedenman"
|
|
28
|
+
- id: "github"
|
|
29
|
+
title: "GitHub"
|
|
30
|
+
url: "https://github.com/ianwieds"
|
|
27
31
|
- id: "instagram"
|
|
28
32
|
title: "Instagram"
|
|
29
|
-
url: "https://www.instagram.com/
|
|
33
|
+
url: "https://www.instagram.com/kiruemusic"
|
|
30
34
|
---
|
|
31
35
|
|
|
32
|
-
Hey everyone, I'm Ian
|
|
36
|
+
Hey everyone, I'm Ian!
|
|
33
37
|
|
|
34
|
-
I'm an innovative business owner and electronic music artist from Los Angeles, CA.
|
|
38
|
+
I'm an innovative business owner and electronic music artist from Los Angeles, CA. Technology and creativity have always driven me - whether I'm building software or producing electronic beats.
|
|
35
39
|
|
|
36
|
-
I quit the corporate 9-5 lifestyle in 2017 to embark on my risky yet rewarding entrepreneurial journey.
|
|
40
|
+
I quit the corporate 9-5 lifestyle in 2017 to embark on my risky yet rewarding entrepreneurial journey. After years of working in traditional tech roles, I realized I wanted to create things that truly mattered to me. Taking that leap was terrifying, but it turned out to be the best decision I ever made.
|
|
41
|
+
|
|
42
|
+
Today, I work for myself building projects I'm passionate about. I'm proud to say that millions of people now use my creations to enhance their productivity and innovation. From browser extensions to web applications, I love solving problems that make people's lives a little easier.
|
|
43
|
+
|
|
44
|
+
When I'm not coding, you'll find me in my home studio producing electronic music under my artist name. Music has been a lifelong passion - it's the perfect creative outlet that balances the logical side of software development. There's something magical about crafting sounds and melodies that move people.
|
|
45
|
+
|
|
46
|
+
I believe in building things that last and treating users with respect. No dark patterns, no shady practices - just honest products that deliver real value. That philosophy has guided every project I've built, and I'm excited to continue this journey.
|