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