@flamingo-stack/openframe-frontend-core 0.0.406 → 0.0.407
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-6WMVBCNA.js → chunk-43H2WOAW.js} +3 -3
- package/dist/{chunk-TFDNJTBX.js → chunk-4UZH3MT2.js} +4 -4
- package/dist/{chunk-VANFD4FX.cjs → chunk-5M5W6XDY.cjs} +7 -7
- package/dist/{chunk-VANFD4FX.cjs.map → chunk-5M5W6XDY.cjs.map} +1 -1
- package/dist/{chunk-GNS65HNC.cjs → chunk-74FWQI73.cjs} +18 -18
- package/dist/{chunk-GNS65HNC.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-XXG2Z2JT.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-SOK32D6C.js → chunk-CVYSW33D.js} +198 -189
- package/dist/chunk-CVYSW33D.js.map +1 -0
- package/dist/{chunk-COERBDG4.cjs → chunk-DOBNDDNE.cjs} +75 -75
- package/dist/{chunk-COERBDG4.cjs.map → chunk-DOBNDDNE.cjs.map} +1 -1
- package/dist/{chunk-LL4QQSAD.cjs → chunk-GGDM5J4B.cjs} +331 -322
- package/dist/chunk-GGDM5J4B.cjs.map +1 -0
- package/dist/{chunk-LSPBPUQM.js → chunk-GJSLKATJ.js} +2 -2
- package/dist/{chunk-C3NPMZBI.js → chunk-GMZL4T7C.js} +3 -3
- package/dist/{chunk-OATWTTCI.js → chunk-H66L2265.js} +6 -6
- package/dist/{chunk-ZVUR3A33.js → chunk-HB63TQQO.js} +2 -2
- package/dist/{chunk-3KZXOLFK.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-AYFWYOL6.js → chunk-KLBEIJVZ.js} +7 -7
- package/dist/{chunk-SF4G7M6U.cjs → chunk-LC6RRLFA.cjs} +15 -15
- package/dist/{chunk-SF4G7M6U.cjs.map → chunk-LC6RRLFA.cjs.map} +1 -1
- package/dist/{chunk-P43ZHPM6.cjs → chunk-LPC3C7MG.cjs} +40 -40
- package/dist/{chunk-P43ZHPM6.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-PQN5R5II.js → chunk-NSF7JUXF.js} +7 -7
- package/dist/{chunk-VIB4SGCD.cjs → chunk-PRKMOF2U.cjs} +14 -14
- package/dist/{chunk-VIB4SGCD.cjs.map → chunk-PRKMOF2U.cjs.map} +1 -1
- package/dist/{chunk-CF3LBCNI.cjs → chunk-Q2MC3CBI.cjs} +35 -35
- package/dist/{chunk-CF3LBCNI.cjs.map → chunk-Q2MC3CBI.cjs.map} +1 -1
- package/dist/{chunk-ISYVNPRT.cjs → chunk-R4MXLJUS.cjs} +42 -42
- package/dist/{chunk-ISYVNPRT.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-VZGU4BV6.cjs → chunk-SY3QS2E5.cjs} +29 -29
- package/dist/{chunk-VZGU4BV6.cjs.map → chunk-SY3QS2E5.cjs.map} +1 -1
- package/dist/{chunk-HJJXNMM7.cjs → chunk-WCPUJA3Y.cjs} +7 -7
- package/dist/{chunk-HJJXNMM7.cjs.map → chunk-WCPUJA3Y.cjs.map} +1 -1
- package/dist/{chunk-7RVSGGO6.js → chunk-XFP43YKG.js} +6 -6
- package/dist/{chunk-JAPP2F4M.cjs → chunk-YX7C5JD7.cjs} +77 -77
- package/dist/{chunk-JAPP2F4M.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/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-LL4QQSAD.cjs.map +0 -1
- package/dist/chunk-NA7XJRWB.js.map +0 -1
- package/dist/chunk-QAFRLO5N.cjs.map +0 -1
- package/dist/chunk-SOK32D6C.js.map +0 -1
- /package/dist/{chunk-6WMVBCNA.js.map → chunk-43H2WOAW.js.map} +0 -0
- /package/dist/{chunk-TFDNJTBX.js.map → chunk-4UZH3MT2.js.map} +0 -0
- /package/dist/{chunk-XXG2Z2JT.js.map → chunk-7XVFSGQA.js.map} +0 -0
- /package/dist/{chunk-LSPBPUQM.js.map → chunk-GJSLKATJ.js.map} +0 -0
- /package/dist/{chunk-C3NPMZBI.js.map → chunk-GMZL4T7C.js.map} +0 -0
- /package/dist/{chunk-OATWTTCI.js.map → chunk-H66L2265.js.map} +0 -0
- /package/dist/{chunk-ZVUR3A33.js.map → chunk-HB63TQQO.js.map} +0 -0
- /package/dist/{chunk-3KZXOLFK.js.map → chunk-HJIRG7R6.js.map} +0 -0
- /package/dist/{chunk-AYFWYOL6.js.map → chunk-KLBEIJVZ.js.map} +0 -0
- /package/dist/{chunk-PQN5R5II.js.map → chunk-NSF7JUXF.js.map} +0 -0
- /package/dist/{chunk-7RVSGGO6.js.map → chunk-XFP43YKG.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
3
|
useSelfFetch
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-NO2KT42M.js";
|
|
5
5
|
import {
|
|
6
6
|
BlogCard,
|
|
7
7
|
BlogCardSkeleton,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
getContentRefLabelOrTitleCase,
|
|
34
34
|
init_pagination,
|
|
35
35
|
orderContentRefTypes
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-CVYSW33D.js";
|
|
37
37
|
|
|
38
38
|
// src/components/related-content/related-content-section.tsx
|
|
39
39
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
@@ -359,4 +359,4 @@ export {
|
|
|
359
359
|
GROUP_PAGE_SIZE,
|
|
360
360
|
RelatedContentSection
|
|
361
361
|
};
|
|
362
|
-
//# sourceMappingURL=chunk-
|
|
362
|
+
//# sourceMappingURL=chunk-7XVFSGQA.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var _chunkSTGWQFYTcjs = require('./chunk-STGWQFYT.cjs');
|
|
5
5
|
|
|
6
6
|
// src/hooks/use-self-fetch.ts
|
|
7
7
|
var _react = require('react');
|
|
@@ -29,7 +29,7 @@ function useSelfFetch(url, options) {
|
|
|
29
29
|
try {
|
|
30
30
|
setIsLoading(true);
|
|
31
31
|
setError(false);
|
|
32
|
-
const res = await
|
|
32
|
+
const res = await _chunkSTGWQFYTcjs.contentFetch.call(void 0, url, { signal: ctrl.signal });
|
|
33
33
|
if (!res.ok) throw new Error(`Request failed (${res.status})`);
|
|
34
34
|
const json = await res.json();
|
|
35
35
|
if (!cancelled) {
|
|
@@ -51,13 +51,16 @@ function useSelfFetch(url, options) {
|
|
|
51
51
|
ctrl.abort();
|
|
52
52
|
};
|
|
53
53
|
}, [url, reloadKey]);
|
|
54
|
+
const forceReload = () => {
|
|
55
|
+
dataUrlRef.current = null;
|
|
56
|
+
setReloadKey((k) => k + 1);
|
|
57
|
+
};
|
|
54
58
|
_react.useEffect.call(void 0, () => {
|
|
55
59
|
if (!revalidateOnVisibleAfterMs || url === null) return;
|
|
56
60
|
const onVisible = () => {
|
|
57
61
|
if (document.visibilityState !== "visible") return;
|
|
58
62
|
if (Date.now() - dataAtRef.current < revalidateOnVisibleAfterMs) return;
|
|
59
|
-
|
|
60
|
-
setReloadKey((k) => k + 1);
|
|
63
|
+
forceReload();
|
|
61
64
|
};
|
|
62
65
|
document.addEventListener("visibilitychange", onVisible);
|
|
63
66
|
return () => document.removeEventListener("visibilitychange", onVisible);
|
|
@@ -67,16 +70,12 @@ function useSelfFetch(url, options) {
|
|
|
67
70
|
setData,
|
|
68
71
|
isLoading,
|
|
69
72
|
error,
|
|
70
|
-
// Force a re-fetch of the current url
|
|
71
|
-
|
|
72
|
-
reload: () => {
|
|
73
|
-
dataUrlRef.current = null;
|
|
74
|
-
setReloadKey((k) => k + 1);
|
|
75
|
-
}
|
|
73
|
+
// Force a re-fetch of the current url (error-retry affordance).
|
|
74
|
+
reload: forceReload
|
|
76
75
|
};
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
|
|
80
79
|
|
|
81
80
|
exports.useSelfFetch = useSelfFetch;
|
|
82
|
-
//# sourceMappingURL=chunk-
|
|
81
|
+
//# sourceMappingURL=chunk-CUN4CJUN.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-CUN4CJUN.cjs","../src/hooks/use-self-fetch.ts"],"names":[],"mappings":"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","file":"/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-CUN4CJUN.cjs","sourcesContent":[null,"'use client'\n\nimport { useEffect, useRef, useState, type Dispatch, type SetStateAction } from 'react'\nimport { contentFetch } from '../utils/embed-content-fetch'\n\nexport interface UseSelfFetchResult<T> {\n data: T | null\n /** Imperatively patch the fetched data (e.g. optimistic vote updates). */\n setData: Dispatch<SetStateAction<T | null>>\n isLoading: boolean\n error: boolean\n /** Re-run the fetch (error-retry affordance). */\n reload: () => void\n}\n\n/**\n * The single source for the 4 self-fetching content views\n * (`ProductReleasesView`, `RoadmapView`, the onboarding catalog/detail). GETs a\n * configured `url` into component state with **plain `fetch` + `useEffect`** —\n * deliberately NO react-query, so embedders don't need a QueryClient. This is\n * the same technology choice the shipped `DeliveryLists` makes; that component\n * predates this hook and still hand-rolls the loop (a future pass can migrate\n * it onto a two-url variant of this hook).\n *\n * Behaviour:\n * - `url = null` → fetching is DISABLED (controlled / SSR mode, or missing\n * config); returns `initialData ?? null` and never fetches.\n * - `initialData` provided → hydrates immediately and SKIPS the first fetch\n * (so the hub's server-rendered data isn't re-fetched on mount); later\n * `url` changes still re-fetch.\n * - a `cancelled` guard ensures an in-flight response from a STALE `url`\n * (e.g. a fast pagination / section toggle) can't overwrite a newer one.\n * - `reload()` bumps an internal key to retry after an error.\n * - `revalidateOnVisibleAfterMs` (opt-in) → re-fetch when the tab becomes\n * visible AND the held data is older than the threshold. Event-driven\n * freshness with ZERO background requests — the replacement for\n * setInterval polling. Data age counts from the last completed fetch, or\n * from mount when `initialData` seeded it (an SSR seed is milliseconds\n * old — without that, the first refocus would always refire).\n *\n * Re-fetches whenever `url` changes, so callers fold all query params INTO the\n * url string (the url IS the cache key).\n */\nexport function useSelfFetch<T>(\n url: string | null,\n options?: { initialData?: T; revalidateOnVisibleAfterMs?: number },\n): UseSelfFetchResult<T> {\n const initialData = options?.initialData\n const revalidateOnVisibleAfterMs = options?.revalidateOnVisibleAfterMs\n const [data, setData] = useState<T | null>(initialData ?? null)\n const [isLoading, setIsLoading] = useState(initialData === undefined && url !== null)\n const [error, setError] = useState(false)\n const [reloadKey, setReloadKey] = useState(0)\n // When the held data was obtained: seeded at mount for SSR-hydrated data,\n // stamped after each completed fetch. Drives the visibility revalidation age\n // check. 0 = nothing held yet (first visible event may fetch).\n const dataAtRef = useRef<number>(initialData !== undefined ? Date.now() : 0)\n // The url whose data we currently hold — seeded from SSR `initialData`, then set after\n // each completed fetch. The effect skips the fetch when this equals `url` (so server-\n // rendered data isn't re-fetched on mount). A VALUE compare (not a one-shot flag) so the\n // SSR-hydration skip survives React 18 StrictMode's mount→unmount→remount in dev;\n // `reload()` nulls it to force a re-fetch of the same url.\n const dataUrlRef = useRef<string | null>(initialData !== undefined ? url : null)\n\n // Re-sync when a CONTROLLED `initialData` changes (e.g. the host navigates\n // between detail slugs without remounting). No-op in self-fetch mode, where\n // `initialData` is `undefined`.\n useEffect(() => {\n if (initialData !== undefined) setData(initialData)\n }, [initialData])\n\n useEffect(() => {\n if (url === null) {\n setIsLoading(false)\n return\n }\n // Already hold data for this exact url (SSR-hydrated, or a prior completed fetch) →\n // skip. `reload()` clears `dataUrlRef` so a retry of the same url still fetches.\n if (dataUrlRef.current === url) return\n const ctrl = new AbortController()\n let cancelled = false\n async function load() {\n try {\n setIsLoading(true)\n setError(false)\n const res = await contentFetch(url as string, { signal: ctrl.signal })\n if (!res.ok) throw new Error(`Request failed (${res.status})`)\n const json = (await res.json()) as T\n if (!cancelled) {\n setData(json)\n dataUrlRef.current = url // remember the url we now hold data for\n dataAtRef.current = Date.now()\n }\n } catch (err) {\n // AbortError on cleanup (unmount / stale-url change / React StrictMode's dev\n // double-invoke) is EXPECTED — the request was intentionally aborted. Aborting\n // also means the orphaned StrictMode fetch shows as \"cancelled\" instead of\n // completing as a wasted duplicate (parity with useChatIdentity). Only real\n // failures fall through to the error state + console.\n if (cancelled || (err as Error)?.name === 'AbortError') return\n setError(true)\n console.error('useSelfFetch:', url, err)\n } finally {\n if (!cancelled) setIsLoading(false)\n }\n }\n load()\n return () => {\n cancelled = true\n ctrl.abort()\n }\n // `url` folds in every query param; `reloadKey` drives retry.\n }, [url, reloadKey])\n\n // ONE force-refetch mechanic shared by reload() and the visibility\n // revalidation: clear the held-url skip, bump the effect key.\n const forceReload = () => {\n dataUrlRef.current = null\n setReloadKey((k) => k + 1)\n }\n\n // Opt-in visibility-driven revalidation. Registered only when the option is\n // set and fetching is enabled; SSR-safe (effects don't run on the server)\n // and StrictMode-safe (idempotent listener, cleaned up per mount cycle).\n useEffect(() => {\n if (!revalidateOnVisibleAfterMs || url === null) return\n const onVisible = () => {\n if (document.visibilityState !== 'visible') return\n if (Date.now() - dataAtRef.current < revalidateOnVisibleAfterMs) return\n forceReload()\n }\n document.addEventListener('visibilitychange', onVisible)\n return () => document.removeEventListener('visibilitychange', onVisible)\n }, [url, revalidateOnVisibleAfterMs])\n\n return {\n data,\n setData,\n isLoading,\n error,\n // Force a re-fetch of the current url (error-retry affordance).\n reload: forceReload,\n }\n}\n"]}
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
useOgPlaceholderUrl,
|
|
27
27
|
useOnboardingState,
|
|
28
28
|
useToast
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-7Q52HP45.js";
|
|
30
30
|
import {
|
|
31
31
|
AlertCircleIcon,
|
|
32
32
|
AnthropicLogoGreyIcon,
|
|
@@ -150,7 +150,7 @@ import {
|
|
|
150
150
|
import {
|
|
151
151
|
useChatRuntime,
|
|
152
152
|
useRequiredChatRuntime
|
|
153
|
-
} from "./chunk-
|
|
153
|
+
} from "./chunk-KFQXO7QB.js";
|
|
154
154
|
import {
|
|
155
155
|
dynamic
|
|
156
156
|
} from "./chunk-EL5YVPD5.js";
|
|
@@ -2745,6 +2745,174 @@ function ColorSwatch({ color, className }) {
|
|
|
2745
2745
|
// src/components/ui/ticket-status-tag.tsx
|
|
2746
2746
|
init_cn();
|
|
2747
2747
|
|
|
2748
|
+
// src/utils/color-analysis.ts
|
|
2749
|
+
var DESIGN_PALETTE = [
|
|
2750
|
+
{ name: "yellow", hex: "#FFC008", rgb: [255, 192, 8] },
|
|
2751
|
+
{ name: "black", hex: "#161616", rgb: [22, 22, 22] },
|
|
2752
|
+
{ name: "gray", hex: "#888888", rgb: [136, 136, 136] }
|
|
2753
|
+
];
|
|
2754
|
+
function hexToRgb(hex) {
|
|
2755
|
+
const normalized = hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, (_, r, g, b) => `${r}${r}${g}${g}${b}${b}`);
|
|
2756
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(normalized);
|
|
2757
|
+
return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : [0, 0, 0];
|
|
2758
|
+
}
|
|
2759
|
+
function getLuminance(rgb) {
|
|
2760
|
+
const [r, g, b] = rgb.map((c) => {
|
|
2761
|
+
c = c / 255;
|
|
2762
|
+
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
2763
|
+
});
|
|
2764
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
2765
|
+
}
|
|
2766
|
+
function getContrastRatio(color1, color2) {
|
|
2767
|
+
const lum1 = getLuminance(color1);
|
|
2768
|
+
const lum2 = getLuminance(color2);
|
|
2769
|
+
const brightest = Math.max(lum1, lum2);
|
|
2770
|
+
const darkest = Math.min(lum1, lum2);
|
|
2771
|
+
return (brightest + 0.05) / (darkest + 0.05);
|
|
2772
|
+
}
|
|
2773
|
+
function pickReadableTextColor(bgHex) {
|
|
2774
|
+
const bg = hexToRgb(bgHex);
|
|
2775
|
+
const darkContrast = getContrastRatio(bg, [26, 26, 26]);
|
|
2776
|
+
const lightContrast = getContrastRatio(bg, [250, 250, 250]);
|
|
2777
|
+
return darkContrast >= lightContrast ? "dark" : "light";
|
|
2778
|
+
}
|
|
2779
|
+
function extractDominantColor(canvas) {
|
|
2780
|
+
const ctx = canvas.getContext("2d");
|
|
2781
|
+
if (!ctx) return [128, 128, 128];
|
|
2782
|
+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
2783
|
+
const data = imageData.data;
|
|
2784
|
+
const sampleSize = Math.max(1, Math.floor(data.length / (4 * 1e3)));
|
|
2785
|
+
const colorCounts = {};
|
|
2786
|
+
for (let i = 0; i < data.length; i += 4 * sampleSize) {
|
|
2787
|
+
const r = data[i];
|
|
2788
|
+
const g = data[i + 1];
|
|
2789
|
+
const b = data[i + 2];
|
|
2790
|
+
const alpha = data[i + 3];
|
|
2791
|
+
if (alpha < 128) continue;
|
|
2792
|
+
const bucketR = Math.round(r / 32) * 32;
|
|
2793
|
+
const bucketG = Math.round(g / 32) * 32;
|
|
2794
|
+
const bucketB = Math.round(b / 32) * 32;
|
|
2795
|
+
const key = `${bucketR},${bucketG},${bucketB}`;
|
|
2796
|
+
colorCounts[key] = (colorCounts[key] || 0) + 1;
|
|
2797
|
+
}
|
|
2798
|
+
let maxCount = 0;
|
|
2799
|
+
let dominantColor = [128, 128, 128];
|
|
2800
|
+
for (const [colorKey, count] of Object.entries(colorCounts)) {
|
|
2801
|
+
if (count > maxCount) {
|
|
2802
|
+
maxCount = count;
|
|
2803
|
+
const [r, g, b] = colorKey.split(",").map(Number);
|
|
2804
|
+
dominantColor = [r, g, b];
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
return dominantColor;
|
|
2808
|
+
}
|
|
2809
|
+
function getBestContrastColor(imageColor) {
|
|
2810
|
+
let bestColor = DESIGN_PALETTE[0];
|
|
2811
|
+
let bestContrast = 0;
|
|
2812
|
+
for (const color of DESIGN_PALETTE) {
|
|
2813
|
+
const contrast = getContrastRatio(imageColor, color.rgb);
|
|
2814
|
+
if (contrast > bestContrast) {
|
|
2815
|
+
bestContrast = contrast;
|
|
2816
|
+
bestColor = color;
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
return bestContrast >= 3 ? bestColor : DESIGN_PALETTE.find((c) => c.name === "black") || bestColor;
|
|
2820
|
+
}
|
|
2821
|
+
function analyzeImageColor(imageSrc) {
|
|
2822
|
+
return new Promise((resolve, reject) => {
|
|
2823
|
+
const img = new Image();
|
|
2824
|
+
img.crossOrigin = "anonymous";
|
|
2825
|
+
img.onload = () => {
|
|
2826
|
+
try {
|
|
2827
|
+
const canvas = document.createElement("canvas");
|
|
2828
|
+
const ctx = canvas.getContext("2d");
|
|
2829
|
+
if (!ctx) {
|
|
2830
|
+
reject(new Error("Could not get canvas context"));
|
|
2831
|
+
return;
|
|
2832
|
+
}
|
|
2833
|
+
const maxSize = 100;
|
|
2834
|
+
const scale = Math.min(maxSize / img.width, maxSize / img.height);
|
|
2835
|
+
canvas.width = img.width * scale;
|
|
2836
|
+
canvas.height = img.height * scale;
|
|
2837
|
+
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
2838
|
+
const dominantColor = extractDominantColor(canvas);
|
|
2839
|
+
const bestContrastColor = getBestContrastColor(dominantColor);
|
|
2840
|
+
resolve(bestContrastColor);
|
|
2841
|
+
} catch (error) {
|
|
2842
|
+
reject(error);
|
|
2843
|
+
}
|
|
2844
|
+
};
|
|
2845
|
+
img.onerror = () => reject(new Error("Failed to load image"));
|
|
2846
|
+
img.src = imageSrc;
|
|
2847
|
+
});
|
|
2848
|
+
}
|
|
2849
|
+
async function extractImageEdgeColorAsync(imageUrl) {
|
|
2850
|
+
return new Promise((resolve) => {
|
|
2851
|
+
if (typeof window === "undefined") {
|
|
2852
|
+
resolve("#000000");
|
|
2853
|
+
return;
|
|
2854
|
+
}
|
|
2855
|
+
const img = new Image();
|
|
2856
|
+
img.crossOrigin = "anonymous";
|
|
2857
|
+
img.onload = () => {
|
|
2858
|
+
try {
|
|
2859
|
+
const canvas = document.createElement("canvas");
|
|
2860
|
+
const ctx = canvas.getContext("2d");
|
|
2861
|
+
if (!ctx) {
|
|
2862
|
+
resolve("#000000");
|
|
2863
|
+
return;
|
|
2864
|
+
}
|
|
2865
|
+
const maxSize = 50;
|
|
2866
|
+
const scale = Math.min(maxSize / img.naturalWidth, maxSize / img.naturalHeight);
|
|
2867
|
+
const w = Math.round(img.naturalWidth * scale);
|
|
2868
|
+
const h = Math.round(img.naturalHeight * scale);
|
|
2869
|
+
canvas.width = w;
|
|
2870
|
+
canvas.height = h;
|
|
2871
|
+
ctx.drawImage(img, 0, 0, w, h);
|
|
2872
|
+
const data = ctx.getImageData(0, 0, w, h).data;
|
|
2873
|
+
const edgeW = Math.max(2, Math.round(w * 0.15));
|
|
2874
|
+
const edgeH = Math.max(2, Math.round(h * 0.15));
|
|
2875
|
+
const bucketSize = 32;
|
|
2876
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
2877
|
+
for (let y = 0; y < h; y++) {
|
|
2878
|
+
for (let x = 0; x < w; x++) {
|
|
2879
|
+
if (!(x < edgeW || x >= w - edgeW || y < edgeH || y >= h - edgeH)) continue;
|
|
2880
|
+
const i = (y * w + x) * 4;
|
|
2881
|
+
if (data[i + 3] < 128) continue;
|
|
2882
|
+
const br = Math.floor(data[i] / bucketSize) * bucketSize;
|
|
2883
|
+
const bg = Math.floor(data[i + 1] / bucketSize) * bucketSize;
|
|
2884
|
+
const bb = Math.floor(data[i + 2] / bucketSize) * bucketSize;
|
|
2885
|
+
const key = `${br},${bg},${bb}`;
|
|
2886
|
+
const existing = buckets.get(key);
|
|
2887
|
+
if (existing) {
|
|
2888
|
+
existing.r += data[i];
|
|
2889
|
+
existing.g += data[i + 1];
|
|
2890
|
+
existing.b += data[i + 2];
|
|
2891
|
+
existing.count++;
|
|
2892
|
+
} else {
|
|
2893
|
+
buckets.set(key, { r: data[i], g: data[i + 1], b: data[i + 2], count: 1 });
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
let best = { r: 0, g: 0, b: 0, count: 0 };
|
|
2898
|
+
for (const b2 of buckets.values()) {
|
|
2899
|
+
if (b2.count > best.count) best = b2;
|
|
2900
|
+
}
|
|
2901
|
+
if (best.count === 0) {
|
|
2902
|
+
resolve("#000000");
|
|
2903
|
+
return;
|
|
2904
|
+
}
|
|
2905
|
+
const r = Math.round(best.r / best.count), g = Math.round(best.g / best.count), b = Math.round(best.b / best.count);
|
|
2906
|
+
resolve(`#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`);
|
|
2907
|
+
} catch {
|
|
2908
|
+
resolve("#000000");
|
|
2909
|
+
}
|
|
2910
|
+
};
|
|
2911
|
+
img.onerror = () => resolve("#000000");
|
|
2912
|
+
img.src = imageUrl;
|
|
2913
|
+
});
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2748
2916
|
// src/utils/ods-color-utils.ts
|
|
2749
2917
|
function getPlatformAccentColor(platform) {
|
|
2750
2918
|
const currentPlatform = platform || getCurrentPlatform();
|
|
@@ -2769,18 +2937,13 @@ function getCurrentPlatform() {
|
|
|
2769
2937
|
return process.env.NEXT_PUBLIC_APP_TYPE || "openmsp";
|
|
2770
2938
|
}
|
|
2771
2939
|
function getReadableTextColor(hex) {
|
|
2772
|
-
|
|
2773
|
-
const r = n >> 16 & 255;
|
|
2774
|
-
const g = n >> 8 & 255;
|
|
2775
|
-
const b = n & 255;
|
|
2776
|
-
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
2777
|
-
return luminance > 0.5 ? "#212121" : "#fafafa";
|
|
2940
|
+
return pickReadableTextColor(hex) === "dark" ? "#212121" : "#fafafa";
|
|
2778
2941
|
}
|
|
2779
2942
|
var HEX_PATTERN = /^#[0-9a-fA-F]{6}$/;
|
|
2780
2943
|
function clamp(n, min, max) {
|
|
2781
2944
|
return Math.max(min, Math.min(max, n));
|
|
2782
2945
|
}
|
|
2783
|
-
function
|
|
2946
|
+
function hexToRgb2(hex) {
|
|
2784
2947
|
if (!HEX_PATTERN.test(hex)) return null;
|
|
2785
2948
|
const n = Number.parseInt(hex.slice(1), 16);
|
|
2786
2949
|
return { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
|
|
@@ -2792,7 +2955,7 @@ function rgbToHex(r, g, b) {
|
|
|
2792
2955
|
var HOVER_DARKEN_STEP = 10;
|
|
2793
2956
|
var ACTIVE_DARKEN_STEP = 20;
|
|
2794
2957
|
function darkenByStep(hex, step) {
|
|
2795
|
-
const rgb =
|
|
2958
|
+
const rgb = hexToRgb2(hex);
|
|
2796
2959
|
if (!rgb) return hex;
|
|
2797
2960
|
return rgbToHex(rgb.r - step, rgb.g - step, rgb.b - step);
|
|
2798
2961
|
}
|
|
@@ -22901,173 +23064,6 @@ function isGenericWebsiteDomain(website) {
|
|
|
22901
23064
|
return isGenericDomain(normalizeDomain(website));
|
|
22902
23065
|
}
|
|
22903
23066
|
|
|
22904
|
-
// src/utils/color-analysis.ts
|
|
22905
|
-
var DESIGN_PALETTE = [
|
|
22906
|
-
{ name: "yellow", hex: "#FFC008", rgb: [255, 192, 8] },
|
|
22907
|
-
{ name: "black", hex: "#161616", rgb: [22, 22, 22] },
|
|
22908
|
-
{ name: "gray", hex: "#888888", rgb: [136, 136, 136] }
|
|
22909
|
-
];
|
|
22910
|
-
function hexToRgb2(hex) {
|
|
22911
|
-
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
22912
|
-
return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : [0, 0, 0];
|
|
22913
|
-
}
|
|
22914
|
-
function getLuminance(rgb) {
|
|
22915
|
-
const [r, g, b] = rgb.map((c) => {
|
|
22916
|
-
c = c / 255;
|
|
22917
|
-
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
22918
|
-
});
|
|
22919
|
-
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
22920
|
-
}
|
|
22921
|
-
function getContrastRatio(color1, color2) {
|
|
22922
|
-
const lum1 = getLuminance(color1);
|
|
22923
|
-
const lum2 = getLuminance(color2);
|
|
22924
|
-
const brightest = Math.max(lum1, lum2);
|
|
22925
|
-
const darkest = Math.min(lum1, lum2);
|
|
22926
|
-
return (brightest + 0.05) / (darkest + 0.05);
|
|
22927
|
-
}
|
|
22928
|
-
function pickReadableTextColor(bgHex) {
|
|
22929
|
-
const bg = hexToRgb2(bgHex);
|
|
22930
|
-
const darkContrast = getContrastRatio(bg, [26, 26, 26]);
|
|
22931
|
-
const lightContrast = getContrastRatio(bg, [250, 250, 250]);
|
|
22932
|
-
return darkContrast >= lightContrast ? "dark" : "light";
|
|
22933
|
-
}
|
|
22934
|
-
function extractDominantColor(canvas) {
|
|
22935
|
-
const ctx = canvas.getContext("2d");
|
|
22936
|
-
if (!ctx) return [128, 128, 128];
|
|
22937
|
-
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
22938
|
-
const data = imageData.data;
|
|
22939
|
-
const sampleSize = Math.max(1, Math.floor(data.length / (4 * 1e3)));
|
|
22940
|
-
const colorCounts = {};
|
|
22941
|
-
for (let i = 0; i < data.length; i += 4 * sampleSize) {
|
|
22942
|
-
const r = data[i];
|
|
22943
|
-
const g = data[i + 1];
|
|
22944
|
-
const b = data[i + 2];
|
|
22945
|
-
const alpha = data[i + 3];
|
|
22946
|
-
if (alpha < 128) continue;
|
|
22947
|
-
const bucketR = Math.round(r / 32) * 32;
|
|
22948
|
-
const bucketG = Math.round(g / 32) * 32;
|
|
22949
|
-
const bucketB = Math.round(b / 32) * 32;
|
|
22950
|
-
const key = `${bucketR},${bucketG},${bucketB}`;
|
|
22951
|
-
colorCounts[key] = (colorCounts[key] || 0) + 1;
|
|
22952
|
-
}
|
|
22953
|
-
let maxCount = 0;
|
|
22954
|
-
let dominantColor = [128, 128, 128];
|
|
22955
|
-
for (const [colorKey, count] of Object.entries(colorCounts)) {
|
|
22956
|
-
if (count > maxCount) {
|
|
22957
|
-
maxCount = count;
|
|
22958
|
-
const [r, g, b] = colorKey.split(",").map(Number);
|
|
22959
|
-
dominantColor = [r, g, b];
|
|
22960
|
-
}
|
|
22961
|
-
}
|
|
22962
|
-
return dominantColor;
|
|
22963
|
-
}
|
|
22964
|
-
function getBestContrastColor(imageColor) {
|
|
22965
|
-
let bestColor = DESIGN_PALETTE[0];
|
|
22966
|
-
let bestContrast = 0;
|
|
22967
|
-
for (const color of DESIGN_PALETTE) {
|
|
22968
|
-
const contrast = getContrastRatio(imageColor, color.rgb);
|
|
22969
|
-
if (contrast > bestContrast) {
|
|
22970
|
-
bestContrast = contrast;
|
|
22971
|
-
bestColor = color;
|
|
22972
|
-
}
|
|
22973
|
-
}
|
|
22974
|
-
return bestContrast >= 3 ? bestColor : DESIGN_PALETTE.find((c) => c.name === "black") || bestColor;
|
|
22975
|
-
}
|
|
22976
|
-
function analyzeImageColor(imageSrc) {
|
|
22977
|
-
return new Promise((resolve, reject) => {
|
|
22978
|
-
const img = new Image();
|
|
22979
|
-
img.crossOrigin = "anonymous";
|
|
22980
|
-
img.onload = () => {
|
|
22981
|
-
try {
|
|
22982
|
-
const canvas = document.createElement("canvas");
|
|
22983
|
-
const ctx = canvas.getContext("2d");
|
|
22984
|
-
if (!ctx) {
|
|
22985
|
-
reject(new Error("Could not get canvas context"));
|
|
22986
|
-
return;
|
|
22987
|
-
}
|
|
22988
|
-
const maxSize = 100;
|
|
22989
|
-
const scale = Math.min(maxSize / img.width, maxSize / img.height);
|
|
22990
|
-
canvas.width = img.width * scale;
|
|
22991
|
-
canvas.height = img.height * scale;
|
|
22992
|
-
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
22993
|
-
const dominantColor = extractDominantColor(canvas);
|
|
22994
|
-
const bestContrastColor = getBestContrastColor(dominantColor);
|
|
22995
|
-
resolve(bestContrastColor);
|
|
22996
|
-
} catch (error) {
|
|
22997
|
-
reject(error);
|
|
22998
|
-
}
|
|
22999
|
-
};
|
|
23000
|
-
img.onerror = () => reject(new Error("Failed to load image"));
|
|
23001
|
-
img.src = imageSrc;
|
|
23002
|
-
});
|
|
23003
|
-
}
|
|
23004
|
-
async function extractImageEdgeColorAsync(imageUrl) {
|
|
23005
|
-
return new Promise((resolve) => {
|
|
23006
|
-
if (typeof window === "undefined") {
|
|
23007
|
-
resolve("#000000");
|
|
23008
|
-
return;
|
|
23009
|
-
}
|
|
23010
|
-
const img = new Image();
|
|
23011
|
-
img.crossOrigin = "anonymous";
|
|
23012
|
-
img.onload = () => {
|
|
23013
|
-
try {
|
|
23014
|
-
const canvas = document.createElement("canvas");
|
|
23015
|
-
const ctx = canvas.getContext("2d");
|
|
23016
|
-
if (!ctx) {
|
|
23017
|
-
resolve("#000000");
|
|
23018
|
-
return;
|
|
23019
|
-
}
|
|
23020
|
-
const maxSize = 50;
|
|
23021
|
-
const scale = Math.min(maxSize / img.naturalWidth, maxSize / img.naturalHeight);
|
|
23022
|
-
const w = Math.round(img.naturalWidth * scale);
|
|
23023
|
-
const h = Math.round(img.naturalHeight * scale);
|
|
23024
|
-
canvas.width = w;
|
|
23025
|
-
canvas.height = h;
|
|
23026
|
-
ctx.drawImage(img, 0, 0, w, h);
|
|
23027
|
-
const data = ctx.getImageData(0, 0, w, h).data;
|
|
23028
|
-
const edgeW = Math.max(2, Math.round(w * 0.15));
|
|
23029
|
-
const edgeH = Math.max(2, Math.round(h * 0.15));
|
|
23030
|
-
const bucketSize = 32;
|
|
23031
|
-
const buckets = /* @__PURE__ */ new Map();
|
|
23032
|
-
for (let y = 0; y < h; y++) {
|
|
23033
|
-
for (let x = 0; x < w; x++) {
|
|
23034
|
-
if (!(x < edgeW || x >= w - edgeW || y < edgeH || y >= h - edgeH)) continue;
|
|
23035
|
-
const i = (y * w + x) * 4;
|
|
23036
|
-
if (data[i + 3] < 128) continue;
|
|
23037
|
-
const br = Math.floor(data[i] / bucketSize) * bucketSize;
|
|
23038
|
-
const bg = Math.floor(data[i + 1] / bucketSize) * bucketSize;
|
|
23039
|
-
const bb = Math.floor(data[i + 2] / bucketSize) * bucketSize;
|
|
23040
|
-
const key = `${br},${bg},${bb}`;
|
|
23041
|
-
const existing = buckets.get(key);
|
|
23042
|
-
if (existing) {
|
|
23043
|
-
existing.r += data[i];
|
|
23044
|
-
existing.g += data[i + 1];
|
|
23045
|
-
existing.b += data[i + 2];
|
|
23046
|
-
existing.count++;
|
|
23047
|
-
} else {
|
|
23048
|
-
buckets.set(key, { r: data[i], g: data[i + 1], b: data[i + 2], count: 1 });
|
|
23049
|
-
}
|
|
23050
|
-
}
|
|
23051
|
-
}
|
|
23052
|
-
let best = { r: 0, g: 0, b: 0, count: 0 };
|
|
23053
|
-
for (const b2 of buckets.values()) {
|
|
23054
|
-
if (b2.count > best.count) best = b2;
|
|
23055
|
-
}
|
|
23056
|
-
if (best.count === 0) {
|
|
23057
|
-
resolve("#000000");
|
|
23058
|
-
return;
|
|
23059
|
-
}
|
|
23060
|
-
const r = Math.round(best.r / best.count), g = Math.round(best.g / best.count), b = Math.round(best.b / best.count);
|
|
23061
|
-
resolve(`#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`);
|
|
23062
|
-
} catch {
|
|
23063
|
-
resolve("#000000");
|
|
23064
|
-
}
|
|
23065
|
-
};
|
|
23066
|
-
img.onerror = () => resolve("#000000");
|
|
23067
|
-
img.src = imageUrl;
|
|
23068
|
-
});
|
|
23069
|
-
}
|
|
23070
|
-
|
|
23071
23067
|
// src/utils/announcement-storage.ts
|
|
23072
23068
|
function announcementDismissCookieName(platform) {
|
|
23073
23069
|
return `${platform}-announcement-dismissed`;
|
|
@@ -23096,6 +23092,19 @@ function isAnnouncementDismissed(platform, id) {
|
|
|
23096
23092
|
return false;
|
|
23097
23093
|
}
|
|
23098
23094
|
}
|
|
23095
|
+
function clearAnnouncementDismissals(platform) {
|
|
23096
|
+
if (typeof document === "undefined") return;
|
|
23097
|
+
document.cookie = `${announcementDismissCookieName(platform)}=; path=/; max-age=0`;
|
|
23098
|
+
try {
|
|
23099
|
+
const prefix = `${platform}-announcement-`;
|
|
23100
|
+
Object.keys(localStorage).forEach((key) => {
|
|
23101
|
+
if (key.startsWith(prefix) && key.endsWith("-dismissed")) {
|
|
23102
|
+
localStorage.removeItem(key);
|
|
23103
|
+
}
|
|
23104
|
+
});
|
|
23105
|
+
} catch {
|
|
23106
|
+
}
|
|
23107
|
+
}
|
|
23099
23108
|
function clearLegacyAnnouncementCache(platform) {
|
|
23100
23109
|
if (typeof window === "undefined") return;
|
|
23101
23110
|
try {
|
|
@@ -41858,7 +41867,7 @@ function ChannelInput({
|
|
|
41858
41867
|
);
|
|
41859
41868
|
}
|
|
41860
41869
|
function RgbInputs({ value, onChange }) {
|
|
41861
|
-
const rgb =
|
|
41870
|
+
const rgb = hexToRgb2(value) ?? { r: 0, g: 0, b: 0 };
|
|
41862
41871
|
const update = (next) => {
|
|
41863
41872
|
const r = next.r ?? rgb.r;
|
|
41864
41873
|
const g = next.g ?? rgb.g;
|
|
@@ -41872,7 +41881,7 @@ function RgbInputs({ value, onChange }) {
|
|
|
41872
41881
|
] });
|
|
41873
41882
|
}
|
|
41874
41883
|
function HslInputs({ value, onChange }) {
|
|
41875
|
-
const rgb =
|
|
41884
|
+
const rgb = hexToRgb2(value) ?? { r: 0, g: 0, b: 0 };
|
|
41876
41885
|
const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
|
|
41877
41886
|
const update = (next) => {
|
|
41878
41887
|
const h = next.h ?? hsl.h;
|
|
@@ -52466,11 +52475,18 @@ export {
|
|
|
52466
52475
|
ActionsMenu,
|
|
52467
52476
|
ActionsMenuDropdown,
|
|
52468
52477
|
ColorSwatch,
|
|
52478
|
+
DESIGN_PALETTE,
|
|
52479
|
+
getContrastRatio,
|
|
52480
|
+
pickReadableTextColor,
|
|
52481
|
+
extractDominantColor,
|
|
52482
|
+
getBestContrastColor,
|
|
52483
|
+
analyzeImageColor,
|
|
52484
|
+
extractImageEdgeColorAsync,
|
|
52469
52485
|
getPlatformAccentColor,
|
|
52470
52486
|
getCurrentPlatform,
|
|
52471
52487
|
getReadableTextColor,
|
|
52472
52488
|
HEX_PATTERN,
|
|
52473
|
-
hexToRgb,
|
|
52489
|
+
hexToRgb2 as hexToRgb,
|
|
52474
52490
|
rgbToHex,
|
|
52475
52491
|
deriveHoverColor,
|
|
52476
52492
|
deriveActiveColor,
|
|
@@ -53033,18 +53049,11 @@ export {
|
|
|
53033
53049
|
isGenericDomain,
|
|
53034
53050
|
hasGenericEmailDomain,
|
|
53035
53051
|
isGenericWebsiteDomain,
|
|
53036
|
-
DESIGN_PALETTE,
|
|
53037
|
-
getLuminance,
|
|
53038
|
-
getContrastRatio,
|
|
53039
|
-
pickReadableTextColor,
|
|
53040
|
-
extractDominantColor,
|
|
53041
|
-
getBestContrastColor,
|
|
53042
|
-
analyzeImageColor,
|
|
53043
|
-
extractImageEdgeColorAsync,
|
|
53044
53052
|
announcementDismissCookieName,
|
|
53045
53053
|
isDismissedCookieValue,
|
|
53046
53054
|
dismissAnnouncement,
|
|
53047
53055
|
isAnnouncementDismissed,
|
|
53056
|
+
clearAnnouncementDismissals,
|
|
53048
53057
|
clearLegacyAnnouncementCache,
|
|
53049
53058
|
readLeadingDecisionFrame,
|
|
53050
53059
|
ANNOUNCEMENT_CTA_DEFAULTS,
|
|
@@ -53360,4 +53369,4 @@ export {
|
|
|
53360
53369
|
LogsList,
|
|
53361
53370
|
assets
|
|
53362
53371
|
};
|
|
53363
|
-
//# sourceMappingURL=chunk-
|
|
53372
|
+
//# sourceMappingURL=chunk-CVYSW33D.js.map
|