ultimate-jekyll-manager 0.0.131 → 0.0.133

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.
Files changed (38) hide show
  1. package/CLAUDE.md +19 -0
  2. package/README.md +17 -0
  3. package/dist/assets/js/libs/auth.js +23 -5
  4. package/dist/assets/js/libs/form-manager.js +6 -0
  5. package/dist/assets/themes/classy/css/layout/_navigation.scss +2 -1
  6. package/dist/commands/migrate.js +62 -4
  7. package/dist/config/_config_default.yml +1 -1
  8. package/dist/config/_config_development.yml +3 -2
  9. package/dist/defaults/dist/_includes/core/foot.html +1 -1
  10. package/dist/defaults/dist/_includes/themes/classy/frontend/sections/nav.html +5 -5
  11. package/dist/defaults/dist/_layouts/core/root.html +5 -0
  12. package/dist/defaults/dist/_layouts/modules/utilities/redirect.html +1 -1
  13. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +6 -6
  14. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/reset.html +1 -1
  15. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signin.html +2 -2
  16. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signup.html +2 -2
  17. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/index.html +1 -1
  18. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +4 -3
  19. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/team/index.html +8 -26
  20. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/team/member.html +3 -1
  21. package/dist/defaults/dist/_team/alex-raeburn.md +11 -5
  22. package/dist/defaults/dist/_team/alfred-caufy.md +11 -6
  23. package/dist/defaults/dist/_team/christina-hill.md +41 -0
  24. package/dist/defaults/dist/_team/ian-wiedenman.md +15 -5
  25. package/dist/defaults/dist/_team/james-oconnor.md +2 -2
  26. package/dist/defaults/dist/_team/marcus-johnson.md +4 -4
  27. package/dist/defaults/dist/_team/priya-sharma.md +3 -3
  28. package/dist/defaults/dist/_team/rare-ivy.md +5 -5
  29. package/dist/defaults/dist/_team/sarah-rodriguez.md +6 -3
  30. package/dist/defaults/dist/pages/test/libraries/form-manager.html +23 -23
  31. package/dist/defaults/src/assets/images/team/alex-raeburn/profile.jpg +0 -0
  32. package/dist/defaults/src/assets/images/team/alfred-caufy/profile.jpg +0 -0
  33. package/dist/defaults/src/assets/images/team/christina-hill/profile.jpg +0 -0
  34. package/dist/gulp/tasks/jekyll.js +2 -0
  35. package/dist/gulp/tasks/serve.js +56 -1
  36. package/firebase-debug.log +462 -0
  37. package/package.json +2 -2
  38. 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 (needs to be done early for error handling)
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
- await handleRedirectResult();
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, just return
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
 
@@ -56,7 +56,8 @@
56
56
  .navbar {
57
57
  &.navbar-floating {
58
58
  border-radius: 1rem;
59
- padding: 0.75rem 1rem;
59
+ // padding: 0.75rem;
60
+ padding: 1rem;
60
61
  background: transparent !important;
61
62
  border: 1px solid rgba(0, 0, 0, 0.06);
62
63
  transition: all 0.3s ease;
@@ -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
 
@@ -291,15 +314,16 @@ async function fixPostsLayout() {
291
314
  }
292
315
 
293
316
  // 4. Migrate post.author from old format to new format (first-last)
317
+ const alexAuthors = ['alex-raeburn', 'rare-ivy', 'christina-hill'];
294
318
  const authorMigrations = {
295
- 'alex': 'alex-raeburn',
296
- 'ian': 'ian-wiedenman',
319
+ 'alex': () => alexAuthors[Math.floor(Math.random() * alexAuthors.length)],
320
+ 'ian': () => 'ian-wiedenman',
297
321
  };
298
322
 
299
- Object.entries(authorMigrations).forEach(([oldAuthor, newAuthor]) => {
323
+ Object.entries(authorMigrations).forEach(([oldAuthor, getNewAuthor]) => {
300
324
  const authorRegex = new RegExp(`^(\\s*author:\\s*)(['"]?)${oldAuthor}\\2\\s*$`, 'gm');
301
325
  if (frontmatter.match(authorRegex)) {
302
- frontmatter = frontmatter.replace(authorRegex, `$1${newAuthor}`);
326
+ frontmatter = frontmatter.replace(authorRegex, `$1${getNewAuthor()}`);
303
327
  modified = true;
304
328
  }
305
329
  });
@@ -402,6 +426,7 @@ async function cleanupOldDirectories() {
402
426
  const directoriesToCheck = [
403
427
  { path: path.join(process.cwd(), 'assets'), name: 'assets' },
404
428
  { path: path.join(process.cwd(), '_posts'), name: '_posts' },
429
+ { path: path.join(process.cwd(), 'src', 'assets', '_src'), name: 'src/assets/_src' },
405
430
  ];
406
431
 
407
432
  logger.log('Checking for empty old directories to clean up...');
@@ -436,3 +461,36 @@ async function cleanupOldDirectories() {
436
461
  logger.log('No empty directories to clean up');
437
462
  }
438
463
  }
464
+
465
+ async function cleanupDeprecatedAuthors() {
466
+ // Deprecated author directories that used first-name only format
467
+ const deprecatedAuthors = ['ian', 'alex'];
468
+
469
+ const directoriesToDelete = deprecatedAuthors.map((author) => ({
470
+ path: path.join(process.cwd(), 'src', 'assets', 'images', 'team', author),
471
+ name: `team/${author}`,
472
+ }));
473
+
474
+ logger.log('Checking for deprecated author directories to remove...');
475
+
476
+ let deletedCount = 0;
477
+
478
+ directoriesToDelete.forEach(({ path: dirPath, name }) => {
479
+ const exists = jetpack.exists(dirPath);
480
+
481
+ if (!exists) {
482
+ return;
483
+ }
484
+
485
+ // Delete the directory and all its contents
486
+ jetpack.remove(dirPath);
487
+ logger.log(` ✓ Deleted deprecated ${name} directory`);
488
+ deletedCount++;
489
+ });
490
+
491
+ if (deletedCount > 0) {
492
+ logger.log(logger.format.green(`✓ Removed ${deletedCount} deprecated author director${deletedCount === 1 ? 'y' : 'ies'}`));
493
+ } else {
494
+ logger.log('No deprecated author directories found');
495
+ }
496
+ }
@@ -1,7 +1,7 @@
1
1
  # Ultimate Jekyll Properties
2
2
  uj:
3
3
  cache_breaker: null
4
- environment: "production"
4
+ # environment: "production" # DEPRECATED: use jekyll.environment instead
5
5
 
6
6
  # Theme
7
7
  theme:
@@ -1,3 +1,4 @@
1
1
  # Ultimate Jekyll Properties
2
- uj:
3
- environment: "development"
2
+ # DEPRECATD THIS (USE jekyll.environment INSTEAD)
3
+ # uj:
4
+ # environment: "development"
@@ -65,7 +65,7 @@
65
65
  <!-- Configuration -->
66
66
  <script type="text/javascript">
67
67
  var Configuration = {
68
- environment: "{{ site.uj.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-block">
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-1">
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-block">
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-2">
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="{{ site.uj.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
- <div class="d-flex align-items-center">
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
- </div>
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-2">
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>
@@ -207,7 +207,7 @@ cta:
207
207
  primary_button:
208
208
  text: "Start Today"
209
209
  icon: "rocket"
210
- href: "/signup"
210
+ href: "/dashboard"
211
211
  secondary_button:
212
212
  text: "Talk to an Expert"
213
213
  icon: "comments"
@@ -32,7 +32,7 @@ pricing:
32
32
  - id: "basic"
33
33
  name: "Basic"
34
34
  tagline: "best for getting started"
35
- url: "/dashboard" # URL for free plan signup
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">Leadership Team</h2>
42
- <p class="fs-5 text-muted">The visionaries and experts driving our mission forward</p>
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
- {% iftruthy member.member.links.website %}
69
- <a href="{{ member.member.links.website }}" 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">
70
- {% uj_icon "globe", "" %}
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
- {% endiftruthy %}
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 link.id, "" %}
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/alexraeburn"
23
+ url: "https://www.linkedin.com/in/alex-raeburn"
24
24
  - id: "instagram"
25
25
  title: "Instagram"
26
- url: "https://www.instagram.com/alexraeburn"
26
+ url: "https://www.instagram.com/_alexraeburn"
27
27
  ---
28
28
 
29
- Hey everyone, I'm Alex. I was born and raised in Beverly Hills, CA. Writing and technology have always been an important part of my life and I'm excited to be a part of this project.
29
+ Hey everyone, I'm Alex!
30
30
 
31
- I love the idea of a social media bot and how it can make our lives easier.
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 also enjoy tending to my Instagram. It's very important to me.
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 is a passionate full-stack developer with over 8 years of experience building scalable web applications. He leads our development team and is dedicated to crafting elegant solutions to complex problems."
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
- Alfred brings a wealth of technical expertise and leadership to our team. With a background in computer science from Stanford University, he has worked at several tech startups before joining us to help build innovative solutions.
30
+ Hey there, I'm Alfred!
34
31
 
35
- His passion for clean code and best practices has helped establish our development standards and mentorship programs. When he's not coding, you can find him contributing to open-source projects or exploring the trails around the Bay Area.
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.