@flamingo-stack/openframe-frontend-core 0.0.406 → 0.0.407-snapshot.20260711133234

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 (167) hide show
  1. package/dist/{chunk-3KEBI6TP.cjs → chunk-2B6773QM.cjs} +1 -1
  2. package/dist/chunk-2B6773QM.cjs.map +1 -0
  3. package/dist/{chunk-TFDNJTBX.js → chunk-5HOII3WB.js} +4 -4
  4. package/dist/{chunk-E6YHDT3D.js → chunk-7Q52HP45.js} +2 -2
  5. package/dist/chunk-7Q52HP45.js.map +1 -0
  6. package/dist/{chunk-VZGU4BV6.cjs → chunk-A3RW7M6B.cjs} +29 -29
  7. package/dist/{chunk-VZGU4BV6.cjs.map → chunk-A3RW7M6B.cjs.map} +1 -1
  8. package/dist/{chunk-QAFRLO5N.cjs → chunk-CUN4CJUN.cjs} +10 -11
  9. package/dist/chunk-CUN4CJUN.cjs.map +1 -0
  10. package/dist/{chunk-6WMVBCNA.js → chunk-E4J5KKHH.js} +3 -3
  11. package/dist/{chunk-P43ZHPM6.cjs → chunk-F4KE5AZO.cjs} +40 -40
  12. package/dist/{chunk-P43ZHPM6.cjs.map → chunk-F4KE5AZO.cjs.map} +1 -1
  13. package/dist/{chunk-PQN5R5II.js → chunk-IK5AR6QG.js} +7 -7
  14. package/dist/{chunk-SOK32D6C.js → chunk-IVM47EGI.js} +346 -297
  15. package/dist/chunk-IVM47EGI.js.map +1 -0
  16. package/dist/{chunk-AYFWYOL6.js → chunk-J6M2G6TD.js} +7 -7
  17. package/dist/{chunk-NA7XJRWB.js → chunk-KFQXO7QB.js} +1 -1
  18. package/dist/chunk-KFQXO7QB.js.map +1 -0
  19. package/dist/{chunk-ISYVNPRT.cjs → chunk-KPGKNUJF.cjs} +42 -42
  20. package/dist/{chunk-ISYVNPRT.cjs.map → chunk-KPGKNUJF.cjs.map} +1 -1
  21. package/dist/{chunk-GNS65HNC.cjs → chunk-KRLBVBYU.cjs} +18 -18
  22. package/dist/{chunk-GNS65HNC.cjs.map → chunk-KRLBVBYU.cjs.map} +1 -1
  23. package/dist/{chunk-ZVUR3A33.js → chunk-KZPVN7AZ.js} +2 -2
  24. package/dist/{chunk-7RVSGGO6.js → chunk-L6OPVKVR.js} +6 -6
  25. package/dist/{chunk-OATWTTCI.js → chunk-LQWYXIKB.js} +6 -6
  26. package/dist/{chunk-COERBDG4.cjs → chunk-NEMUCNCG.cjs} +75 -75
  27. package/dist/{chunk-COERBDG4.cjs.map → chunk-NEMUCNCG.cjs.map} +1 -1
  28. package/dist/{chunk-PNJ5LMVK.js → chunk-NO2KT42M.js} +9 -10
  29. package/dist/{chunk-PNJ5LMVK.js.map → chunk-NO2KT42M.js.map} +1 -1
  30. package/dist/{chunk-LSPBPUQM.js → chunk-O5W26SCL.js} +2 -2
  31. package/dist/{chunk-VANFD4FX.cjs → chunk-RL344I7V.cjs} +7 -7
  32. package/dist/{chunk-VANFD4FX.cjs.map → chunk-RL344I7V.cjs.map} +1 -1
  33. package/dist/{chunk-CF3LBCNI.cjs → chunk-RPGFIUN3.cjs} +35 -35
  34. package/dist/{chunk-CF3LBCNI.cjs.map → chunk-RPGFIUN3.cjs.map} +1 -1
  35. package/dist/{chunk-LL4QQSAD.cjs → chunk-SOALFYU6.cjs} +479 -430
  36. package/dist/chunk-SOALFYU6.cjs.map +1 -0
  37. package/dist/{chunk-CCIBZ7TO.cjs → chunk-STGWQFYT.cjs} +5 -5
  38. package/dist/chunk-STGWQFYT.cjs.map +1 -0
  39. package/dist/{chunk-VIB4SGCD.cjs → chunk-T6ZUBXPA.cjs} +14 -14
  40. package/dist/{chunk-VIB4SGCD.cjs.map → chunk-T6ZUBXPA.cjs.map} +1 -1
  41. package/dist/{chunk-HJJXNMM7.cjs → chunk-V3EZQWHQ.cjs} +7 -7
  42. package/dist/{chunk-HJJXNMM7.cjs.map → chunk-V3EZQWHQ.cjs.map} +1 -1
  43. package/dist/{chunk-3KZXOLFK.js → chunk-VUW4G6SU.js} +4 -4
  44. package/dist/{chunk-JAPP2F4M.cjs → chunk-WGOATV3P.cjs} +77 -77
  45. package/dist/{chunk-JAPP2F4M.cjs.map → chunk-WGOATV3P.cjs.map} +1 -1
  46. package/dist/{chunk-SF4G7M6U.cjs → chunk-YRKPMYI3.cjs} +15 -15
  47. package/dist/{chunk-SF4G7M6U.cjs.map → chunk-YRKPMYI3.cjs.map} +1 -1
  48. package/dist/{chunk-XXG2Z2JT.js → chunk-ZF5O3KUQ.js} +3 -3
  49. package/dist/{chunk-C3NPMZBI.js → chunk-ZMFQWMM7.js} +3 -3
  50. package/dist/components/announcement-bar.d.ts.map +1 -1
  51. package/dist/components/case-studies/index.cjs +11 -10
  52. package/dist/components/case-studies/index.cjs.map +1 -1
  53. package/dist/components/case-studies/index.js +5 -4
  54. package/dist/components/case-studies/index.js.map +1 -1
  55. package/dist/components/chat/index.cjs +5 -4
  56. package/dist/components/chat/index.cjs.map +1 -1
  57. package/dist/components/chat/index.js +4 -3
  58. package/dist/components/chat/quick-action-chip.d.ts +11 -2
  59. package/dist/components/chat/quick-action-chip.d.ts.map +1 -1
  60. package/dist/components/contact/index.cjs +6 -5
  61. package/dist/components/contact/index.cjs.map +1 -1
  62. package/dist/components/contact/index.js +5 -4
  63. package/dist/components/docs/index.cjs +8 -8
  64. package/dist/components/docs/index.js +7 -7
  65. package/dist/components/embeds/index.cjs +6 -5
  66. package/dist/components/embeds/index.cjs.map +1 -1
  67. package/dist/components/embeds/index.js +5 -4
  68. package/dist/components/embeds/reddit-embed-client.d.ts.map +1 -1
  69. package/dist/components/faq/index.cjs +7 -6
  70. package/dist/components/faq/index.cjs.map +1 -1
  71. package/dist/components/faq/index.js +6 -5
  72. package/dist/components/features/index.cjs +5 -4
  73. package/dist/components/features/index.cjs.map +1 -1
  74. package/dist/components/features/index.js +4 -3
  75. package/dist/components/help-center-pages/index.cjs +24 -24
  76. package/dist/components/help-center-pages/index.js +15 -15
  77. package/dist/components/index.cjs +186 -180
  78. package/dist/components/index.cjs.map +1 -1
  79. package/dist/components/index.d.ts +1 -0
  80. package/dist/components/index.d.ts.map +1 -1
  81. package/dist/components/index.js +39 -33
  82. package/dist/components/index.js.map +1 -1
  83. package/dist/components/media-carousel.d.ts +28 -4
  84. package/dist/components/media-carousel.d.ts.map +1 -1
  85. package/dist/components/navigation/index.cjs +5 -4
  86. package/dist/components/navigation/index.cjs.map +1 -1
  87. package/dist/components/navigation/index.js +4 -3
  88. package/dist/components/onboarding-guides/index.cjs +9 -9
  89. package/dist/components/onboarding-guides/index.js +8 -8
  90. package/dist/components/related-content/index.cjs +7 -6
  91. package/dist/components/related-content/index.cjs.map +1 -1
  92. package/dist/components/related-content/index.js +6 -5
  93. package/dist/components/tickets/index.cjs +8 -8
  94. package/dist/components/tickets/index.js +7 -7
  95. package/dist/components/ui/index.cjs +5 -4
  96. package/dist/components/ui/index.cjs.map +1 -1
  97. package/dist/components/ui/index.js +4 -3
  98. package/dist/components/ui/tag.d.ts +3 -2
  99. package/dist/components/ui/tag.d.ts.map +1 -1
  100. package/dist/contexts/endpoints-runtime-context.d.ts +1 -1
  101. package/dist/contexts/endpoints-runtime-context.d.ts.map +1 -1
  102. package/dist/contexts/index.cjs +2 -2
  103. package/dist/contexts/index.js +1 -1
  104. package/dist/hooks/index.cjs +3 -3
  105. package/dist/hooks/index.js +2 -2
  106. package/dist/hooks/use-self-fetch.d.ts.map +1 -1
  107. package/dist/index.cjs +5 -4
  108. package/dist/index.cjs.map +1 -1
  109. package/dist/index.js +6 -5
  110. package/dist/types/announcement.cjs.map +1 -1
  111. package/dist/types/announcement.d.ts +0 -6
  112. package/dist/types/announcement.d.ts.map +1 -1
  113. package/dist/types/announcement.js.map +1 -1
  114. package/dist/types/index.cjs.map +1 -1
  115. package/dist/types/index.js.map +1 -1
  116. package/dist/utils/announcement-storage.d.ts +3 -0
  117. package/dist/utils/announcement-storage.d.ts.map +1 -1
  118. package/dist/utils/app-config.d.ts.map +1 -1
  119. package/dist/utils/color-analysis.d.ts +0 -4
  120. package/dist/utils/color-analysis.d.ts.map +1 -1
  121. package/dist/utils/index.cjs +186 -177
  122. package/dist/utils/index.cjs.map +1 -1
  123. package/dist/utils/index.js +185 -176
  124. package/dist/utils/index.js.map +1 -1
  125. package/dist/utils/media-carousel-utils-stub.d.ts +3 -1
  126. package/dist/utils/media-carousel-utils-stub.d.ts.map +1 -1
  127. package/dist/utils/ods-color-utils.d.ts +2 -1
  128. package/dist/utils/ods-color-utils.d.ts.map +1 -1
  129. package/package.json +1 -1
  130. package/src/components/announcement-bar.tsx +38 -21
  131. package/src/components/chat/quick-action-chip.tsx +18 -4
  132. package/src/components/embeds/reddit-embed-client.tsx +0 -3
  133. package/src/components/index.ts +5 -0
  134. package/src/components/media-carousel.tsx +195 -149
  135. package/src/components/ui/tag.tsx +21 -3
  136. package/src/contexts/endpoints-runtime-context.tsx +1 -1
  137. package/src/hooks/use-self-fetch.ts +10 -9
  138. package/src/stories/AnnouncementBar.stories.tsx +8 -14
  139. package/src/styles/ods-design-tokens.css +2 -0
  140. package/src/types/announcement.ts +0 -8
  141. package/src/utils/announcement-storage.ts +17 -0
  142. package/src/utils/app-config.ts +3 -2
  143. package/src/utils/color-analysis.ts +5 -2
  144. package/src/utils/media-carousel-utils-stub.ts +3 -1
  145. package/src/utils/ods-color-utils.ts +4 -7
  146. package/dist/chunk-3KEBI6TP.cjs.map +0 -1
  147. package/dist/chunk-CCIBZ7TO.cjs.map +0 -1
  148. package/dist/chunk-E6YHDT3D.js.map +0 -1
  149. package/dist/chunk-LL4QQSAD.cjs.map +0 -1
  150. package/dist/chunk-NA7XJRWB.js.map +0 -1
  151. package/dist/chunk-QAFRLO5N.cjs.map +0 -1
  152. package/dist/chunk-SOK32D6C.js.map +0 -1
  153. package/dist/utils/media-carousel-utils.d.ts +0 -10
  154. package/dist/utils/media-carousel-utils.d.ts.map +0 -1
  155. package/src/utils/.media-carousel-utils.md +0 -31
  156. package/src/utils/media-carousel-utils.ts +0 -22
  157. /package/dist/{chunk-TFDNJTBX.js.map → chunk-5HOII3WB.js.map} +0 -0
  158. /package/dist/{chunk-6WMVBCNA.js.map → chunk-E4J5KKHH.js.map} +0 -0
  159. /package/dist/{chunk-PQN5R5II.js.map → chunk-IK5AR6QG.js.map} +0 -0
  160. /package/dist/{chunk-AYFWYOL6.js.map → chunk-J6M2G6TD.js.map} +0 -0
  161. /package/dist/{chunk-ZVUR3A33.js.map → chunk-KZPVN7AZ.js.map} +0 -0
  162. /package/dist/{chunk-7RVSGGO6.js.map → chunk-L6OPVKVR.js.map} +0 -0
  163. /package/dist/{chunk-OATWTTCI.js.map → chunk-LQWYXIKB.js.map} +0 -0
  164. /package/dist/{chunk-LSPBPUQM.js.map → chunk-O5W26SCL.js.map} +0 -0
  165. /package/dist/{chunk-3KZXOLFK.js.map → chunk-VUW4G6SU.js.map} +0 -0
  166. /package/dist/{chunk-XXG2Z2JT.js.map → chunk-ZF5O3KUQ.js.map} +0 -0
  167. /package/dist/{chunk-C3NPMZBI.js.map → chunk-ZMFQWMM7.js.map} +0 -0
@@ -468,6 +468,174 @@ function formatBioText(aboutHtml, fallback = "") {
468
468
  }
469
469
  var PLAY_ICON_PATH = "M4.875 5.006c0-2.501 2.793-3.989 4.87-2.592l9.78 6.578c2.135 1.437 2.135 4.58 0 6.016l-9.78 6.579c-2.077 1.396-4.87-.091-4.87-2.593zm2.25 13.988c0 .7.783 1.118 1.364.727l9.78-6.58c.81-.545.81-1.738 0-2.283L8.488 4.28a.875.875 0 0 0-1.364.726v13.988Z";
470
470
 
471
+ // src/utils/color-analysis.ts
472
+ var DESIGN_PALETTE = [
473
+ { name: "yellow", hex: "#FFC008", rgb: [255, 192, 8] },
474
+ { name: "black", hex: "#161616", rgb: [22, 22, 22] },
475
+ { name: "gray", hex: "#888888", rgb: [136, 136, 136] }
476
+ ];
477
+ function hexToRgb(hex) {
478
+ const normalized = hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, (_, r, g, b) => `${r}${r}${g}${g}${b}${b}`);
479
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(normalized);
480
+ return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : [0, 0, 0];
481
+ }
482
+ function getLuminance(rgb) {
483
+ const [r, g, b] = rgb.map((c) => {
484
+ c = c / 255;
485
+ return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
486
+ });
487
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
488
+ }
489
+ function getContrastRatio(color1, color2) {
490
+ const lum1 = getLuminance(color1);
491
+ const lum2 = getLuminance(color2);
492
+ const brightest = Math.max(lum1, lum2);
493
+ const darkest = Math.min(lum1, lum2);
494
+ return (brightest + 0.05) / (darkest + 0.05);
495
+ }
496
+ function pickReadableTextColor(bgHex) {
497
+ const bg = hexToRgb(bgHex);
498
+ const darkContrast = getContrastRatio(bg, [26, 26, 26]);
499
+ const lightContrast = getContrastRatio(bg, [250, 250, 250]);
500
+ return darkContrast >= lightContrast ? "dark" : "light";
501
+ }
502
+ function extractDominantColor(canvas) {
503
+ const ctx = canvas.getContext("2d");
504
+ if (!ctx) return [128, 128, 128];
505
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
506
+ const data = imageData.data;
507
+ const sampleSize = Math.max(1, Math.floor(data.length / (4 * 1e3)));
508
+ const colorCounts = {};
509
+ for (let i = 0; i < data.length; i += 4 * sampleSize) {
510
+ const r = data[i];
511
+ const g = data[i + 1];
512
+ const b = data[i + 2];
513
+ const alpha = data[i + 3];
514
+ if (alpha < 128) continue;
515
+ const bucketR = Math.round(r / 32) * 32;
516
+ const bucketG = Math.round(g / 32) * 32;
517
+ const bucketB = Math.round(b / 32) * 32;
518
+ const key = `${bucketR},${bucketG},${bucketB}`;
519
+ colorCounts[key] = (colorCounts[key] || 0) + 1;
520
+ }
521
+ let maxCount = 0;
522
+ let dominantColor = [128, 128, 128];
523
+ for (const [colorKey, count] of Object.entries(colorCounts)) {
524
+ if (count > maxCount) {
525
+ maxCount = count;
526
+ const [r, g, b] = colorKey.split(",").map(Number);
527
+ dominantColor = [r, g, b];
528
+ }
529
+ }
530
+ return dominantColor;
531
+ }
532
+ function getBestContrastColor(imageColor) {
533
+ let bestColor = DESIGN_PALETTE[0];
534
+ let bestContrast = 0;
535
+ for (const color of DESIGN_PALETTE) {
536
+ const contrast = getContrastRatio(imageColor, color.rgb);
537
+ if (contrast > bestContrast) {
538
+ bestContrast = contrast;
539
+ bestColor = color;
540
+ }
541
+ }
542
+ return bestContrast >= 3 ? bestColor : DESIGN_PALETTE.find((c) => c.name === "black") || bestColor;
543
+ }
544
+ function analyzeImageColor(imageSrc) {
545
+ return new Promise((resolve, reject) => {
546
+ const img = new Image();
547
+ img.crossOrigin = "anonymous";
548
+ img.onload = () => {
549
+ try {
550
+ const canvas = document.createElement("canvas");
551
+ const ctx = canvas.getContext("2d");
552
+ if (!ctx) {
553
+ reject(new Error("Could not get canvas context"));
554
+ return;
555
+ }
556
+ const maxSize = 100;
557
+ const scale = Math.min(maxSize / img.width, maxSize / img.height);
558
+ canvas.width = img.width * scale;
559
+ canvas.height = img.height * scale;
560
+ ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
561
+ const dominantColor = extractDominantColor(canvas);
562
+ const bestContrastColor = getBestContrastColor(dominantColor);
563
+ resolve(bestContrastColor);
564
+ } catch (error) {
565
+ reject(error);
566
+ }
567
+ };
568
+ img.onerror = () => reject(new Error("Failed to load image"));
569
+ img.src = imageSrc;
570
+ });
571
+ }
572
+ async function extractImageEdgeColorAsync(imageUrl) {
573
+ return new Promise((resolve) => {
574
+ if (typeof window === "undefined") {
575
+ resolve("#000000");
576
+ return;
577
+ }
578
+ const img = new Image();
579
+ img.crossOrigin = "anonymous";
580
+ img.onload = () => {
581
+ try {
582
+ const canvas = document.createElement("canvas");
583
+ const ctx = canvas.getContext("2d");
584
+ if (!ctx) {
585
+ resolve("#000000");
586
+ return;
587
+ }
588
+ const maxSize = 50;
589
+ const scale = Math.min(maxSize / img.naturalWidth, maxSize / img.naturalHeight);
590
+ const w = Math.round(img.naturalWidth * scale);
591
+ const h = Math.round(img.naturalHeight * scale);
592
+ canvas.width = w;
593
+ canvas.height = h;
594
+ ctx.drawImage(img, 0, 0, w, h);
595
+ const data = ctx.getImageData(0, 0, w, h).data;
596
+ const edgeW = Math.max(2, Math.round(w * 0.15));
597
+ const edgeH = Math.max(2, Math.round(h * 0.15));
598
+ const bucketSize = 32;
599
+ const buckets = /* @__PURE__ */ new Map();
600
+ for (let y = 0; y < h; y++) {
601
+ for (let x = 0; x < w; x++) {
602
+ if (!(x < edgeW || x >= w - edgeW || y < edgeH || y >= h - edgeH)) continue;
603
+ const i = (y * w + x) * 4;
604
+ if (data[i + 3] < 128) continue;
605
+ const br = Math.floor(data[i] / bucketSize) * bucketSize;
606
+ const bg = Math.floor(data[i + 1] / bucketSize) * bucketSize;
607
+ const bb = Math.floor(data[i + 2] / bucketSize) * bucketSize;
608
+ const key = `${br},${bg},${bb}`;
609
+ const existing = buckets.get(key);
610
+ if (existing) {
611
+ existing.r += data[i];
612
+ existing.g += data[i + 1];
613
+ existing.b += data[i + 2];
614
+ existing.count++;
615
+ } else {
616
+ buckets.set(key, { r: data[i], g: data[i + 1], b: data[i + 2], count: 1 });
617
+ }
618
+ }
619
+ }
620
+ let best = { r: 0, g: 0, b: 0, count: 0 };
621
+ for (const b2 of buckets.values()) {
622
+ if (b2.count > best.count) best = b2;
623
+ }
624
+ if (best.count === 0) {
625
+ resolve("#000000");
626
+ return;
627
+ }
628
+ const r = Math.round(best.r / best.count), g = Math.round(best.g / best.count), b = Math.round(best.b / best.count);
629
+ resolve(`#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`);
630
+ } catch {
631
+ resolve("#000000");
632
+ }
633
+ };
634
+ img.onerror = () => resolve("#000000");
635
+ img.src = imageUrl;
636
+ });
637
+ }
638
+
471
639
  // src/utils/ods-color-utils.ts
472
640
  function getPlatformAccentColor(platform) {
473
641
  const currentPlatform = platform || getCurrentPlatform();
@@ -492,18 +660,13 @@ function getCurrentPlatform() {
492
660
  return process.env.NEXT_PUBLIC_APP_TYPE || "openmsp";
493
661
  }
494
662
  function getReadableTextColor(hex) {
495
- const n = parseInt(hex.replace("#", ""), 16);
496
- const r = n >> 16 & 255;
497
- const g = n >> 8 & 255;
498
- const b = n & 255;
499
- const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
500
- return luminance > 0.5 ? "#212121" : "#fafafa";
663
+ return pickReadableTextColor(hex) === "dark" ? "#212121" : "#fafafa";
501
664
  }
502
665
  var HEX_PATTERN = /^#[0-9a-fA-F]{6}$/;
503
666
  function clamp(n, min, max) {
504
667
  return Math.max(min, Math.min(max, n));
505
668
  }
506
- function hexToRgb(hex) {
669
+ function hexToRgb2(hex) {
507
670
  if (!HEX_PATTERN.test(hex)) return null;
508
671
  const n = Number.parseInt(hex.slice(1), 16);
509
672
  return { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
@@ -515,7 +678,7 @@ function rgbToHex(r, g, b) {
515
678
  var HOVER_DARKEN_STEP = 10;
516
679
  var ACTIVE_DARKEN_STEP = 20;
517
680
  function darkenByStep(hex, step) {
518
- const rgb = hexToRgb(hex);
681
+ const rgb = hexToRgb2(hex);
519
682
  if (!rgb) return hex;
520
683
  return rgbToHex(rgb.r - step, rgb.g - step, rgb.b - step);
521
684
  }
@@ -2318,173 +2481,6 @@ function isGenericWebsiteDomain(website) {
2318
2481
  return isGenericDomain(normalizeDomain(website));
2319
2482
  }
2320
2483
 
2321
- // src/utils/color-analysis.ts
2322
- var DESIGN_PALETTE = [
2323
- { name: "yellow", hex: "#FFC008", rgb: [255, 192, 8] },
2324
- { name: "black", hex: "#161616", rgb: [22, 22, 22] },
2325
- { name: "gray", hex: "#888888", rgb: [136, 136, 136] }
2326
- ];
2327
- function hexToRgb2(hex) {
2328
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
2329
- return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : [0, 0, 0];
2330
- }
2331
- function getLuminance(rgb) {
2332
- const [r, g, b] = rgb.map((c) => {
2333
- c = c / 255;
2334
- return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
2335
- });
2336
- return 0.2126 * r + 0.7152 * g + 0.0722 * b;
2337
- }
2338
- function getContrastRatio(color1, color2) {
2339
- const lum1 = getLuminance(color1);
2340
- const lum2 = getLuminance(color2);
2341
- const brightest = Math.max(lum1, lum2);
2342
- const darkest = Math.min(lum1, lum2);
2343
- return (brightest + 0.05) / (darkest + 0.05);
2344
- }
2345
- function pickReadableTextColor(bgHex) {
2346
- const bg = hexToRgb2(bgHex);
2347
- const darkContrast = getContrastRatio(bg, [26, 26, 26]);
2348
- const lightContrast = getContrastRatio(bg, [250, 250, 250]);
2349
- return darkContrast >= lightContrast ? "dark" : "light";
2350
- }
2351
- function extractDominantColor(canvas) {
2352
- const ctx = canvas.getContext("2d");
2353
- if (!ctx) return [128, 128, 128];
2354
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
2355
- const data = imageData.data;
2356
- const sampleSize = Math.max(1, Math.floor(data.length / (4 * 1e3)));
2357
- const colorCounts = {};
2358
- for (let i = 0; i < data.length; i += 4 * sampleSize) {
2359
- const r = data[i];
2360
- const g = data[i + 1];
2361
- const b = data[i + 2];
2362
- const alpha = data[i + 3];
2363
- if (alpha < 128) continue;
2364
- const bucketR = Math.round(r / 32) * 32;
2365
- const bucketG = Math.round(g / 32) * 32;
2366
- const bucketB = Math.round(b / 32) * 32;
2367
- const key = `${bucketR},${bucketG},${bucketB}`;
2368
- colorCounts[key] = (colorCounts[key] || 0) + 1;
2369
- }
2370
- let maxCount = 0;
2371
- let dominantColor = [128, 128, 128];
2372
- for (const [colorKey, count] of Object.entries(colorCounts)) {
2373
- if (count > maxCount) {
2374
- maxCount = count;
2375
- const [r, g, b] = colorKey.split(",").map(Number);
2376
- dominantColor = [r, g, b];
2377
- }
2378
- }
2379
- return dominantColor;
2380
- }
2381
- function getBestContrastColor(imageColor) {
2382
- let bestColor = DESIGN_PALETTE[0];
2383
- let bestContrast = 0;
2384
- for (const color of DESIGN_PALETTE) {
2385
- const contrast = getContrastRatio(imageColor, color.rgb);
2386
- if (contrast > bestContrast) {
2387
- bestContrast = contrast;
2388
- bestColor = color;
2389
- }
2390
- }
2391
- return bestContrast >= 3 ? bestColor : DESIGN_PALETTE.find((c) => c.name === "black") || bestColor;
2392
- }
2393
- function analyzeImageColor(imageSrc) {
2394
- return new Promise((resolve, reject) => {
2395
- const img = new Image();
2396
- img.crossOrigin = "anonymous";
2397
- img.onload = () => {
2398
- try {
2399
- const canvas = document.createElement("canvas");
2400
- const ctx = canvas.getContext("2d");
2401
- if (!ctx) {
2402
- reject(new Error("Could not get canvas context"));
2403
- return;
2404
- }
2405
- const maxSize = 100;
2406
- const scale = Math.min(maxSize / img.width, maxSize / img.height);
2407
- canvas.width = img.width * scale;
2408
- canvas.height = img.height * scale;
2409
- ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
2410
- const dominantColor = extractDominantColor(canvas);
2411
- const bestContrastColor = getBestContrastColor(dominantColor);
2412
- resolve(bestContrastColor);
2413
- } catch (error) {
2414
- reject(error);
2415
- }
2416
- };
2417
- img.onerror = () => reject(new Error("Failed to load image"));
2418
- img.src = imageSrc;
2419
- });
2420
- }
2421
- async function extractImageEdgeColorAsync(imageUrl) {
2422
- return new Promise((resolve) => {
2423
- if (typeof window === "undefined") {
2424
- resolve("#000000");
2425
- return;
2426
- }
2427
- const img = new Image();
2428
- img.crossOrigin = "anonymous";
2429
- img.onload = () => {
2430
- try {
2431
- const canvas = document.createElement("canvas");
2432
- const ctx = canvas.getContext("2d");
2433
- if (!ctx) {
2434
- resolve("#000000");
2435
- return;
2436
- }
2437
- const maxSize = 50;
2438
- const scale = Math.min(maxSize / img.naturalWidth, maxSize / img.naturalHeight);
2439
- const w = Math.round(img.naturalWidth * scale);
2440
- const h = Math.round(img.naturalHeight * scale);
2441
- canvas.width = w;
2442
- canvas.height = h;
2443
- ctx.drawImage(img, 0, 0, w, h);
2444
- const data = ctx.getImageData(0, 0, w, h).data;
2445
- const edgeW = Math.max(2, Math.round(w * 0.15));
2446
- const edgeH = Math.max(2, Math.round(h * 0.15));
2447
- const bucketSize = 32;
2448
- const buckets = /* @__PURE__ */ new Map();
2449
- for (let y = 0; y < h; y++) {
2450
- for (let x = 0; x < w; x++) {
2451
- if (!(x < edgeW || x >= w - edgeW || y < edgeH || y >= h - edgeH)) continue;
2452
- const i = (y * w + x) * 4;
2453
- if (data[i + 3] < 128) continue;
2454
- const br = Math.floor(data[i] / bucketSize) * bucketSize;
2455
- const bg = Math.floor(data[i + 1] / bucketSize) * bucketSize;
2456
- const bb = Math.floor(data[i + 2] / bucketSize) * bucketSize;
2457
- const key = `${br},${bg},${bb}`;
2458
- const existing = buckets.get(key);
2459
- if (existing) {
2460
- existing.r += data[i];
2461
- existing.g += data[i + 1];
2462
- existing.b += data[i + 2];
2463
- existing.count++;
2464
- } else {
2465
- buckets.set(key, { r: data[i], g: data[i + 1], b: data[i + 2], count: 1 });
2466
- }
2467
- }
2468
- }
2469
- let best = { r: 0, g: 0, b: 0, count: 0 };
2470
- for (const b2 of buckets.values()) {
2471
- if (b2.count > best.count) best = b2;
2472
- }
2473
- if (best.count === 0) {
2474
- resolve("#000000");
2475
- return;
2476
- }
2477
- const r = Math.round(best.r / best.count), g = Math.round(best.g / best.count), b = Math.round(best.b / best.count);
2478
- resolve(`#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`);
2479
- } catch {
2480
- resolve("#000000");
2481
- }
2482
- };
2483
- img.onerror = () => resolve("#000000");
2484
- img.src = imageUrl;
2485
- });
2486
- }
2487
-
2488
2484
  // src/utils/announcement-storage.ts
2489
2485
  function announcementDismissCookieName(platform) {
2490
2486
  return `${platform}-announcement-dismissed`;
@@ -2513,6 +2509,19 @@ function isAnnouncementDismissed(platform, id) {
2513
2509
  return false;
2514
2510
  }
2515
2511
  }
2512
+ function clearAnnouncementDismissals(platform) {
2513
+ if (typeof document === "undefined") return;
2514
+ document.cookie = `${announcementDismissCookieName(platform)}=; path=/; max-age=0`;
2515
+ try {
2516
+ const prefix = `${platform}-announcement-`;
2517
+ Object.keys(localStorage).forEach((key) => {
2518
+ if (key.startsWith(prefix) && key.endsWith("-dismissed")) {
2519
+ localStorage.removeItem(key);
2520
+ }
2521
+ });
2522
+ } catch {
2523
+ }
2524
+ }
2516
2525
  function clearLegacyAnnouncementCache(platform) {
2517
2526
  if (typeof window === "undefined") return;
2518
2527
  try {
@@ -4091,6 +4100,7 @@ exports.buildOgPlaceholderUrl = buildOgPlaceholderUrl;
4091
4100
  exports.buildSuggestionUrl = buildSuggestionUrl;
4092
4101
  exports.canonicalContentRefType = canonicalContentRefType;
4093
4102
  exports.cleanEmailDomain = cleanEmailDomain;
4103
+ exports.clearAnnouncementDismissals = clearAnnouncementDismissals;
4094
4104
  exports.clearEmbedProxyAuth = clearEmbedProxyAuth;
4095
4105
  exports.clearLegacyAnnouncementCache = clearLegacyAnnouncementCache;
4096
4106
  exports.clickupTaskUrl = clickupTaskUrl;
@@ -4185,7 +4195,6 @@ exports.getEmbedProxyAuth = getEmbedProxyAuth;
4185
4195
  exports.getFirstLastInitials = getFirstLastInitials;
4186
4196
  exports.getIconComponent = getIconComponent;
4187
4197
  exports.getInitialExpandedNodeIds = getInitialExpandedNodeIds;
4188
- exports.getLuminance = getLuminance;
4189
4198
  exports.getOSIcon = getOSIcon;
4190
4199
  exports.getOSLabel = getOSLabel;
4191
4200
  exports.getOSPlatformId = getOSPlatformId;
@@ -4214,7 +4223,7 @@ exports.getToolLabel = getToolLabel;
4214
4223
  exports.getToolTypeAliases = getToolTypeAliases;
4215
4224
  exports.getTrendColors = getTrendColors;
4216
4225
  exports.hasGenericEmailDomain = hasGenericEmailDomain;
4217
- exports.hexToRgb = hexToRgb;
4226
+ exports.hexToRgb = hexToRgb2;
4218
4227
  exports.isAnnouncementDismissed = isAnnouncementDismissed;
4219
4228
  exports.isCrossOriginUrl = isCrossOriginUrl;
4220
4229
  exports.isDismissedCookieValue = isDismissedCookieValue;