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

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 (136) 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-RIGB7LP7.js → chunk-43H2WOAW.js} +3 -3
  4. package/dist/{chunk-QYTGHN2T.js → chunk-4UZH3MT2.js} +4 -4
  5. package/dist/{chunk-LREN3G7R.cjs → chunk-5M5W6XDY.cjs} +7 -7
  6. package/dist/{chunk-LREN3G7R.cjs.map → chunk-5M5W6XDY.cjs.map} +1 -1
  7. package/dist/{chunk-WEZIVLCO.cjs → chunk-74FWQI73.cjs} +18 -18
  8. package/dist/{chunk-WEZIVLCO.cjs.map → chunk-74FWQI73.cjs.map} +1 -1
  9. package/dist/{chunk-E6YHDT3D.js → chunk-7Q52HP45.js} +2 -2
  10. package/dist/chunk-7Q52HP45.js.map +1 -0
  11. package/dist/{chunk-3XCNFTFV.js → chunk-7XVFSGQA.js} +3 -3
  12. package/dist/{chunk-QAFRLO5N.cjs → chunk-CUN4CJUN.cjs} +10 -11
  13. package/dist/chunk-CUN4CJUN.cjs.map +1 -0
  14. package/dist/{chunk-ICJRSNBM.js → chunk-CVYSW33D.js} +199 -189
  15. package/dist/chunk-CVYSW33D.js.map +1 -0
  16. package/dist/{chunk-FOJRR647.cjs → chunk-DOBNDDNE.cjs} +75 -75
  17. package/dist/{chunk-FOJRR647.cjs.map → chunk-DOBNDDNE.cjs.map} +1 -1
  18. package/dist/{chunk-FFYEDIAG.cjs → chunk-GGDM5J4B.cjs} +332 -322
  19. package/dist/chunk-GGDM5J4B.cjs.map +1 -0
  20. package/dist/{chunk-UN2BJ7XW.js → chunk-GJSLKATJ.js} +2 -2
  21. package/dist/{chunk-GT7AJXKH.js → chunk-GMZL4T7C.js} +3 -3
  22. package/dist/{chunk-BK7QCB5J.js → chunk-H66L2265.js} +6 -6
  23. package/dist/{chunk-F3YLM5PO.js → chunk-HB63TQQO.js} +2 -2
  24. package/dist/{chunk-5XZEY34X.js → chunk-HJIRG7R6.js} +4 -4
  25. package/dist/{chunk-NA7XJRWB.js → chunk-KFQXO7QB.js} +1 -1
  26. package/dist/chunk-KFQXO7QB.js.map +1 -0
  27. package/dist/{chunk-Q2KKEE6W.js → chunk-KLBEIJVZ.js} +7 -7
  28. package/dist/{chunk-M6BGJVDY.cjs → chunk-LC6RRLFA.cjs} +15 -15
  29. package/dist/{chunk-M6BGJVDY.cjs.map → chunk-LC6RRLFA.cjs.map} +1 -1
  30. package/dist/{chunk-VFWEFR3Q.cjs → chunk-LPC3C7MG.cjs} +40 -40
  31. package/dist/{chunk-VFWEFR3Q.cjs.map → chunk-LPC3C7MG.cjs.map} +1 -1
  32. package/dist/{chunk-PNJ5LMVK.js → chunk-NO2KT42M.js} +9 -10
  33. package/dist/{chunk-PNJ5LMVK.js.map → chunk-NO2KT42M.js.map} +1 -1
  34. package/dist/{chunk-RC35ITSR.js → chunk-NSF7JUXF.js} +7 -7
  35. package/dist/{chunk-V4MOB3AD.cjs → chunk-PRKMOF2U.cjs} +14 -14
  36. package/dist/{chunk-V4MOB3AD.cjs.map → chunk-PRKMOF2U.cjs.map} +1 -1
  37. package/dist/{chunk-DHIYBC5Z.cjs → chunk-Q2MC3CBI.cjs} +35 -35
  38. package/dist/{chunk-DHIYBC5Z.cjs.map → chunk-Q2MC3CBI.cjs.map} +1 -1
  39. package/dist/{chunk-BS6O4HLJ.cjs → chunk-R4MXLJUS.cjs} +42 -42
  40. package/dist/{chunk-BS6O4HLJ.cjs.map → chunk-R4MXLJUS.cjs.map} +1 -1
  41. package/dist/{chunk-CCIBZ7TO.cjs → chunk-STGWQFYT.cjs} +5 -5
  42. package/dist/chunk-STGWQFYT.cjs.map +1 -0
  43. package/dist/{chunk-6OQ7YOX5.cjs → chunk-SY3QS2E5.cjs} +29 -29
  44. package/dist/{chunk-6OQ7YOX5.cjs.map → chunk-SY3QS2E5.cjs.map} +1 -1
  45. package/dist/{chunk-ELLTTMPE.cjs → chunk-WCPUJA3Y.cjs} +7 -7
  46. package/dist/{chunk-ELLTTMPE.cjs.map → chunk-WCPUJA3Y.cjs.map} +1 -1
  47. package/dist/{chunk-UIAQXIA6.js → chunk-XFP43YKG.js} +6 -6
  48. package/dist/{chunk-ACJ4CM6H.cjs → chunk-YX7C5JD7.cjs} +77 -77
  49. package/dist/{chunk-ACJ4CM6H.cjs.map → chunk-YX7C5JD7.cjs.map} +1 -1
  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 +185 -179
  68. package/dist/components/index.cjs.map +1 -1
  69. package/dist/components/index.js +38 -32
  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 +0 -6
  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 +3 -0
  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 +0 -4
  101. package/dist/utils/color-analysis.d.ts.map +1 -1
  102. package/dist/utils/index.cjs +186 -177
  103. package/dist/utils/index.cjs.map +1 -1
  104. package/dist/utils/index.js +185 -176
  105. package/dist/utils/index.js.map +1 -1
  106. package/dist/utils/ods-color-utils.d.ts +2 -1
  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 +38 -21
  110. package/src/components/features/video.tsx +8 -0
  111. package/src/contexts/endpoints-runtime-context.tsx +1 -1
  112. package/src/hooks/use-self-fetch.ts +10 -9
  113. package/src/stories/AnnouncementBar.stories.tsx +8 -14
  114. package/src/types/announcement.ts +0 -8
  115. package/src/utils/announcement-storage.ts +17 -0
  116. package/src/utils/app-config.ts +3 -2
  117. package/src/utils/color-analysis.ts +5 -2
  118. package/src/utils/ods-color-utils.ts +4 -7
  119. package/dist/chunk-3KEBI6TP.cjs.map +0 -1
  120. package/dist/chunk-CCIBZ7TO.cjs.map +0 -1
  121. package/dist/chunk-E6YHDT3D.js.map +0 -1
  122. package/dist/chunk-FFYEDIAG.cjs.map +0 -1
  123. package/dist/chunk-ICJRSNBM.js.map +0 -1
  124. package/dist/chunk-NA7XJRWB.js.map +0 -1
  125. package/dist/chunk-QAFRLO5N.cjs.map +0 -1
  126. /package/dist/{chunk-RIGB7LP7.js.map → chunk-43H2WOAW.js.map} +0 -0
  127. /package/dist/{chunk-QYTGHN2T.js.map → chunk-4UZH3MT2.js.map} +0 -0
  128. /package/dist/{chunk-3XCNFTFV.js.map → chunk-7XVFSGQA.js.map} +0 -0
  129. /package/dist/{chunk-UN2BJ7XW.js.map → chunk-GJSLKATJ.js.map} +0 -0
  130. /package/dist/{chunk-GT7AJXKH.js.map → chunk-GMZL4T7C.js.map} +0 -0
  131. /package/dist/{chunk-BK7QCB5J.js.map → chunk-H66L2265.js.map} +0 -0
  132. /package/dist/{chunk-F3YLM5PO.js.map → chunk-HB63TQQO.js.map} +0 -0
  133. /package/dist/{chunk-5XZEY34X.js.map → chunk-HJIRG7R6.js.map} +0 -0
  134. /package/dist/{chunk-Q2KKEE6W.js.map → chunk-KLBEIJVZ.js.map} +0 -0
  135. /package/dist/{chunk-RC35ITSR.js.map → chunk-NSF7JUXF.js.map} +0 -0
  136. /package/dist/{chunk-UIAQXIA6.js.map → chunk-XFP43YKG.js.map} +0 -0
@@ -462,6 +462,174 @@ 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
+
465
633
  // src/utils/ods-color-utils.ts
466
634
  function getPlatformAccentColor(platform) {
467
635
  const currentPlatform = platform || getCurrentPlatform();
@@ -486,18 +654,13 @@ function getCurrentPlatform() {
486
654
  return process.env.NEXT_PUBLIC_APP_TYPE || "openmsp";
487
655
  }
488
656
  function getReadableTextColor(hex) {
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";
657
+ return pickReadableTextColor(hex) === "dark" ? "#212121" : "#fafafa";
495
658
  }
496
659
  var HEX_PATTERN = /^#[0-9a-fA-F]{6}$/;
497
660
  function clamp(n, min, max) {
498
661
  return Math.max(min, Math.min(max, n));
499
662
  }
500
- function hexToRgb(hex) {
663
+ function hexToRgb2(hex) {
501
664
  if (!HEX_PATTERN.test(hex)) return null;
502
665
  const n = Number.parseInt(hex.slice(1), 16);
503
666
  return { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
@@ -509,7 +672,7 @@ function rgbToHex(r, g, b) {
509
672
  var HOVER_DARKEN_STEP = 10;
510
673
  var ACTIVE_DARKEN_STEP = 20;
511
674
  function darkenByStep(hex, step) {
512
- const rgb = hexToRgb(hex);
675
+ const rgb = hexToRgb2(hex);
513
676
  if (!rgb) return hex;
514
677
  return rgbToHex(rgb.r - step, rgb.g - step, rgb.b - step);
515
678
  }
@@ -2312,173 +2475,6 @@ function isGenericWebsiteDomain(website) {
2312
2475
  return isGenericDomain(normalizeDomain(website));
2313
2476
  }
2314
2477
 
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
-
2482
2478
  // src/utils/announcement-storage.ts
2483
2479
  function announcementDismissCookieName(platform) {
2484
2480
  return `${platform}-announcement-dismissed`;
@@ -2507,6 +2503,19 @@ function isAnnouncementDismissed(platform, id) {
2507
2503
  return false;
2508
2504
  }
2509
2505
  }
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
+ }
2510
2519
  function clearLegacyAnnouncementCache(platform) {
2511
2520
  if (typeof window === "undefined") return;
2512
2521
  try {
@@ -4037,6 +4046,6 @@ function toFigmaOriginalUrl(url) {
4037
4046
  // src/utils/page-header-constants.ts
4038
4047
  var SECTION_HERO_ICON_CLASS = "h-10 w-10 text-ods-accent";
4039
4048
 
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 };
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 };
4041
4050
  //# sourceMappingURL=index.js.map
4042
4051
  //# sourceMappingURL=index.js.map