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

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 (135) hide show
  1. package/dist/{chunk-2B6773QM.cjs → chunk-3KEBI6TP.cjs} +1 -1
  2. package/dist/chunk-3KEBI6TP.cjs.map +1 -0
  3. package/dist/{chunk-HJIRG7R6.js → chunk-3KZXOLFK.js} +4 -4
  4. package/dist/{chunk-43H2WOAW.js → chunk-6WMVBCNA.js} +3 -3
  5. package/dist/{chunk-XFP43YKG.js → chunk-7RVSGGO6.js} +6 -6
  6. package/dist/{chunk-KLBEIJVZ.js → chunk-AYFWYOL6.js} +7 -7
  7. package/dist/{chunk-GMZL4T7C.js → chunk-C3NPMZBI.js} +3 -3
  8. package/dist/{chunk-STGWQFYT.cjs → chunk-CCIBZ7TO.cjs} +5 -5
  9. package/dist/chunk-CCIBZ7TO.cjs.map +1 -0
  10. package/dist/{chunk-Q2MC3CBI.cjs → chunk-CF3LBCNI.cjs} +35 -35
  11. package/dist/{chunk-Q2MC3CBI.cjs.map → chunk-CF3LBCNI.cjs.map} +1 -1
  12. package/dist/{chunk-DOBNDDNE.cjs → chunk-COERBDG4.cjs} +75 -75
  13. package/dist/{chunk-DOBNDDNE.cjs.map → chunk-COERBDG4.cjs.map} +1 -1
  14. package/dist/{chunk-7Q52HP45.js → chunk-E6YHDT3D.js} +2 -2
  15. package/dist/chunk-E6YHDT3D.js.map +1 -0
  16. package/dist/{chunk-74FWQI73.cjs → chunk-GNS65HNC.cjs} +18 -18
  17. package/dist/{chunk-74FWQI73.cjs.map → chunk-GNS65HNC.cjs.map} +1 -1
  18. package/dist/{chunk-WCPUJA3Y.cjs → chunk-HJJXNMM7.cjs} +7 -7
  19. package/dist/{chunk-WCPUJA3Y.cjs.map → chunk-HJJXNMM7.cjs.map} +1 -1
  20. package/dist/{chunk-R4MXLJUS.cjs → chunk-ISYVNPRT.cjs} +42 -42
  21. package/dist/{chunk-R4MXLJUS.cjs.map → chunk-ISYVNPRT.cjs.map} +1 -1
  22. package/dist/{chunk-YX7C5JD7.cjs → chunk-JAPP2F4M.cjs} +77 -77
  23. package/dist/{chunk-YX7C5JD7.cjs.map → chunk-JAPP2F4M.cjs.map} +1 -1
  24. package/dist/{chunk-GGDM5J4B.cjs → chunk-LL4QQSAD.cjs} +322 -331
  25. package/dist/chunk-LL4QQSAD.cjs.map +1 -0
  26. package/dist/{chunk-GJSLKATJ.js → chunk-LSPBPUQM.js} +2 -2
  27. package/dist/{chunk-KFQXO7QB.js → chunk-NA7XJRWB.js} +1 -1
  28. package/dist/chunk-NA7XJRWB.js.map +1 -0
  29. package/dist/{chunk-H66L2265.js → chunk-OATWTTCI.js} +6 -6
  30. package/dist/{chunk-LPC3C7MG.cjs → chunk-P43ZHPM6.cjs} +40 -40
  31. package/dist/{chunk-LPC3C7MG.cjs.map → chunk-P43ZHPM6.cjs.map} +1 -1
  32. package/dist/{chunk-NO2KT42M.js → chunk-PNJ5LMVK.js} +10 -9
  33. package/dist/{chunk-NO2KT42M.js.map → chunk-PNJ5LMVK.js.map} +1 -1
  34. package/dist/{chunk-NSF7JUXF.js → chunk-PQN5R5II.js} +7 -7
  35. package/dist/{chunk-CUN4CJUN.cjs → chunk-QAFRLO5N.cjs} +11 -10
  36. package/dist/chunk-QAFRLO5N.cjs.map +1 -0
  37. package/dist/{chunk-LC6RRLFA.cjs → chunk-SF4G7M6U.cjs} +15 -15
  38. package/dist/{chunk-LC6RRLFA.cjs.map → chunk-SF4G7M6U.cjs.map} +1 -1
  39. package/dist/{chunk-CVYSW33D.js → chunk-SOK32D6C.js} +189 -198
  40. package/dist/chunk-SOK32D6C.js.map +1 -0
  41. package/dist/{chunk-4UZH3MT2.js → chunk-TFDNJTBX.js} +4 -4
  42. package/dist/{chunk-5M5W6XDY.cjs → chunk-VANFD4FX.cjs} +7 -7
  43. package/dist/{chunk-5M5W6XDY.cjs.map → chunk-VANFD4FX.cjs.map} +1 -1
  44. package/dist/{chunk-PRKMOF2U.cjs → chunk-VIB4SGCD.cjs} +14 -14
  45. package/dist/{chunk-PRKMOF2U.cjs.map → chunk-VIB4SGCD.cjs.map} +1 -1
  46. package/dist/{chunk-SY3QS2E5.cjs → chunk-VZGU4BV6.cjs} +29 -29
  47. package/dist/{chunk-SY3QS2E5.cjs.map → chunk-VZGU4BV6.cjs.map} +1 -1
  48. package/dist/{chunk-7XVFSGQA.js → chunk-XXG2Z2JT.js} +3 -3
  49. package/dist/{chunk-HB63TQQO.js → chunk-ZVUR3A33.js} +2 -2
  50. package/dist/components/announcement-bar.d.ts.map +1 -1
  51. package/dist/components/case-studies/index.cjs +10 -10
  52. package/dist/components/case-studies/index.js +4 -4
  53. package/dist/components/chat/index.cjs +4 -4
  54. package/dist/components/chat/index.js +3 -3
  55. package/dist/components/contact/index.cjs +5 -5
  56. package/dist/components/contact/index.js +4 -4
  57. package/dist/components/docs/index.cjs +7 -7
  58. package/dist/components/docs/index.js +6 -6
  59. package/dist/components/embeds/index.cjs +5 -5
  60. package/dist/components/embeds/index.js +4 -4
  61. package/dist/components/faq/index.cjs +6 -6
  62. package/dist/components/faq/index.js +5 -5
  63. package/dist/components/features/index.cjs +4 -4
  64. package/dist/components/features/index.js +3 -3
  65. package/dist/components/help-center-pages/index.cjs +23 -23
  66. package/dist/components/help-center-pages/index.js +14 -14
  67. package/dist/components/index.cjs +179 -185
  68. package/dist/components/index.cjs.map +1 -1
  69. package/dist/components/index.js +32 -38
  70. package/dist/components/index.js.map +1 -1
  71. package/dist/components/navigation/index.cjs +4 -4
  72. package/dist/components/navigation/index.js +3 -3
  73. package/dist/components/onboarding-guides/index.cjs +8 -8
  74. package/dist/components/onboarding-guides/index.js +7 -7
  75. package/dist/components/related-content/index.cjs +6 -6
  76. package/dist/components/related-content/index.js +5 -5
  77. package/dist/components/tickets/index.cjs +7 -7
  78. package/dist/components/tickets/index.js +6 -6
  79. package/dist/components/ui/index.cjs +4 -4
  80. package/dist/components/ui/index.js +3 -3
  81. package/dist/contexts/endpoints-runtime-context.d.ts +1 -1
  82. package/dist/contexts/endpoints-runtime-context.d.ts.map +1 -1
  83. package/dist/contexts/index.cjs +2 -2
  84. package/dist/contexts/index.js +1 -1
  85. package/dist/hooks/index.cjs +3 -3
  86. package/dist/hooks/index.js +2 -2
  87. package/dist/hooks/use-self-fetch.d.ts.map +1 -1
  88. package/dist/index.cjs +4 -4
  89. package/dist/index.cjs.map +1 -1
  90. package/dist/index.js +5 -5
  91. package/dist/types/announcement.cjs.map +1 -1
  92. package/dist/types/announcement.d.ts +6 -0
  93. package/dist/types/announcement.d.ts.map +1 -1
  94. package/dist/types/announcement.js.map +1 -1
  95. package/dist/types/index.cjs.map +1 -1
  96. package/dist/types/index.js.map +1 -1
  97. package/dist/utils/announcement-storage.d.ts +0 -3
  98. package/dist/utils/announcement-storage.d.ts.map +1 -1
  99. package/dist/utils/app-config.d.ts.map +1 -1
  100. package/dist/utils/color-analysis.d.ts +4 -0
  101. package/dist/utils/color-analysis.d.ts.map +1 -1
  102. package/dist/utils/index.cjs +177 -186
  103. package/dist/utils/index.cjs.map +1 -1
  104. package/dist/utils/index.js +176 -185
  105. package/dist/utils/index.js.map +1 -1
  106. package/dist/utils/ods-color-utils.d.ts +1 -2
  107. package/dist/utils/ods-color-utils.d.ts.map +1 -1
  108. package/package.json +1 -1
  109. package/src/components/announcement-bar.tsx +21 -38
  110. package/src/contexts/endpoints-runtime-context.tsx +1 -1
  111. package/src/hooks/use-self-fetch.ts +9 -10
  112. package/src/stories/AnnouncementBar.stories.tsx +14 -8
  113. package/src/types/announcement.ts +8 -0
  114. package/src/utils/announcement-storage.ts +0 -17
  115. package/src/utils/app-config.ts +2 -3
  116. package/src/utils/color-analysis.ts +2 -5
  117. package/src/utils/ods-color-utils.ts +7 -4
  118. package/dist/chunk-2B6773QM.cjs.map +0 -1
  119. package/dist/chunk-7Q52HP45.js.map +0 -1
  120. package/dist/chunk-CUN4CJUN.cjs.map +0 -1
  121. package/dist/chunk-CVYSW33D.js.map +0 -1
  122. package/dist/chunk-GGDM5J4B.cjs.map +0 -1
  123. package/dist/chunk-KFQXO7QB.js.map +0 -1
  124. package/dist/chunk-STGWQFYT.cjs.map +0 -1
  125. /package/dist/{chunk-HJIRG7R6.js.map → chunk-3KZXOLFK.js.map} +0 -0
  126. /package/dist/{chunk-43H2WOAW.js.map → chunk-6WMVBCNA.js.map} +0 -0
  127. /package/dist/{chunk-XFP43YKG.js.map → chunk-7RVSGGO6.js.map} +0 -0
  128. /package/dist/{chunk-KLBEIJVZ.js.map → chunk-AYFWYOL6.js.map} +0 -0
  129. /package/dist/{chunk-GMZL4T7C.js.map → chunk-C3NPMZBI.js.map} +0 -0
  130. /package/dist/{chunk-GJSLKATJ.js.map → chunk-LSPBPUQM.js.map} +0 -0
  131. /package/dist/{chunk-H66L2265.js.map → chunk-OATWTTCI.js.map} +0 -0
  132. /package/dist/{chunk-NSF7JUXF.js.map → chunk-PQN5R5II.js.map} +0 -0
  133. /package/dist/{chunk-4UZH3MT2.js.map → chunk-TFDNJTBX.js.map} +0 -0
  134. /package/dist/{chunk-7XVFSGQA.js.map → chunk-XXG2Z2JT.js.map} +0 -0
  135. /package/dist/{chunk-HB63TQQO.js.map → chunk-ZVUR3A33.js.map} +0 -0
@@ -468,174 +468,6 @@ 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
-
639
471
  // src/utils/ods-color-utils.ts
640
472
  function getPlatformAccentColor(platform) {
641
473
  const currentPlatform = platform || getCurrentPlatform();
@@ -660,13 +492,18 @@ function getCurrentPlatform() {
660
492
  return process.env.NEXT_PUBLIC_APP_TYPE || "openmsp";
661
493
  }
662
494
  function getReadableTextColor(hex) {
663
- return pickReadableTextColor(hex) === "dark" ? "#212121" : "#fafafa";
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";
664
501
  }
665
502
  var HEX_PATTERN = /^#[0-9a-fA-F]{6}$/;
666
503
  function clamp(n, min, max) {
667
504
  return Math.max(min, Math.min(max, n));
668
505
  }
669
- function hexToRgb2(hex) {
506
+ function hexToRgb(hex) {
670
507
  if (!HEX_PATTERN.test(hex)) return null;
671
508
  const n = Number.parseInt(hex.slice(1), 16);
672
509
  return { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
@@ -678,7 +515,7 @@ function rgbToHex(r, g, b) {
678
515
  var HOVER_DARKEN_STEP = 10;
679
516
  var ACTIVE_DARKEN_STEP = 20;
680
517
  function darkenByStep(hex, step) {
681
- const rgb = hexToRgb2(hex);
518
+ const rgb = hexToRgb(hex);
682
519
  if (!rgb) return hex;
683
520
  return rgbToHex(rgb.r - step, rgb.g - step, rgb.b - step);
684
521
  }
@@ -2481,6 +2318,173 @@ function isGenericWebsiteDomain(website) {
2481
2318
  return isGenericDomain(normalizeDomain(website));
2482
2319
  }
2483
2320
 
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
+
2484
2488
  // src/utils/announcement-storage.ts
2485
2489
  function announcementDismissCookieName(platform) {
2486
2490
  return `${platform}-announcement-dismissed`;
@@ -2509,19 +2513,6 @@ function isAnnouncementDismissed(platform, id) {
2509
2513
  return false;
2510
2514
  }
2511
2515
  }
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
- }
2525
2516
  function clearLegacyAnnouncementCache(platform) {
2526
2517
  if (typeof window === "undefined") return;
2527
2518
  try {
@@ -4100,7 +4091,6 @@ exports.buildOgPlaceholderUrl = buildOgPlaceholderUrl;
4100
4091
  exports.buildSuggestionUrl = buildSuggestionUrl;
4101
4092
  exports.canonicalContentRefType = canonicalContentRefType;
4102
4093
  exports.cleanEmailDomain = cleanEmailDomain;
4103
- exports.clearAnnouncementDismissals = clearAnnouncementDismissals;
4104
4094
  exports.clearEmbedProxyAuth = clearEmbedProxyAuth;
4105
4095
  exports.clearLegacyAnnouncementCache = clearLegacyAnnouncementCache;
4106
4096
  exports.clickupTaskUrl = clickupTaskUrl;
@@ -4195,6 +4185,7 @@ exports.getEmbedProxyAuth = getEmbedProxyAuth;
4195
4185
  exports.getFirstLastInitials = getFirstLastInitials;
4196
4186
  exports.getIconComponent = getIconComponent;
4197
4187
  exports.getInitialExpandedNodeIds = getInitialExpandedNodeIds;
4188
+ exports.getLuminance = getLuminance;
4198
4189
  exports.getOSIcon = getOSIcon;
4199
4190
  exports.getOSLabel = getOSLabel;
4200
4191
  exports.getOSPlatformId = getOSPlatformId;
@@ -4223,7 +4214,7 @@ exports.getToolLabel = getToolLabel;
4223
4214
  exports.getToolTypeAliases = getToolTypeAliases;
4224
4215
  exports.getTrendColors = getTrendColors;
4225
4216
  exports.hasGenericEmailDomain = hasGenericEmailDomain;
4226
- exports.hexToRgb = hexToRgb2;
4217
+ exports.hexToRgb = hexToRgb;
4227
4218
  exports.isAnnouncementDismissed = isAnnouncementDismissed;
4228
4219
  exports.isCrossOriginUrl = isCrossOriginUrl;
4229
4220
  exports.isDismissedCookieValue = isDismissedCookieValue;