ultimate-jekyll-manager 0.0.135 → 0.0.137

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/TODO.md CHANGED
@@ -98,10 +98,6 @@ REMAKE main/misc/embed-manager.html in UJ
98
98
  REMAKE the dashboard one in UJ
99
99
  FINISH redirec.js in UJ
100
100
 
101
- # Update git remote url
102
- * Check git remote get-url origin
103
- * Update to correct one if necessary (imagemin wont work unless tis is accurate)
104
-
105
101
  # Fix notifications
106
102
  * UJ 2.0 for a while was making a DUPLICATE notifaction in users/{uid}/notifications/{token} AND in notifications/{token}
107
103
  * We can SAFELY DELETE the users/{uid}/notifications collection
@@ -15,11 +15,6 @@ article .blog-post-content {
15
15
  margin-top: 2.5rem;
16
16
  }
17
17
 
18
- // .uj-vert-unit {
19
- // margin-top: 2.5rem;
20
- // margin-bottom: 2.5rem;
21
- // }
22
-
23
18
  // First heading shouldn't have extra top margin
24
19
  // > :first-child {
25
20
  // margin-top: 0;
@@ -40,7 +40,9 @@ function insertBlogPostAds() {
40
40
  }
41
41
 
42
42
  // Find valid positions to insert ads (every 4 paragraphs)
43
+ // But ensure the last ad isn't too close to the end of the article
43
44
  const positions = [];
45
+ const minParagraphsAfterLastAd = 2; // Ensure at least 2 paragraphs after the last ad
44
46
 
45
47
  for (let i = 0; i < $paragraphs.length; i++) {
46
48
  // Only consider every 4th paragraph
@@ -48,6 +50,12 @@ function insertBlogPostAds() {
48
50
  continue;
49
51
  }
50
52
 
53
+ // Skip if this position is too close to the end of the article
54
+ const paragraphsRemaining = $paragraphs.length - 1 - i;
55
+ if (paragraphsRemaining < minParagraphsAfterLastAd) {
56
+ continue;
57
+ }
58
+
51
59
  const $p = $paragraphs[i];
52
60
  const $prevSibling = $p.previousElementSibling;
53
61
 
@@ -101,6 +109,7 @@ function insertBlogPostAds() {
101
109
 
102
110
  // Set data-lazy attribute
103
111
  $adContainer.setAttribute('data-lazy', `@script ${JSON.stringify(lazyConfig)}`);
112
+ $adContainer.classList.add('my-4');
104
113
 
105
114
  // Insert after the target paragraph
106
115
  targetParagraph.parentNode.insertBefore($adContainer, targetParagraph.nextSibling);
@@ -42,6 +42,7 @@ module.exports = async function (options) {
42
42
  options.updateBundle = options.updateBundle !== 'false';
43
43
  options.publishGitHubToken = options.publishGitHubToken !== 'false';
44
44
  options.updateGitHubPages = options.updateGitHubPages !== 'false';
45
+ options.deduplicatePosts = options.deduplicatePosts !== 'false';
45
46
 
46
47
  // Log
47
48
  logger.log(`Welcome to ${package.name} v${package.version}!`);
@@ -125,6 +126,11 @@ module.exports = async function (options) {
125
126
  if (options.updateBundle && !Manager.isServer()) {
126
127
  await updateBundle();
127
128
  }
129
+
130
+ // Deduplicate posts (remove duplicate posts with same slug but different dates)
131
+ if (options.deduplicatePosts) {
132
+ await deduplicatePosts();
133
+ }
128
134
  } catch (e) {
129
135
  // Throw error
130
136
  throw e;
@@ -599,7 +605,7 @@ async function updateGitHubPages(options) {
599
605
  owner,
600
606
  repo,
601
607
  source: sourceConfig,
602
- };
608
+ };
603
609
 
604
610
  // Add custom domain if available and not github.io domain
605
611
  if (customDomain && !customDomain.includes('github.io')) {
@@ -654,3 +660,117 @@ async function updateGitHubPages(options) {
654
660
  // Don't throw - this is not critical for setup to continue
655
661
  }
656
662
  }
663
+
664
+ // Deduplicate posts - removes duplicate posts with same slug but different dates
665
+ // Keeps the ORIGINAL (oldest) post and removes newer duplicates
666
+ async function deduplicatePosts() {
667
+ logger.log('🔍 Checking for duplicate posts...');
668
+
669
+ // Find all post files in src/_posts
670
+ const postsGlob = 'src/_posts/**/*.{md,markdown,html}';
671
+ const postFiles = glob(postsGlob, { nodir: true });
672
+
673
+ if (postFiles.length === 0) {
674
+ logger.log('No posts found');
675
+ return;
676
+ }
677
+
678
+ logger.log(`Found ${postFiles.length} post files`);
679
+
680
+ // Group posts by slug (filename without date prefix)
681
+ const postsBySlug = {};
682
+
683
+ for (const filePath of postFiles) {
684
+ const filename = path.basename(filePath);
685
+
686
+ // Jekyll post format: YYYY-MM-DD-slug.ext
687
+ const match = filename.match(/^(\d{4}-\d{2}-\d{2})-(.+)\.(md|markdown|html)$/);
688
+
689
+ if (!match) {
690
+ continue;
691
+ }
692
+
693
+ const [, dateStr, slug, ext] = match;
694
+ const date = new Date(dateStr);
695
+
696
+ if (!postsBySlug[slug]) {
697
+ postsBySlug[slug] = [];
698
+ }
699
+
700
+ postsBySlug[slug].push({
701
+ filePath,
702
+ filename,
703
+ date,
704
+ dateStr,
705
+ slug,
706
+ ext,
707
+ });
708
+ }
709
+
710
+ // Find duplicates and keep only the ORIGINAL (oldest)
711
+ let removedCount = 0;
712
+ const duplicates = [];
713
+
714
+ for (const [slug, posts] of Object.entries(postsBySlug)) {
715
+ if (posts.length <= 1) {
716
+ continue;
717
+ }
718
+
719
+ // Sort by date ascending (oldest first)
720
+ posts.sort((a, b) => a.date - b.date);
721
+
722
+ // Keep the oldest (original), mark the rest for removal
723
+ const [original, ...newer] = posts;
724
+
725
+ logger.log(`Found ${posts.length} posts with slug "${slug}":`);
726
+ logger.log(` ✅ Keeping original: ${original.filename} (${original.dateStr})`);
727
+
728
+ for (const post of newer) {
729
+ logger.log(` ❌ Removing duplicate: ${post.filename} (${post.dateStr})`);
730
+
731
+ // Remove the duplicate post file
732
+ try {
733
+ jetpack.remove(post.filePath);
734
+ removedCount++;
735
+
736
+ // Also remove the associated images folder (src/assets/images/blog/post-SLUG)
737
+ const imageFolder = `src/assets/images/blog/post-${post.slug}`;
738
+ if (jetpack.exists(imageFolder)) {
739
+ jetpack.remove(imageFolder);
740
+ logger.log(` 🗑️ Removed image folder: ${imageFolder}`);
741
+ }
742
+
743
+ duplicates.push({
744
+ kept: original.filename,
745
+ removed: post.filename,
746
+ removedPath: post.filePath,
747
+ slug,
748
+ });
749
+ } catch (error) {
750
+ logger.error(`Failed to remove ${post.filePath}:`, error);
751
+ }
752
+ }
753
+ }
754
+
755
+ // Log summary
756
+ if (removedCount > 0) {
757
+ logger.log(`✅ Removed ${removedCount} duplicate post(s)`);
758
+
759
+ // Save report
760
+ const reportDir = path.join(rootPathProject, '.temp/deduplicate');
761
+ jetpack.dir(reportDir);
762
+
763
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
764
+ const reportPath = path.join(reportDir, `duplicates-${timestamp}.json`);
765
+
766
+ jetpack.write(reportPath, JSON.stringify({
767
+ timestamp: new Date().toISOString(),
768
+ removedCount,
769
+ duplicates,
770
+ }, null, 2));
771
+
772
+ logger.log(`Report saved to: ${reportPath}`);
773
+ } else {
774
+ logger.log('✅ No duplicate posts found');
775
+ }
776
+ }
@@ -2396,3 +2396,31 @@
2396
2396
  [debug] [2025-12-04T08:02:22.587Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2397
2397
  [debug] [2025-12-04T08:02:22.588Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2398
2398
  [debug] [2025-12-04T08:02:22.588Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2399
+ [debug] [2025-12-04T19:09:21.046Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2400
+ [debug] [2025-12-04T19:09:21.045Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2401
+ [debug] [2025-12-04T19:09:21.047Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2402
+ [debug] [2025-12-04T19:09:21.047Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2403
+ [debug] [2025-12-04T19:09:21.048Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2404
+ [debug] [2025-12-04T19:09:21.057Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2405
+ [debug] [2025-12-04T19:09:21.057Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2406
+ [debug] [2025-12-04T19:09:21.047Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2407
+ [debug] [2025-12-04T19:09:21.047Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2408
+ [debug] [2025-12-04T19:09:21.048Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2409
+ [debug] [2025-12-04T19:09:21.056Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2410
+ [debug] [2025-12-04T19:09:21.057Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2411
+ [debug] [2025-12-04T19:09:21.106Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2412
+ [debug] [2025-12-04T19:09:21.108Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2413
+ [debug] [2025-12-04T19:09:21.106Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2414
+ [debug] [2025-12-04T19:09:21.107Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2415
+ [debug] [2025-12-04T19:09:21.107Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2416
+ [debug] [2025-12-04T19:09:21.108Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2417
+ [debug] [2025-12-04T19:09:21.108Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2418
+ [debug] [2025-12-04T19:09:21.109Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2419
+ [debug] [2025-12-04T19:09:21.109Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2420
+ [debug] [2025-12-04T19:09:21.109Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2421
+ [debug] [2025-12-04T19:09:21.109Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2422
+ [debug] [2025-12-04T19:09:21.109Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2423
+ [debug] [2025-12-04T19:09:21.111Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2424
+ [debug] [2025-12-04T19:09:21.111Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
2425
+ [debug] [2025-12-04T19:09:21.111Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
2426
+ [debug] [2025-12-04T19:09:21.111Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultimate-jekyll-manager",
3
- "version": "0.0.135",
3
+ "version": "0.0.137",
4
4
  "description": "Ultimate Jekyll dependency manager",
5
5
  "main": "dist/index.js",
6
6
  "exports": {