@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.
- package/dist/{chunk-3KEBI6TP.cjs → chunk-2B6773QM.cjs} +1 -1
- package/dist/chunk-2B6773QM.cjs.map +1 -0
- package/dist/{chunk-RIGB7LP7.js → chunk-43H2WOAW.js} +3 -3
- package/dist/{chunk-QYTGHN2T.js → chunk-4UZH3MT2.js} +4 -4
- package/dist/{chunk-LREN3G7R.cjs → chunk-5M5W6XDY.cjs} +7 -7
- package/dist/{chunk-LREN3G7R.cjs.map → chunk-5M5W6XDY.cjs.map} +1 -1
- package/dist/{chunk-WEZIVLCO.cjs → chunk-74FWQI73.cjs} +18 -18
- package/dist/{chunk-WEZIVLCO.cjs.map → chunk-74FWQI73.cjs.map} +1 -1
- package/dist/{chunk-E6YHDT3D.js → chunk-7Q52HP45.js} +2 -2
- package/dist/chunk-7Q52HP45.js.map +1 -0
- package/dist/{chunk-3XCNFTFV.js → chunk-7XVFSGQA.js} +3 -3
- package/dist/{chunk-QAFRLO5N.cjs → chunk-CUN4CJUN.cjs} +10 -11
- package/dist/chunk-CUN4CJUN.cjs.map +1 -0
- package/dist/{chunk-ICJRSNBM.js → chunk-CVYSW33D.js} +199 -189
- package/dist/chunk-CVYSW33D.js.map +1 -0
- package/dist/{chunk-FOJRR647.cjs → chunk-DOBNDDNE.cjs} +75 -75
- package/dist/{chunk-FOJRR647.cjs.map → chunk-DOBNDDNE.cjs.map} +1 -1
- package/dist/{chunk-FFYEDIAG.cjs → chunk-GGDM5J4B.cjs} +332 -322
- package/dist/chunk-GGDM5J4B.cjs.map +1 -0
- package/dist/{chunk-UN2BJ7XW.js → chunk-GJSLKATJ.js} +2 -2
- package/dist/{chunk-GT7AJXKH.js → chunk-GMZL4T7C.js} +3 -3
- package/dist/{chunk-BK7QCB5J.js → chunk-H66L2265.js} +6 -6
- package/dist/{chunk-F3YLM5PO.js → chunk-HB63TQQO.js} +2 -2
- package/dist/{chunk-5XZEY34X.js → chunk-HJIRG7R6.js} +4 -4
- package/dist/{chunk-NA7XJRWB.js → chunk-KFQXO7QB.js} +1 -1
- package/dist/chunk-KFQXO7QB.js.map +1 -0
- package/dist/{chunk-Q2KKEE6W.js → chunk-KLBEIJVZ.js} +7 -7
- package/dist/{chunk-M6BGJVDY.cjs → chunk-LC6RRLFA.cjs} +15 -15
- package/dist/{chunk-M6BGJVDY.cjs.map → chunk-LC6RRLFA.cjs.map} +1 -1
- package/dist/{chunk-VFWEFR3Q.cjs → chunk-LPC3C7MG.cjs} +40 -40
- package/dist/{chunk-VFWEFR3Q.cjs.map → chunk-LPC3C7MG.cjs.map} +1 -1
- package/dist/{chunk-PNJ5LMVK.js → chunk-NO2KT42M.js} +9 -10
- package/dist/{chunk-PNJ5LMVK.js.map → chunk-NO2KT42M.js.map} +1 -1
- package/dist/{chunk-RC35ITSR.js → chunk-NSF7JUXF.js} +7 -7
- package/dist/{chunk-V4MOB3AD.cjs → chunk-PRKMOF2U.cjs} +14 -14
- package/dist/{chunk-V4MOB3AD.cjs.map → chunk-PRKMOF2U.cjs.map} +1 -1
- package/dist/{chunk-DHIYBC5Z.cjs → chunk-Q2MC3CBI.cjs} +35 -35
- package/dist/{chunk-DHIYBC5Z.cjs.map → chunk-Q2MC3CBI.cjs.map} +1 -1
- package/dist/{chunk-BS6O4HLJ.cjs → chunk-R4MXLJUS.cjs} +42 -42
- package/dist/{chunk-BS6O4HLJ.cjs.map → chunk-R4MXLJUS.cjs.map} +1 -1
- package/dist/{chunk-CCIBZ7TO.cjs → chunk-STGWQFYT.cjs} +5 -5
- package/dist/chunk-STGWQFYT.cjs.map +1 -0
- package/dist/{chunk-6OQ7YOX5.cjs → chunk-SY3QS2E5.cjs} +29 -29
- package/dist/{chunk-6OQ7YOX5.cjs.map → chunk-SY3QS2E5.cjs.map} +1 -1
- package/dist/{chunk-ELLTTMPE.cjs → chunk-WCPUJA3Y.cjs} +7 -7
- package/dist/{chunk-ELLTTMPE.cjs.map → chunk-WCPUJA3Y.cjs.map} +1 -1
- package/dist/{chunk-UIAQXIA6.js → chunk-XFP43YKG.js} +6 -6
- package/dist/{chunk-ACJ4CM6H.cjs → chunk-YX7C5JD7.cjs} +77 -77
- package/dist/{chunk-ACJ4CM6H.cjs.map → chunk-YX7C5JD7.cjs.map} +1 -1
- package/dist/components/announcement-bar.d.ts.map +1 -1
- package/dist/components/case-studies/index.cjs +10 -10
- package/dist/components/case-studies/index.js +4 -4
- package/dist/components/chat/index.cjs +4 -4
- package/dist/components/chat/index.js +3 -3
- package/dist/components/contact/index.cjs +5 -5
- package/dist/components/contact/index.js +4 -4
- package/dist/components/docs/index.cjs +7 -7
- package/dist/components/docs/index.js +6 -6
- package/dist/components/embeds/index.cjs +5 -5
- package/dist/components/embeds/index.js +4 -4
- package/dist/components/faq/index.cjs +6 -6
- package/dist/components/faq/index.js +5 -5
- package/dist/components/features/index.cjs +4 -4
- package/dist/components/features/index.js +3 -3
- package/dist/components/help-center-pages/index.cjs +23 -23
- package/dist/components/help-center-pages/index.js +14 -14
- package/dist/components/index.cjs +185 -179
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +38 -32
- package/dist/components/index.js.map +1 -1
- package/dist/components/navigation/index.cjs +4 -4
- package/dist/components/navigation/index.js +3 -3
- package/dist/components/onboarding-guides/index.cjs +8 -8
- package/dist/components/onboarding-guides/index.js +7 -7
- package/dist/components/related-content/index.cjs +6 -6
- package/dist/components/related-content/index.js +5 -5
- package/dist/components/tickets/index.cjs +7 -7
- package/dist/components/tickets/index.js +6 -6
- package/dist/components/ui/index.cjs +4 -4
- package/dist/components/ui/index.js +3 -3
- package/dist/contexts/endpoints-runtime-context.d.ts +1 -1
- package/dist/contexts/endpoints-runtime-context.d.ts.map +1 -1
- package/dist/contexts/index.cjs +2 -2
- package/dist/contexts/index.js +1 -1
- package/dist/hooks/index.cjs +3 -3
- package/dist/hooks/index.js +2 -2
- package/dist/hooks/use-self-fetch.d.ts.map +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -5
- package/dist/types/announcement.cjs.map +1 -1
- package/dist/types/announcement.d.ts +0 -6
- package/dist/types/announcement.d.ts.map +1 -1
- package/dist/types/announcement.js.map +1 -1
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/announcement-storage.d.ts +3 -0
- package/dist/utils/announcement-storage.d.ts.map +1 -1
- package/dist/utils/app-config.d.ts.map +1 -1
- package/dist/utils/color-analysis.d.ts +0 -4
- package/dist/utils/color-analysis.d.ts.map +1 -1
- package/dist/utils/index.cjs +186 -177
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js +185 -176
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/ods-color-utils.d.ts +2 -1
- package/dist/utils/ods-color-utils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/announcement-bar.tsx +38 -21
- package/src/components/features/video.tsx +8 -0
- package/src/contexts/endpoints-runtime-context.tsx +1 -1
- package/src/hooks/use-self-fetch.ts +10 -9
- package/src/stories/AnnouncementBar.stories.tsx +8 -14
- package/src/types/announcement.ts +0 -8
- package/src/utils/announcement-storage.ts +17 -0
- package/src/utils/app-config.ts +3 -2
- package/src/utils/color-analysis.ts +5 -2
- package/src/utils/ods-color-utils.ts +4 -7
- package/dist/chunk-3KEBI6TP.cjs.map +0 -1
- package/dist/chunk-CCIBZ7TO.cjs.map +0 -1
- package/dist/chunk-E6YHDT3D.js.map +0 -1
- package/dist/chunk-FFYEDIAG.cjs.map +0 -1
- package/dist/chunk-ICJRSNBM.js.map +0 -1
- package/dist/chunk-NA7XJRWB.js.map +0 -1
- package/dist/chunk-QAFRLO5N.cjs.map +0 -1
- /package/dist/{chunk-RIGB7LP7.js.map → chunk-43H2WOAW.js.map} +0 -0
- /package/dist/{chunk-QYTGHN2T.js.map → chunk-4UZH3MT2.js.map} +0 -0
- /package/dist/{chunk-3XCNFTFV.js.map → chunk-7XVFSGQA.js.map} +0 -0
- /package/dist/{chunk-UN2BJ7XW.js.map → chunk-GJSLKATJ.js.map} +0 -0
- /package/dist/{chunk-GT7AJXKH.js.map → chunk-GMZL4T7C.js.map} +0 -0
- /package/dist/{chunk-BK7QCB5J.js.map → chunk-H66L2265.js.map} +0 -0
- /package/dist/{chunk-F3YLM5PO.js.map → chunk-HB63TQQO.js.map} +0 -0
- /package/dist/{chunk-5XZEY34X.js.map → chunk-HJIRG7R6.js.map} +0 -0
- /package/dist/{chunk-Q2KKEE6W.js.map → chunk-KLBEIJVZ.js.map} +0 -0
- /package/dist/{chunk-RC35ITSR.js.map → chunk-NSF7JUXF.js.map} +0 -0
- /package/dist/{chunk-UIAQXIA6.js.map → chunk-XFP43YKG.js.map} +0 -0
package/dist/utils/index.cjs
CHANGED
|
@@ -468,6 +468,174 @@ function formatBioText(aboutHtml, fallback = "") {
|
|
|
468
468
|
}
|
|
469
469
|
var PLAY_ICON_PATH = "M4.875 5.006c0-2.501 2.793-3.989 4.87-2.592l9.78 6.578c2.135 1.437 2.135 4.58 0 6.016l-9.78 6.579c-2.077 1.396-4.87-.091-4.87-2.593zm2.25 13.988c0 .7.783 1.118 1.364.727l9.78-6.58c.81-.545.81-1.738 0-2.283L8.488 4.28a.875.875 0 0 0-1.364.726v13.988Z";
|
|
470
470
|
|
|
471
|
+
// src/utils/color-analysis.ts
|
|
472
|
+
var DESIGN_PALETTE = [
|
|
473
|
+
{ name: "yellow", hex: "#FFC008", rgb: [255, 192, 8] },
|
|
474
|
+
{ name: "black", hex: "#161616", rgb: [22, 22, 22] },
|
|
475
|
+
{ name: "gray", hex: "#888888", rgb: [136, 136, 136] }
|
|
476
|
+
];
|
|
477
|
+
function hexToRgb(hex) {
|
|
478
|
+
const normalized = hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, (_, r, g, b) => `${r}${r}${g}${g}${b}${b}`);
|
|
479
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(normalized);
|
|
480
|
+
return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : [0, 0, 0];
|
|
481
|
+
}
|
|
482
|
+
function getLuminance(rgb) {
|
|
483
|
+
const [r, g, b] = rgb.map((c) => {
|
|
484
|
+
c = c / 255;
|
|
485
|
+
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
486
|
+
});
|
|
487
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
488
|
+
}
|
|
489
|
+
function getContrastRatio(color1, color2) {
|
|
490
|
+
const lum1 = getLuminance(color1);
|
|
491
|
+
const lum2 = getLuminance(color2);
|
|
492
|
+
const brightest = Math.max(lum1, lum2);
|
|
493
|
+
const darkest = Math.min(lum1, lum2);
|
|
494
|
+
return (brightest + 0.05) / (darkest + 0.05);
|
|
495
|
+
}
|
|
496
|
+
function pickReadableTextColor(bgHex) {
|
|
497
|
+
const bg = hexToRgb(bgHex);
|
|
498
|
+
const darkContrast = getContrastRatio(bg, [26, 26, 26]);
|
|
499
|
+
const lightContrast = getContrastRatio(bg, [250, 250, 250]);
|
|
500
|
+
return darkContrast >= lightContrast ? "dark" : "light";
|
|
501
|
+
}
|
|
502
|
+
function extractDominantColor(canvas) {
|
|
503
|
+
const ctx = canvas.getContext("2d");
|
|
504
|
+
if (!ctx) return [128, 128, 128];
|
|
505
|
+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
506
|
+
const data = imageData.data;
|
|
507
|
+
const sampleSize = Math.max(1, Math.floor(data.length / (4 * 1e3)));
|
|
508
|
+
const colorCounts = {};
|
|
509
|
+
for (let i = 0; i < data.length; i += 4 * sampleSize) {
|
|
510
|
+
const r = data[i];
|
|
511
|
+
const g = data[i + 1];
|
|
512
|
+
const b = data[i + 2];
|
|
513
|
+
const alpha = data[i + 3];
|
|
514
|
+
if (alpha < 128) continue;
|
|
515
|
+
const bucketR = Math.round(r / 32) * 32;
|
|
516
|
+
const bucketG = Math.round(g / 32) * 32;
|
|
517
|
+
const bucketB = Math.round(b / 32) * 32;
|
|
518
|
+
const key = `${bucketR},${bucketG},${bucketB}`;
|
|
519
|
+
colorCounts[key] = (colorCounts[key] || 0) + 1;
|
|
520
|
+
}
|
|
521
|
+
let maxCount = 0;
|
|
522
|
+
let dominantColor = [128, 128, 128];
|
|
523
|
+
for (const [colorKey, count] of Object.entries(colorCounts)) {
|
|
524
|
+
if (count > maxCount) {
|
|
525
|
+
maxCount = count;
|
|
526
|
+
const [r, g, b] = colorKey.split(",").map(Number);
|
|
527
|
+
dominantColor = [r, g, b];
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return dominantColor;
|
|
531
|
+
}
|
|
532
|
+
function getBestContrastColor(imageColor) {
|
|
533
|
+
let bestColor = DESIGN_PALETTE[0];
|
|
534
|
+
let bestContrast = 0;
|
|
535
|
+
for (const color of DESIGN_PALETTE) {
|
|
536
|
+
const contrast = getContrastRatio(imageColor, color.rgb);
|
|
537
|
+
if (contrast > bestContrast) {
|
|
538
|
+
bestContrast = contrast;
|
|
539
|
+
bestColor = color;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return bestContrast >= 3 ? bestColor : DESIGN_PALETTE.find((c) => c.name === "black") || bestColor;
|
|
543
|
+
}
|
|
544
|
+
function analyzeImageColor(imageSrc) {
|
|
545
|
+
return new Promise((resolve, reject) => {
|
|
546
|
+
const img = new Image();
|
|
547
|
+
img.crossOrigin = "anonymous";
|
|
548
|
+
img.onload = () => {
|
|
549
|
+
try {
|
|
550
|
+
const canvas = document.createElement("canvas");
|
|
551
|
+
const ctx = canvas.getContext("2d");
|
|
552
|
+
if (!ctx) {
|
|
553
|
+
reject(new Error("Could not get canvas context"));
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
const maxSize = 100;
|
|
557
|
+
const scale = Math.min(maxSize / img.width, maxSize / img.height);
|
|
558
|
+
canvas.width = img.width * scale;
|
|
559
|
+
canvas.height = img.height * scale;
|
|
560
|
+
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
561
|
+
const dominantColor = extractDominantColor(canvas);
|
|
562
|
+
const bestContrastColor = getBestContrastColor(dominantColor);
|
|
563
|
+
resolve(bestContrastColor);
|
|
564
|
+
} catch (error) {
|
|
565
|
+
reject(error);
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
img.onerror = () => reject(new Error("Failed to load image"));
|
|
569
|
+
img.src = imageSrc;
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
async function extractImageEdgeColorAsync(imageUrl) {
|
|
573
|
+
return new Promise((resolve) => {
|
|
574
|
+
if (typeof window === "undefined") {
|
|
575
|
+
resolve("#000000");
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
const img = new Image();
|
|
579
|
+
img.crossOrigin = "anonymous";
|
|
580
|
+
img.onload = () => {
|
|
581
|
+
try {
|
|
582
|
+
const canvas = document.createElement("canvas");
|
|
583
|
+
const ctx = canvas.getContext("2d");
|
|
584
|
+
if (!ctx) {
|
|
585
|
+
resolve("#000000");
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
const maxSize = 50;
|
|
589
|
+
const scale = Math.min(maxSize / img.naturalWidth, maxSize / img.naturalHeight);
|
|
590
|
+
const w = Math.round(img.naturalWidth * scale);
|
|
591
|
+
const h = Math.round(img.naturalHeight * scale);
|
|
592
|
+
canvas.width = w;
|
|
593
|
+
canvas.height = h;
|
|
594
|
+
ctx.drawImage(img, 0, 0, w, h);
|
|
595
|
+
const data = ctx.getImageData(0, 0, w, h).data;
|
|
596
|
+
const edgeW = Math.max(2, Math.round(w * 0.15));
|
|
597
|
+
const edgeH = Math.max(2, Math.round(h * 0.15));
|
|
598
|
+
const bucketSize = 32;
|
|
599
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
600
|
+
for (let y = 0; y < h; y++) {
|
|
601
|
+
for (let x = 0; x < w; x++) {
|
|
602
|
+
if (!(x < edgeW || x >= w - edgeW || y < edgeH || y >= h - edgeH)) continue;
|
|
603
|
+
const i = (y * w + x) * 4;
|
|
604
|
+
if (data[i + 3] < 128) continue;
|
|
605
|
+
const br = Math.floor(data[i] / bucketSize) * bucketSize;
|
|
606
|
+
const bg = Math.floor(data[i + 1] / bucketSize) * bucketSize;
|
|
607
|
+
const bb = Math.floor(data[i + 2] / bucketSize) * bucketSize;
|
|
608
|
+
const key = `${br},${bg},${bb}`;
|
|
609
|
+
const existing = buckets.get(key);
|
|
610
|
+
if (existing) {
|
|
611
|
+
existing.r += data[i];
|
|
612
|
+
existing.g += data[i + 1];
|
|
613
|
+
existing.b += data[i + 2];
|
|
614
|
+
existing.count++;
|
|
615
|
+
} else {
|
|
616
|
+
buckets.set(key, { r: data[i], g: data[i + 1], b: data[i + 2], count: 1 });
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
let best = { r: 0, g: 0, b: 0, count: 0 };
|
|
621
|
+
for (const b2 of buckets.values()) {
|
|
622
|
+
if (b2.count > best.count) best = b2;
|
|
623
|
+
}
|
|
624
|
+
if (best.count === 0) {
|
|
625
|
+
resolve("#000000");
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
const r = Math.round(best.r / best.count), g = Math.round(best.g / best.count), b = Math.round(best.b / best.count);
|
|
629
|
+
resolve(`#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`);
|
|
630
|
+
} catch {
|
|
631
|
+
resolve("#000000");
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
img.onerror = () => resolve("#000000");
|
|
635
|
+
img.src = imageUrl;
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
|
|
471
639
|
// src/utils/ods-color-utils.ts
|
|
472
640
|
function getPlatformAccentColor(platform) {
|
|
473
641
|
const currentPlatform = platform || getCurrentPlatform();
|
|
@@ -492,18 +660,13 @@ function getCurrentPlatform() {
|
|
|
492
660
|
return process.env.NEXT_PUBLIC_APP_TYPE || "openmsp";
|
|
493
661
|
}
|
|
494
662
|
function getReadableTextColor(hex) {
|
|
495
|
-
|
|
496
|
-
const r = n >> 16 & 255;
|
|
497
|
-
const g = n >> 8 & 255;
|
|
498
|
-
const b = n & 255;
|
|
499
|
-
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
500
|
-
return luminance > 0.5 ? "#212121" : "#fafafa";
|
|
663
|
+
return pickReadableTextColor(hex) === "dark" ? "#212121" : "#fafafa";
|
|
501
664
|
}
|
|
502
665
|
var HEX_PATTERN = /^#[0-9a-fA-F]{6}$/;
|
|
503
666
|
function clamp(n, min, max) {
|
|
504
667
|
return Math.max(min, Math.min(max, n));
|
|
505
668
|
}
|
|
506
|
-
function
|
|
669
|
+
function hexToRgb2(hex) {
|
|
507
670
|
if (!HEX_PATTERN.test(hex)) return null;
|
|
508
671
|
const n = Number.parseInt(hex.slice(1), 16);
|
|
509
672
|
return { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
|
|
@@ -515,7 +678,7 @@ function rgbToHex(r, g, b) {
|
|
|
515
678
|
var HOVER_DARKEN_STEP = 10;
|
|
516
679
|
var ACTIVE_DARKEN_STEP = 20;
|
|
517
680
|
function darkenByStep(hex, step) {
|
|
518
|
-
const rgb =
|
|
681
|
+
const rgb = hexToRgb2(hex);
|
|
519
682
|
if (!rgb) return hex;
|
|
520
683
|
return rgbToHex(rgb.r - step, rgb.g - step, rgb.b - step);
|
|
521
684
|
}
|
|
@@ -2318,173 +2481,6 @@ function isGenericWebsiteDomain(website) {
|
|
|
2318
2481
|
return isGenericDomain(normalizeDomain(website));
|
|
2319
2482
|
}
|
|
2320
2483
|
|
|
2321
|
-
// src/utils/color-analysis.ts
|
|
2322
|
-
var DESIGN_PALETTE = [
|
|
2323
|
-
{ name: "yellow", hex: "#FFC008", rgb: [255, 192, 8] },
|
|
2324
|
-
{ name: "black", hex: "#161616", rgb: [22, 22, 22] },
|
|
2325
|
-
{ name: "gray", hex: "#888888", rgb: [136, 136, 136] }
|
|
2326
|
-
];
|
|
2327
|
-
function hexToRgb2(hex) {
|
|
2328
|
-
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
2329
|
-
return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : [0, 0, 0];
|
|
2330
|
-
}
|
|
2331
|
-
function getLuminance(rgb) {
|
|
2332
|
-
const [r, g, b] = rgb.map((c) => {
|
|
2333
|
-
c = c / 255;
|
|
2334
|
-
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
2335
|
-
});
|
|
2336
|
-
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
2337
|
-
}
|
|
2338
|
-
function getContrastRatio(color1, color2) {
|
|
2339
|
-
const lum1 = getLuminance(color1);
|
|
2340
|
-
const lum2 = getLuminance(color2);
|
|
2341
|
-
const brightest = Math.max(lum1, lum2);
|
|
2342
|
-
const darkest = Math.min(lum1, lum2);
|
|
2343
|
-
return (brightest + 0.05) / (darkest + 0.05);
|
|
2344
|
-
}
|
|
2345
|
-
function pickReadableTextColor(bgHex) {
|
|
2346
|
-
const bg = hexToRgb2(bgHex);
|
|
2347
|
-
const darkContrast = getContrastRatio(bg, [26, 26, 26]);
|
|
2348
|
-
const lightContrast = getContrastRatio(bg, [250, 250, 250]);
|
|
2349
|
-
return darkContrast >= lightContrast ? "dark" : "light";
|
|
2350
|
-
}
|
|
2351
|
-
function extractDominantColor(canvas) {
|
|
2352
|
-
const ctx = canvas.getContext("2d");
|
|
2353
|
-
if (!ctx) return [128, 128, 128];
|
|
2354
|
-
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
2355
|
-
const data = imageData.data;
|
|
2356
|
-
const sampleSize = Math.max(1, Math.floor(data.length / (4 * 1e3)));
|
|
2357
|
-
const colorCounts = {};
|
|
2358
|
-
for (let i = 0; i < data.length; i += 4 * sampleSize) {
|
|
2359
|
-
const r = data[i];
|
|
2360
|
-
const g = data[i + 1];
|
|
2361
|
-
const b = data[i + 2];
|
|
2362
|
-
const alpha = data[i + 3];
|
|
2363
|
-
if (alpha < 128) continue;
|
|
2364
|
-
const bucketR = Math.round(r / 32) * 32;
|
|
2365
|
-
const bucketG = Math.round(g / 32) * 32;
|
|
2366
|
-
const bucketB = Math.round(b / 32) * 32;
|
|
2367
|
-
const key = `${bucketR},${bucketG},${bucketB}`;
|
|
2368
|
-
colorCounts[key] = (colorCounts[key] || 0) + 1;
|
|
2369
|
-
}
|
|
2370
|
-
let maxCount = 0;
|
|
2371
|
-
let dominantColor = [128, 128, 128];
|
|
2372
|
-
for (const [colorKey, count] of Object.entries(colorCounts)) {
|
|
2373
|
-
if (count > maxCount) {
|
|
2374
|
-
maxCount = count;
|
|
2375
|
-
const [r, g, b] = colorKey.split(",").map(Number);
|
|
2376
|
-
dominantColor = [r, g, b];
|
|
2377
|
-
}
|
|
2378
|
-
}
|
|
2379
|
-
return dominantColor;
|
|
2380
|
-
}
|
|
2381
|
-
function getBestContrastColor(imageColor) {
|
|
2382
|
-
let bestColor = DESIGN_PALETTE[0];
|
|
2383
|
-
let bestContrast = 0;
|
|
2384
|
-
for (const color of DESIGN_PALETTE) {
|
|
2385
|
-
const contrast = getContrastRatio(imageColor, color.rgb);
|
|
2386
|
-
if (contrast > bestContrast) {
|
|
2387
|
-
bestContrast = contrast;
|
|
2388
|
-
bestColor = color;
|
|
2389
|
-
}
|
|
2390
|
-
}
|
|
2391
|
-
return bestContrast >= 3 ? bestColor : DESIGN_PALETTE.find((c) => c.name === "black") || bestColor;
|
|
2392
|
-
}
|
|
2393
|
-
function analyzeImageColor(imageSrc) {
|
|
2394
|
-
return new Promise((resolve, reject) => {
|
|
2395
|
-
const img = new Image();
|
|
2396
|
-
img.crossOrigin = "anonymous";
|
|
2397
|
-
img.onload = () => {
|
|
2398
|
-
try {
|
|
2399
|
-
const canvas = document.createElement("canvas");
|
|
2400
|
-
const ctx = canvas.getContext("2d");
|
|
2401
|
-
if (!ctx) {
|
|
2402
|
-
reject(new Error("Could not get canvas context"));
|
|
2403
|
-
return;
|
|
2404
|
-
}
|
|
2405
|
-
const maxSize = 100;
|
|
2406
|
-
const scale = Math.min(maxSize / img.width, maxSize / img.height);
|
|
2407
|
-
canvas.width = img.width * scale;
|
|
2408
|
-
canvas.height = img.height * scale;
|
|
2409
|
-
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
2410
|
-
const dominantColor = extractDominantColor(canvas);
|
|
2411
|
-
const bestContrastColor = getBestContrastColor(dominantColor);
|
|
2412
|
-
resolve(bestContrastColor);
|
|
2413
|
-
} catch (error) {
|
|
2414
|
-
reject(error);
|
|
2415
|
-
}
|
|
2416
|
-
};
|
|
2417
|
-
img.onerror = () => reject(new Error("Failed to load image"));
|
|
2418
|
-
img.src = imageSrc;
|
|
2419
|
-
});
|
|
2420
|
-
}
|
|
2421
|
-
async function extractImageEdgeColorAsync(imageUrl) {
|
|
2422
|
-
return new Promise((resolve) => {
|
|
2423
|
-
if (typeof window === "undefined") {
|
|
2424
|
-
resolve("#000000");
|
|
2425
|
-
return;
|
|
2426
|
-
}
|
|
2427
|
-
const img = new Image();
|
|
2428
|
-
img.crossOrigin = "anonymous";
|
|
2429
|
-
img.onload = () => {
|
|
2430
|
-
try {
|
|
2431
|
-
const canvas = document.createElement("canvas");
|
|
2432
|
-
const ctx = canvas.getContext("2d");
|
|
2433
|
-
if (!ctx) {
|
|
2434
|
-
resolve("#000000");
|
|
2435
|
-
return;
|
|
2436
|
-
}
|
|
2437
|
-
const maxSize = 50;
|
|
2438
|
-
const scale = Math.min(maxSize / img.naturalWidth, maxSize / img.naturalHeight);
|
|
2439
|
-
const w = Math.round(img.naturalWidth * scale);
|
|
2440
|
-
const h = Math.round(img.naturalHeight * scale);
|
|
2441
|
-
canvas.width = w;
|
|
2442
|
-
canvas.height = h;
|
|
2443
|
-
ctx.drawImage(img, 0, 0, w, h);
|
|
2444
|
-
const data = ctx.getImageData(0, 0, w, h).data;
|
|
2445
|
-
const edgeW = Math.max(2, Math.round(w * 0.15));
|
|
2446
|
-
const edgeH = Math.max(2, Math.round(h * 0.15));
|
|
2447
|
-
const bucketSize = 32;
|
|
2448
|
-
const buckets = /* @__PURE__ */ new Map();
|
|
2449
|
-
for (let y = 0; y < h; y++) {
|
|
2450
|
-
for (let x = 0; x < w; x++) {
|
|
2451
|
-
if (!(x < edgeW || x >= w - edgeW || y < edgeH || y >= h - edgeH)) continue;
|
|
2452
|
-
const i = (y * w + x) * 4;
|
|
2453
|
-
if (data[i + 3] < 128) continue;
|
|
2454
|
-
const br = Math.floor(data[i] / bucketSize) * bucketSize;
|
|
2455
|
-
const bg = Math.floor(data[i + 1] / bucketSize) * bucketSize;
|
|
2456
|
-
const bb = Math.floor(data[i + 2] / bucketSize) * bucketSize;
|
|
2457
|
-
const key = `${br},${bg},${bb}`;
|
|
2458
|
-
const existing = buckets.get(key);
|
|
2459
|
-
if (existing) {
|
|
2460
|
-
existing.r += data[i];
|
|
2461
|
-
existing.g += data[i + 1];
|
|
2462
|
-
existing.b += data[i + 2];
|
|
2463
|
-
existing.count++;
|
|
2464
|
-
} else {
|
|
2465
|
-
buckets.set(key, { r: data[i], g: data[i + 1], b: data[i + 2], count: 1 });
|
|
2466
|
-
}
|
|
2467
|
-
}
|
|
2468
|
-
}
|
|
2469
|
-
let best = { r: 0, g: 0, b: 0, count: 0 };
|
|
2470
|
-
for (const b2 of buckets.values()) {
|
|
2471
|
-
if (b2.count > best.count) best = b2;
|
|
2472
|
-
}
|
|
2473
|
-
if (best.count === 0) {
|
|
2474
|
-
resolve("#000000");
|
|
2475
|
-
return;
|
|
2476
|
-
}
|
|
2477
|
-
const r = Math.round(best.r / best.count), g = Math.round(best.g / best.count), b = Math.round(best.b / best.count);
|
|
2478
|
-
resolve(`#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`);
|
|
2479
|
-
} catch {
|
|
2480
|
-
resolve("#000000");
|
|
2481
|
-
}
|
|
2482
|
-
};
|
|
2483
|
-
img.onerror = () => resolve("#000000");
|
|
2484
|
-
img.src = imageUrl;
|
|
2485
|
-
});
|
|
2486
|
-
}
|
|
2487
|
-
|
|
2488
2484
|
// src/utils/announcement-storage.ts
|
|
2489
2485
|
function announcementDismissCookieName(platform) {
|
|
2490
2486
|
return `${platform}-announcement-dismissed`;
|
|
@@ -2513,6 +2509,19 @@ function isAnnouncementDismissed(platform, id) {
|
|
|
2513
2509
|
return false;
|
|
2514
2510
|
}
|
|
2515
2511
|
}
|
|
2512
|
+
function clearAnnouncementDismissals(platform) {
|
|
2513
|
+
if (typeof document === "undefined") return;
|
|
2514
|
+
document.cookie = `${announcementDismissCookieName(platform)}=; path=/; max-age=0`;
|
|
2515
|
+
try {
|
|
2516
|
+
const prefix = `${platform}-announcement-`;
|
|
2517
|
+
Object.keys(localStorage).forEach((key) => {
|
|
2518
|
+
if (key.startsWith(prefix) && key.endsWith("-dismissed")) {
|
|
2519
|
+
localStorage.removeItem(key);
|
|
2520
|
+
}
|
|
2521
|
+
});
|
|
2522
|
+
} catch {
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2516
2525
|
function clearLegacyAnnouncementCache(platform) {
|
|
2517
2526
|
if (typeof window === "undefined") return;
|
|
2518
2527
|
try {
|
|
@@ -4091,6 +4100,7 @@ exports.buildOgPlaceholderUrl = buildOgPlaceholderUrl;
|
|
|
4091
4100
|
exports.buildSuggestionUrl = buildSuggestionUrl;
|
|
4092
4101
|
exports.canonicalContentRefType = canonicalContentRefType;
|
|
4093
4102
|
exports.cleanEmailDomain = cleanEmailDomain;
|
|
4103
|
+
exports.clearAnnouncementDismissals = clearAnnouncementDismissals;
|
|
4094
4104
|
exports.clearEmbedProxyAuth = clearEmbedProxyAuth;
|
|
4095
4105
|
exports.clearLegacyAnnouncementCache = clearLegacyAnnouncementCache;
|
|
4096
4106
|
exports.clickupTaskUrl = clickupTaskUrl;
|
|
@@ -4185,7 +4195,6 @@ exports.getEmbedProxyAuth = getEmbedProxyAuth;
|
|
|
4185
4195
|
exports.getFirstLastInitials = getFirstLastInitials;
|
|
4186
4196
|
exports.getIconComponent = getIconComponent;
|
|
4187
4197
|
exports.getInitialExpandedNodeIds = getInitialExpandedNodeIds;
|
|
4188
|
-
exports.getLuminance = getLuminance;
|
|
4189
4198
|
exports.getOSIcon = getOSIcon;
|
|
4190
4199
|
exports.getOSLabel = getOSLabel;
|
|
4191
4200
|
exports.getOSPlatformId = getOSPlatformId;
|
|
@@ -4214,7 +4223,7 @@ exports.getToolLabel = getToolLabel;
|
|
|
4214
4223
|
exports.getToolTypeAliases = getToolTypeAliases;
|
|
4215
4224
|
exports.getTrendColors = getTrendColors;
|
|
4216
4225
|
exports.hasGenericEmailDomain = hasGenericEmailDomain;
|
|
4217
|
-
exports.hexToRgb =
|
|
4226
|
+
exports.hexToRgb = hexToRgb2;
|
|
4218
4227
|
exports.isAnnouncementDismissed = isAnnouncementDismissed;
|
|
4219
4228
|
exports.isCrossOriginUrl = isCrossOriginUrl;
|
|
4220
4229
|
exports.isDismissedCookieValue = isDismissedCookieValue;
|