@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
@@ -462,174 +462,6 @@ function formatBioText(aboutHtml, fallback = "") {
462
462
  }
463
463
  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";
464
464
 
465
- // src/utils/color-analysis.ts
466
- var DESIGN_PALETTE = [
467
- { name: "yellow", hex: "#FFC008", rgb: [255, 192, 8] },
468
- { name: "black", hex: "#161616", rgb: [22, 22, 22] },
469
- { name: "gray", hex: "#888888", rgb: [136, 136, 136] }
470
- ];
471
- function hexToRgb(hex) {
472
- const normalized = hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, (_, r, g, b) => `${r}${r}${g}${g}${b}${b}`);
473
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(normalized);
474
- return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : [0, 0, 0];
475
- }
476
- function getLuminance(rgb) {
477
- const [r, g, b] = rgb.map((c) => {
478
- c = c / 255;
479
- return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
480
- });
481
- return 0.2126 * r + 0.7152 * g + 0.0722 * b;
482
- }
483
- function getContrastRatio(color1, color2) {
484
- const lum1 = getLuminance(color1);
485
- const lum2 = getLuminance(color2);
486
- const brightest = Math.max(lum1, lum2);
487
- const darkest = Math.min(lum1, lum2);
488
- return (brightest + 0.05) / (darkest + 0.05);
489
- }
490
- function pickReadableTextColor(bgHex) {
491
- const bg = hexToRgb(bgHex);
492
- const darkContrast = getContrastRatio(bg, [26, 26, 26]);
493
- const lightContrast = getContrastRatio(bg, [250, 250, 250]);
494
- return darkContrast >= lightContrast ? "dark" : "light";
495
- }
496
- function extractDominantColor(canvas) {
497
- const ctx = canvas.getContext("2d");
498
- if (!ctx) return [128, 128, 128];
499
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
500
- const data = imageData.data;
501
- const sampleSize = Math.max(1, Math.floor(data.length / (4 * 1e3)));
502
- const colorCounts = {};
503
- for (let i = 0; i < data.length; i += 4 * sampleSize) {
504
- const r = data[i];
505
- const g = data[i + 1];
506
- const b = data[i + 2];
507
- const alpha = data[i + 3];
508
- if (alpha < 128) continue;
509
- const bucketR = Math.round(r / 32) * 32;
510
- const bucketG = Math.round(g / 32) * 32;
511
- const bucketB = Math.round(b / 32) * 32;
512
- const key = `${bucketR},${bucketG},${bucketB}`;
513
- colorCounts[key] = (colorCounts[key] || 0) + 1;
514
- }
515
- let maxCount = 0;
516
- let dominantColor = [128, 128, 128];
517
- for (const [colorKey, count] of Object.entries(colorCounts)) {
518
- if (count > maxCount) {
519
- maxCount = count;
520
- const [r, g, b] = colorKey.split(",").map(Number);
521
- dominantColor = [r, g, b];
522
- }
523
- }
524
- return dominantColor;
525
- }
526
- function getBestContrastColor(imageColor) {
527
- let bestColor = DESIGN_PALETTE[0];
528
- let bestContrast = 0;
529
- for (const color of DESIGN_PALETTE) {
530
- const contrast = getContrastRatio(imageColor, color.rgb);
531
- if (contrast > bestContrast) {
532
- bestContrast = contrast;
533
- bestColor = color;
534
- }
535
- }
536
- return bestContrast >= 3 ? bestColor : DESIGN_PALETTE.find((c) => c.name === "black") || bestColor;
537
- }
538
- function analyzeImageColor(imageSrc) {
539
- return new Promise((resolve, reject) => {
540
- const img = new Image();
541
- img.crossOrigin = "anonymous";
542
- img.onload = () => {
543
- try {
544
- const canvas = document.createElement("canvas");
545
- const ctx = canvas.getContext("2d");
546
- if (!ctx) {
547
- reject(new Error("Could not get canvas context"));
548
- return;
549
- }
550
- const maxSize = 100;
551
- const scale = Math.min(maxSize / img.width, maxSize / img.height);
552
- canvas.width = img.width * scale;
553
- canvas.height = img.height * scale;
554
- ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
555
- const dominantColor = extractDominantColor(canvas);
556
- const bestContrastColor = getBestContrastColor(dominantColor);
557
- resolve(bestContrastColor);
558
- } catch (error) {
559
- reject(error);
560
- }
561
- };
562
- img.onerror = () => reject(new Error("Failed to load image"));
563
- img.src = imageSrc;
564
- });
565
- }
566
- async function extractImageEdgeColorAsync(imageUrl) {
567
- return new Promise((resolve) => {
568
- if (typeof window === "undefined") {
569
- resolve("#000000");
570
- return;
571
- }
572
- const img = new Image();
573
- img.crossOrigin = "anonymous";
574
- img.onload = () => {
575
- try {
576
- const canvas = document.createElement("canvas");
577
- const ctx = canvas.getContext("2d");
578
- if (!ctx) {
579
- resolve("#000000");
580
- return;
581
- }
582
- const maxSize = 50;
583
- const scale = Math.min(maxSize / img.naturalWidth, maxSize / img.naturalHeight);
584
- const w = Math.round(img.naturalWidth * scale);
585
- const h = Math.round(img.naturalHeight * scale);
586
- canvas.width = w;
587
- canvas.height = h;
588
- ctx.drawImage(img, 0, 0, w, h);
589
- const data = ctx.getImageData(0, 0, w, h).data;
590
- const edgeW = Math.max(2, Math.round(w * 0.15));
591
- const edgeH = Math.max(2, Math.round(h * 0.15));
592
- const bucketSize = 32;
593
- const buckets = /* @__PURE__ */ new Map();
594
- for (let y = 0; y < h; y++) {
595
- for (let x = 0; x < w; x++) {
596
- if (!(x < edgeW || x >= w - edgeW || y < edgeH || y >= h - edgeH)) continue;
597
- const i = (y * w + x) * 4;
598
- if (data[i + 3] < 128) continue;
599
- const br = Math.floor(data[i] / bucketSize) * bucketSize;
600
- const bg = Math.floor(data[i + 1] / bucketSize) * bucketSize;
601
- const bb = Math.floor(data[i + 2] / bucketSize) * bucketSize;
602
- const key = `${br},${bg},${bb}`;
603
- const existing = buckets.get(key);
604
- if (existing) {
605
- existing.r += data[i];
606
- existing.g += data[i + 1];
607
- existing.b += data[i + 2];
608
- existing.count++;
609
- } else {
610
- buckets.set(key, { r: data[i], g: data[i + 1], b: data[i + 2], count: 1 });
611
- }
612
- }
613
- }
614
- let best = { r: 0, g: 0, b: 0, count: 0 };
615
- for (const b2 of buckets.values()) {
616
- if (b2.count > best.count) best = b2;
617
- }
618
- if (best.count === 0) {
619
- resolve("#000000");
620
- return;
621
- }
622
- const r = Math.round(best.r / best.count), g = Math.round(best.g / best.count), b = Math.round(best.b / best.count);
623
- resolve(`#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`);
624
- } catch {
625
- resolve("#000000");
626
- }
627
- };
628
- img.onerror = () => resolve("#000000");
629
- img.src = imageUrl;
630
- });
631
- }
632
-
633
465
  // src/utils/ods-color-utils.ts
634
466
  function getPlatformAccentColor(platform) {
635
467
  const currentPlatform = platform || getCurrentPlatform();
@@ -654,13 +486,18 @@ function getCurrentPlatform() {
654
486
  return process.env.NEXT_PUBLIC_APP_TYPE || "openmsp";
655
487
  }
656
488
  function getReadableTextColor(hex) {
657
- return pickReadableTextColor(hex) === "dark" ? "#212121" : "#fafafa";
489
+ const n = parseInt(hex.replace("#", ""), 16);
490
+ const r = n >> 16 & 255;
491
+ const g = n >> 8 & 255;
492
+ const b = n & 255;
493
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
494
+ return luminance > 0.5 ? "#212121" : "#fafafa";
658
495
  }
659
496
  var HEX_PATTERN = /^#[0-9a-fA-F]{6}$/;
660
497
  function clamp(n, min, max) {
661
498
  return Math.max(min, Math.min(max, n));
662
499
  }
663
- function hexToRgb2(hex) {
500
+ function hexToRgb(hex) {
664
501
  if (!HEX_PATTERN.test(hex)) return null;
665
502
  const n = Number.parseInt(hex.slice(1), 16);
666
503
  return { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
@@ -672,7 +509,7 @@ function rgbToHex(r, g, b) {
672
509
  var HOVER_DARKEN_STEP = 10;
673
510
  var ACTIVE_DARKEN_STEP = 20;
674
511
  function darkenByStep(hex, step) {
675
- const rgb = hexToRgb2(hex);
512
+ const rgb = hexToRgb(hex);
676
513
  if (!rgb) return hex;
677
514
  return rgbToHex(rgb.r - step, rgb.g - step, rgb.b - step);
678
515
  }
@@ -2475,6 +2312,173 @@ function isGenericWebsiteDomain(website) {
2475
2312
  return isGenericDomain(normalizeDomain(website));
2476
2313
  }
2477
2314
 
2315
+ // src/utils/color-analysis.ts
2316
+ var DESIGN_PALETTE = [
2317
+ { name: "yellow", hex: "#FFC008", rgb: [255, 192, 8] },
2318
+ { name: "black", hex: "#161616", rgb: [22, 22, 22] },
2319
+ { name: "gray", hex: "#888888", rgb: [136, 136, 136] }
2320
+ ];
2321
+ function hexToRgb2(hex) {
2322
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
2323
+ return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : [0, 0, 0];
2324
+ }
2325
+ function getLuminance(rgb) {
2326
+ const [r, g, b] = rgb.map((c) => {
2327
+ c = c / 255;
2328
+ return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
2329
+ });
2330
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
2331
+ }
2332
+ function getContrastRatio(color1, color2) {
2333
+ const lum1 = getLuminance(color1);
2334
+ const lum2 = getLuminance(color2);
2335
+ const brightest = Math.max(lum1, lum2);
2336
+ const darkest = Math.min(lum1, lum2);
2337
+ return (brightest + 0.05) / (darkest + 0.05);
2338
+ }
2339
+ function pickReadableTextColor(bgHex) {
2340
+ const bg = hexToRgb2(bgHex);
2341
+ const darkContrast = getContrastRatio(bg, [26, 26, 26]);
2342
+ const lightContrast = getContrastRatio(bg, [250, 250, 250]);
2343
+ return darkContrast >= lightContrast ? "dark" : "light";
2344
+ }
2345
+ function extractDominantColor(canvas) {
2346
+ const ctx = canvas.getContext("2d");
2347
+ if (!ctx) return [128, 128, 128];
2348
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
2349
+ const data = imageData.data;
2350
+ const sampleSize = Math.max(1, Math.floor(data.length / (4 * 1e3)));
2351
+ const colorCounts = {};
2352
+ for (let i = 0; i < data.length; i += 4 * sampleSize) {
2353
+ const r = data[i];
2354
+ const g = data[i + 1];
2355
+ const b = data[i + 2];
2356
+ const alpha = data[i + 3];
2357
+ if (alpha < 128) continue;
2358
+ const bucketR = Math.round(r / 32) * 32;
2359
+ const bucketG = Math.round(g / 32) * 32;
2360
+ const bucketB = Math.round(b / 32) * 32;
2361
+ const key = `${bucketR},${bucketG},${bucketB}`;
2362
+ colorCounts[key] = (colorCounts[key] || 0) + 1;
2363
+ }
2364
+ let maxCount = 0;
2365
+ let dominantColor = [128, 128, 128];
2366
+ for (const [colorKey, count] of Object.entries(colorCounts)) {
2367
+ if (count > maxCount) {
2368
+ maxCount = count;
2369
+ const [r, g, b] = colorKey.split(",").map(Number);
2370
+ dominantColor = [r, g, b];
2371
+ }
2372
+ }
2373
+ return dominantColor;
2374
+ }
2375
+ function getBestContrastColor(imageColor) {
2376
+ let bestColor = DESIGN_PALETTE[0];
2377
+ let bestContrast = 0;
2378
+ for (const color of DESIGN_PALETTE) {
2379
+ const contrast = getContrastRatio(imageColor, color.rgb);
2380
+ if (contrast > bestContrast) {
2381
+ bestContrast = contrast;
2382
+ bestColor = color;
2383
+ }
2384
+ }
2385
+ return bestContrast >= 3 ? bestColor : DESIGN_PALETTE.find((c) => c.name === "black") || bestColor;
2386
+ }
2387
+ function analyzeImageColor(imageSrc) {
2388
+ return new Promise((resolve, reject) => {
2389
+ const img = new Image();
2390
+ img.crossOrigin = "anonymous";
2391
+ img.onload = () => {
2392
+ try {
2393
+ const canvas = document.createElement("canvas");
2394
+ const ctx = canvas.getContext("2d");
2395
+ if (!ctx) {
2396
+ reject(new Error("Could not get canvas context"));
2397
+ return;
2398
+ }
2399
+ const maxSize = 100;
2400
+ const scale = Math.min(maxSize / img.width, maxSize / img.height);
2401
+ canvas.width = img.width * scale;
2402
+ canvas.height = img.height * scale;
2403
+ ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
2404
+ const dominantColor = extractDominantColor(canvas);
2405
+ const bestContrastColor = getBestContrastColor(dominantColor);
2406
+ resolve(bestContrastColor);
2407
+ } catch (error) {
2408
+ reject(error);
2409
+ }
2410
+ };
2411
+ img.onerror = () => reject(new Error("Failed to load image"));
2412
+ img.src = imageSrc;
2413
+ });
2414
+ }
2415
+ async function extractImageEdgeColorAsync(imageUrl) {
2416
+ return new Promise((resolve) => {
2417
+ if (typeof window === "undefined") {
2418
+ resolve("#000000");
2419
+ return;
2420
+ }
2421
+ const img = new Image();
2422
+ img.crossOrigin = "anonymous";
2423
+ img.onload = () => {
2424
+ try {
2425
+ const canvas = document.createElement("canvas");
2426
+ const ctx = canvas.getContext("2d");
2427
+ if (!ctx) {
2428
+ resolve("#000000");
2429
+ return;
2430
+ }
2431
+ const maxSize = 50;
2432
+ const scale = Math.min(maxSize / img.naturalWidth, maxSize / img.naturalHeight);
2433
+ const w = Math.round(img.naturalWidth * scale);
2434
+ const h = Math.round(img.naturalHeight * scale);
2435
+ canvas.width = w;
2436
+ canvas.height = h;
2437
+ ctx.drawImage(img, 0, 0, w, h);
2438
+ const data = ctx.getImageData(0, 0, w, h).data;
2439
+ const edgeW = Math.max(2, Math.round(w * 0.15));
2440
+ const edgeH = Math.max(2, Math.round(h * 0.15));
2441
+ const bucketSize = 32;
2442
+ const buckets = /* @__PURE__ */ new Map();
2443
+ for (let y = 0; y < h; y++) {
2444
+ for (let x = 0; x < w; x++) {
2445
+ if (!(x < edgeW || x >= w - edgeW || y < edgeH || y >= h - edgeH)) continue;
2446
+ const i = (y * w + x) * 4;
2447
+ if (data[i + 3] < 128) continue;
2448
+ const br = Math.floor(data[i] / bucketSize) * bucketSize;
2449
+ const bg = Math.floor(data[i + 1] / bucketSize) * bucketSize;
2450
+ const bb = Math.floor(data[i + 2] / bucketSize) * bucketSize;
2451
+ const key = `${br},${bg},${bb}`;
2452
+ const existing = buckets.get(key);
2453
+ if (existing) {
2454
+ existing.r += data[i];
2455
+ existing.g += data[i + 1];
2456
+ existing.b += data[i + 2];
2457
+ existing.count++;
2458
+ } else {
2459
+ buckets.set(key, { r: data[i], g: data[i + 1], b: data[i + 2], count: 1 });
2460
+ }
2461
+ }
2462
+ }
2463
+ let best = { r: 0, g: 0, b: 0, count: 0 };
2464
+ for (const b2 of buckets.values()) {
2465
+ if (b2.count > best.count) best = b2;
2466
+ }
2467
+ if (best.count === 0) {
2468
+ resolve("#000000");
2469
+ return;
2470
+ }
2471
+ const r = Math.round(best.r / best.count), g = Math.round(best.g / best.count), b = Math.round(best.b / best.count);
2472
+ resolve(`#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`);
2473
+ } catch {
2474
+ resolve("#000000");
2475
+ }
2476
+ };
2477
+ img.onerror = () => resolve("#000000");
2478
+ img.src = imageUrl;
2479
+ });
2480
+ }
2481
+
2478
2482
  // src/utils/announcement-storage.ts
2479
2483
  function announcementDismissCookieName(platform) {
2480
2484
  return `${platform}-announcement-dismissed`;
@@ -2503,19 +2507,6 @@ function isAnnouncementDismissed(platform, id) {
2503
2507
  return false;
2504
2508
  }
2505
2509
  }
2506
- function clearAnnouncementDismissals(platform) {
2507
- if (typeof document === "undefined") return;
2508
- document.cookie = `${announcementDismissCookieName(platform)}=; path=/; max-age=0`;
2509
- try {
2510
- const prefix = `${platform}-announcement-`;
2511
- Object.keys(localStorage).forEach((key) => {
2512
- if (key.startsWith(prefix) && key.endsWith("-dismissed")) {
2513
- localStorage.removeItem(key);
2514
- }
2515
- });
2516
- } catch {
2517
- }
2518
- }
2519
2510
  function clearLegacyAnnouncementCache(platform) {
2520
2511
  if (typeof window === "undefined") return;
2521
2512
  try {
@@ -4046,6 +4037,6 @@ function toFigmaOriginalUrl(url) {
4046
4037
  // src/utils/page-header-constants.ts
4047
4038
  var SECTION_HERO_ICON_CLASS = "h-10 w-10 text-ods-accent";
4048
4039
 
4049
- export { ANTHROPIC_SUPPORTED_IMAGE_MIME, AUTO_CONTINUATION_DIRECTIVE_PREFIX, BRAND_MARK_SVGS, CHAT_ATTACHMENT_MARKDOWN_PATTERN, CHAT_ATTACHMENT_VIEW_TOKEN_QUERY_PARAM, CHAT_ATTACHMENT_VIEW_URL_PREFIX, CHAT_ATTACHMENT_VIEW_URL_PREFIX_REGEX_ESCAPED, CONTENT_REF_GROUPS, CUSTOM_ITEM_ID, DEFAULT_CONTENT_SUFFIXES, DEFAULT_FOLDER_INDEX_FILE, DEFAULT_MIN_FILL_MS, DEFAULT_OS_PLATFORM, DELIVERY_TASK_TYPE_OPTIONS, DESIGN_PALETTE, DEV_SECTION_PARAM_KEYS, ELAPSED_MS_FIELD, GENERIC_EMAIL_DOMAINS, HEX_PATTERN, HONEYPOT_FIELD, HUB_HEADER_OFFSET_PX, ICON_REGISTRY, OPENFRAME_DEV_SECTIONS, OS_PLATFORMS, PLAY_ICON_PATH, ROADMAP_STATUS_OPTIONS, SCROLL_ANCHOR, SCROLL_ANCHOR_WIRE_KEY, SECTION_HERO_ICON_CLASS, SEO_TITLE_MAX_LENGTH, SOURCE_ICON_NAMES, SOURCE_LABELS_BY_TABLE, STICKY_HEADER_OFFSET_PX, TICKET_STATUS_OPTIONS, analyzeImageColor, announcementDismissCookieName, applyProxyAuth, brandMarkDataUri, buildAutoContinuationDirective, buildChatAttachmentViewUrl, buildDefaultHref, buildDiscussAddendum, buildDocumentTree, buildListUrl, buildOgPlaceholderUrl, buildSuggestionUrl, canonicalContentRefType, cleanEmailDomain, clearAnnouncementDismissals, clearEmbedProxyAuth, clearLegacyAnnouncementCache, clickupTaskUrl, cn, consumeAccessCode, createUTCTimestamp, deepClone, delay, deriveActiveColor, deriveHoverColor, devSectionAnchorId, dismissAnnouncement, embedAuthedFetch, escapeMarkdownInline, evaluateHumanitySignals, extractDomainFromEmail, extractDominantColor, extractEntityIdFilter, extractHumanitySignals, extractImageEdgeColorAsync, extractItemId, extractItems, extractSections, faqItemAnchor, faqSectionSlug, fetchPriorityProp, findDocNodeByPath, flattenAssistantContent, formatAbbreviatedNumber, formatAbsoluteDate, formatBioText, formatBytes, formatBytesShort, formatChatAttachmentMarkdownForBubble, formatClassification, formatCompactMetric, formatCurrency, formatDate, formatDateRange, formatDateShort, formatDateSlashUTC, formatDateTime, formatDateTimeAt, formatDateUTC, formatDocName, formatDuration, formatDurationCompact, formatDurationFromMs, formatDurationFromRange, formatDurationMMSS, formatEntryMonthUTC, formatFileSize, formatLargeNumber, formatLegalDate, formatNumber, formatPercent, formatPhoneE164, formatPrice, formatPricingModel, formatRelativeTime, formatReleaseDate, formatSingularLookupInvocation, formatTicketFullTimestamp, formatTicketRelativeTime, formatTimeWithTimezone, formatUnderscoreText, formatWholeDollars, generateImageSizes, generateRandomString, getAllPlatformBaseDomains, getBaseUrl, getBestContrastColor, getConfidenceBgClass, getConfidenceBorderClass, getConfidenceColorClass, getConfidenceLabel, getConfidenceLevel, getConfidenceTextClass, getContentRefLabel, getContentRefLabelOrTitleCase, getContrastRatio, getCountryByCode, getCountryPhoneData, getCurrentPlatform, getDefaultColorForPlatform, getDefaultIconForPlatform, getDetailedTimeDifference, getDocAncestorNodeIds, getDocSourceDefaultPath, getDynamicIcon, getEmbedProxyAuth, getFirstLastInitials, getIconComponent, getInitialExpandedNodeIds, getOSIcon, getOSLabel, getOSPlatformId, getOSTypeDefinition, getPersistedProxyEmail, getPlatformAccentColor, getPlatformColor, getPlatformDescription, getPlatformDisplayName, getPlatformIcon, getPlatformIconComponent, getPlatformIconComponent as getPlatformLogo, getPlatformProductionUrl, getPlatformSlogan, getProxiedImageUrl, getReadableTextColor, getShellIcon, getShellLabel, getSlackCommunityJoinUrl, getSmallPlatformIcon, getSourceIconName, getSourceLabel, getStatusColorScheme, getTaskTypeLabel, getToolLabel, getToolTypeAliases, getTrendColors, hasGenericEmailDomain, hexToRgb2 as hexToRgb, isAnnouncementDismissed, isCrossOriginUrl, isDismissedCookieValue, isFigmaSlidesUrl, isGenericDomain, isGenericWebsiteDomain, isOSPlatform, isToday, isValidEmailDomain, isValidToolType, isWithinMinutes, makeComposeContentUrl, markdownToPlainText, nameInitials, navigateSamePageHash, normalizeDocPath, normalizeDomain, normalizeHashFragment, normalizeIconKey, normalizeOSType, normalizeToolType, normalizeToolTypeWithFallback, orderContentRefTypes, parseFaqHash, parseScrollAnchor, parseWireCommandOverride, pathToNodeId, pickReadableTextColor, platformColors, platformDescriptions, platformDisplayNames, platformHexColors, platformIconNames, platformIcons, platformSlogans, readLeadingDecisionFrame, releaseTypeToBadgeColor, resolveContentFetchPath, resolveReleaseCover, rgbToHex, sanitizeTitleForChat, scrollElementIntoView, serializeJsonLd, setEmbedAuthAdapter, setEmbedProxyAuth, shouldProxyImage, sortTreeChildren, splitCsvEnv, stripChatAttachmentMarkdown, stripFolderIndexFromPath, stripHtml, stripInlineMarkdown, toDocSlug, toFigmaEmbedUrl, toFigmaOriginalUrl, toGoogleSheetsEmbedUrl, toGoogleSheetsOriginalUrl, toToolLabel, transformPlatformConfigsToOptions, truncateString, urlPathLooksLikeSvg, validateAccessCode, validateAndConsumeAccessCode, validateEmailDomain, validateEmailDomainList, validatePhoneNumber };
4040
+ export { ANTHROPIC_SUPPORTED_IMAGE_MIME, AUTO_CONTINUATION_DIRECTIVE_PREFIX, BRAND_MARK_SVGS, CHAT_ATTACHMENT_MARKDOWN_PATTERN, CHAT_ATTACHMENT_VIEW_TOKEN_QUERY_PARAM, CHAT_ATTACHMENT_VIEW_URL_PREFIX, CHAT_ATTACHMENT_VIEW_URL_PREFIX_REGEX_ESCAPED, CONTENT_REF_GROUPS, CUSTOM_ITEM_ID, DEFAULT_CONTENT_SUFFIXES, DEFAULT_FOLDER_INDEX_FILE, DEFAULT_MIN_FILL_MS, DEFAULT_OS_PLATFORM, DELIVERY_TASK_TYPE_OPTIONS, DESIGN_PALETTE, DEV_SECTION_PARAM_KEYS, ELAPSED_MS_FIELD, GENERIC_EMAIL_DOMAINS, HEX_PATTERN, HONEYPOT_FIELD, HUB_HEADER_OFFSET_PX, ICON_REGISTRY, OPENFRAME_DEV_SECTIONS, OS_PLATFORMS, PLAY_ICON_PATH, ROADMAP_STATUS_OPTIONS, SCROLL_ANCHOR, SCROLL_ANCHOR_WIRE_KEY, SECTION_HERO_ICON_CLASS, SEO_TITLE_MAX_LENGTH, SOURCE_ICON_NAMES, SOURCE_LABELS_BY_TABLE, STICKY_HEADER_OFFSET_PX, TICKET_STATUS_OPTIONS, analyzeImageColor, announcementDismissCookieName, applyProxyAuth, brandMarkDataUri, buildAutoContinuationDirective, buildChatAttachmentViewUrl, buildDefaultHref, buildDiscussAddendum, buildDocumentTree, buildListUrl, buildOgPlaceholderUrl, buildSuggestionUrl, canonicalContentRefType, cleanEmailDomain, clearEmbedProxyAuth, clearLegacyAnnouncementCache, clickupTaskUrl, cn, consumeAccessCode, createUTCTimestamp, deepClone, delay, deriveActiveColor, deriveHoverColor, devSectionAnchorId, dismissAnnouncement, embedAuthedFetch, escapeMarkdownInline, evaluateHumanitySignals, extractDomainFromEmail, extractDominantColor, extractEntityIdFilter, extractHumanitySignals, extractImageEdgeColorAsync, extractItemId, extractItems, extractSections, faqItemAnchor, faqSectionSlug, fetchPriorityProp, findDocNodeByPath, flattenAssistantContent, formatAbbreviatedNumber, formatAbsoluteDate, formatBioText, formatBytes, formatBytesShort, formatChatAttachmentMarkdownForBubble, formatClassification, formatCompactMetric, formatCurrency, formatDate, formatDateRange, formatDateShort, formatDateSlashUTC, formatDateTime, formatDateTimeAt, formatDateUTC, formatDocName, formatDuration, formatDurationCompact, formatDurationFromMs, formatDurationFromRange, formatDurationMMSS, formatEntryMonthUTC, formatFileSize, formatLargeNumber, formatLegalDate, formatNumber, formatPercent, formatPhoneE164, formatPrice, formatPricingModel, formatRelativeTime, formatReleaseDate, formatSingularLookupInvocation, formatTicketFullTimestamp, formatTicketRelativeTime, formatTimeWithTimezone, formatUnderscoreText, formatWholeDollars, generateImageSizes, generateRandomString, getAllPlatformBaseDomains, getBaseUrl, getBestContrastColor, getConfidenceBgClass, getConfidenceBorderClass, getConfidenceColorClass, getConfidenceLabel, getConfidenceLevel, getConfidenceTextClass, getContentRefLabel, getContentRefLabelOrTitleCase, getContrastRatio, getCountryByCode, getCountryPhoneData, getCurrentPlatform, getDefaultColorForPlatform, getDefaultIconForPlatform, getDetailedTimeDifference, getDocAncestorNodeIds, getDocSourceDefaultPath, getDynamicIcon, getEmbedProxyAuth, getFirstLastInitials, getIconComponent, getInitialExpandedNodeIds, getLuminance, getOSIcon, getOSLabel, getOSPlatformId, getOSTypeDefinition, getPersistedProxyEmail, getPlatformAccentColor, getPlatformColor, getPlatformDescription, getPlatformDisplayName, getPlatformIcon, getPlatformIconComponent, getPlatformIconComponent as getPlatformLogo, getPlatformProductionUrl, getPlatformSlogan, getProxiedImageUrl, getReadableTextColor, getShellIcon, getShellLabel, getSlackCommunityJoinUrl, getSmallPlatformIcon, getSourceIconName, getSourceLabel, getStatusColorScheme, getTaskTypeLabel, getToolLabel, getToolTypeAliases, getTrendColors, hasGenericEmailDomain, hexToRgb, isAnnouncementDismissed, isCrossOriginUrl, isDismissedCookieValue, isFigmaSlidesUrl, isGenericDomain, isGenericWebsiteDomain, isOSPlatform, isToday, isValidEmailDomain, isValidToolType, isWithinMinutes, makeComposeContentUrl, markdownToPlainText, nameInitials, navigateSamePageHash, normalizeDocPath, normalizeDomain, normalizeHashFragment, normalizeIconKey, normalizeOSType, normalizeToolType, normalizeToolTypeWithFallback, orderContentRefTypes, parseFaqHash, parseScrollAnchor, parseWireCommandOverride, pathToNodeId, pickReadableTextColor, platformColors, platformDescriptions, platformDisplayNames, platformHexColors, platformIconNames, platformIcons, platformSlogans, readLeadingDecisionFrame, releaseTypeToBadgeColor, resolveContentFetchPath, resolveReleaseCover, rgbToHex, sanitizeTitleForChat, scrollElementIntoView, serializeJsonLd, setEmbedAuthAdapter, setEmbedProxyAuth, shouldProxyImage, sortTreeChildren, splitCsvEnv, stripChatAttachmentMarkdown, stripFolderIndexFromPath, stripHtml, stripInlineMarkdown, toDocSlug, toFigmaEmbedUrl, toFigmaOriginalUrl, toGoogleSheetsEmbedUrl, toGoogleSheetsOriginalUrl, toToolLabel, transformPlatformConfigsToOptions, truncateString, urlPathLooksLikeSvg, validateAccessCode, validateAndConsumeAccessCode, validateEmailDomain, validateEmailDomainList, validatePhoneNumber };
4050
4041
  //# sourceMappingURL=index.js.map
4051
4042
  //# sourceMappingURL=index.js.map