@flamingo-stack/openframe-frontend-core 0.0.533 → 0.0.534-snapshot.20260812085314
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-2MYDGLJS.cjs → chunk-2P4J2YLI.cjs} +98 -98
- package/dist/{chunk-2MYDGLJS.cjs.map → chunk-2P4J2YLI.cjs.map} +1 -1
- package/dist/{chunk-GS4HJA2G.js → chunk-4A736Z6S.js} +74 -20
- package/dist/chunk-4A736Z6S.js.map +1 -0
- package/dist/{chunk-LIUARTOZ.js → chunk-4DTUUM5V.js} +150 -309
- package/dist/chunk-4DTUUM5V.js.map +1 -0
- package/dist/{chunk-RKITTO5V.cjs → chunk-4HQFV4PK.cjs} +14 -14
- package/dist/{chunk-RKITTO5V.cjs.map → chunk-4HQFV4PK.cjs.map} +1 -1
- package/dist/{chunk-GYONSC3U.cjs → chunk-4QYUNDS3.cjs} +3 -3
- package/dist/{chunk-GYONSC3U.cjs.map → chunk-4QYUNDS3.cjs.map} +1 -1
- package/dist/{chunk-GNOK5J34.cjs → chunk-5OLF6WXF.cjs} +40 -40
- package/dist/{chunk-GNOK5J34.cjs.map → chunk-5OLF6WXF.cjs.map} +1 -1
- package/dist/{chunk-SXLEPNY2.cjs → chunk-5RJUHUCI.cjs} +106 -52
- package/dist/chunk-5RJUHUCI.cjs.map +1 -0
- package/dist/{chunk-OLOKQQAP.cjs → chunk-7MHYRBBQ.cjs} +5 -5
- package/dist/{chunk-OLOKQQAP.cjs.map → chunk-7MHYRBBQ.cjs.map} +1 -1
- package/dist/{chunk-UPHN2VRZ.cjs → chunk-E3YB55RR.cjs} +954 -1113
- package/dist/chunk-E3YB55RR.cjs.map +1 -0
- package/dist/{chunk-5U67WTAS.js → chunk-EHPQKXXW.js} +3 -3
- package/dist/{chunk-JDW2IL7A.cjs → chunk-GV4FDDFV.cjs} +18 -18
- package/dist/{chunk-JDW2IL7A.cjs.map → chunk-GV4FDDFV.cjs.map} +1 -1
- package/dist/{chunk-6W3ULZ4X.js → chunk-JVO5CYMK.js} +8 -8
- package/dist/{chunk-4QKXNWH5.js → chunk-K6566PEB.js} +3 -3
- package/dist/{chunk-YLB6XXO6.js → chunk-KLFGP6PR.js} +2 -2
- package/dist/{chunk-6YXN5RHW.js → chunk-LIQJAC6Z.js} +2 -2
- package/dist/{chunk-46FKXLNE.js → chunk-LIX5OUHH.js} +2 -2
- package/dist/{chunk-RCBRCZUF.js → chunk-LQPHB2YF.js} +2 -2
- package/dist/{chunk-2XGHEJZK.js → chunk-MZVFZMQ6.js} +6 -6
- package/dist/{chunk-6SMLYZLH.js → chunk-N3AEJTCK.js} +5 -5
- package/dist/{chunk-LE3BJ5H2.js → chunk-NB6BP6JB.js} +3 -3
- package/dist/{chunk-QZ2NAPLF.cjs → chunk-P65EZEBW.cjs} +12 -12
- package/dist/{chunk-QZ2NAPLF.cjs.map → chunk-P65EZEBW.cjs.map} +1 -1
- package/dist/{chunk-MVGL5NNJ.js → chunk-PLGITXT7.js} +2 -2
- package/dist/{chunk-KMB66NYX.cjs → chunk-PSBL3S2B.cjs} +7 -7
- package/dist/{chunk-KMB66NYX.cjs.map → chunk-PSBL3S2B.cjs.map} +1 -1
- package/dist/{chunk-U555TMPC.js → chunk-QUVIT4JP.js} +6 -6
- package/dist/{chunk-4ZRHVOEB.cjs → chunk-RO67OOKJ.cjs} +40 -40
- package/dist/{chunk-4ZRHVOEB.cjs.map → chunk-RO67OOKJ.cjs.map} +1 -1
- package/dist/{chunk-NAV4FRNL.cjs → chunk-TS2EHMEX.cjs} +29 -29
- package/dist/{chunk-NAV4FRNL.cjs.map → chunk-TS2EHMEX.cjs.map} +1 -1
- package/dist/{chunk-Z3NOI7X7.cjs → chunk-U2Q7GEX2.cjs} +32 -32
- package/dist/{chunk-Z3NOI7X7.cjs.map → chunk-U2Q7GEX2.cjs.map} +1 -1
- package/dist/{chunk-XN4JKIJY.js → chunk-VPDTDKO5.js} +2 -2
- package/dist/{chunk-ENPGPZIB.cjs → chunk-Y55XQFJK.cjs} +75 -75
- package/dist/{chunk-ENPGPZIB.cjs.map → chunk-Y55XQFJK.cjs.map} +1 -1
- package/dist/{chunk-2TUOBFPK.js → chunk-Y72MXG5N.js} +4 -4
- package/dist/{chunk-DFQLUK75.cjs → chunk-ZKKEKG73.cjs} +3 -3
- package/dist/{chunk-DFQLUK75.cjs.map → chunk-ZKKEKG73.cjs.map} +1 -1
- package/dist/{chunk-J4BE4FIR.cjs → chunk-ZR5CJTNR.cjs} +4 -4
- package/dist/{chunk-J4BE4FIR.cjs.map → chunk-ZR5CJTNR.cjs.map} +1 -1
- package/dist/components/case-studies/index.cjs +9 -9
- package/dist/components/case-studies/index.js +3 -3
- package/dist/components/chat/chat-input.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +3 -3
- package/dist/components/chat/index.js +2 -2
- package/dist/components/contact/index.cjs +4 -4
- package/dist/components/contact/index.js +3 -3
- package/dist/components/docs/index.cjs +6 -6
- package/dist/components/docs/index.js +5 -5
- package/dist/components/embeds/index.cjs +4 -4
- package/dist/components/embeds/index.js +3 -3
- package/dist/components/faq/index.cjs +5 -5
- package/dist/components/faq/index.js +4 -4
- package/dist/components/features/index.cjs +3 -3
- package/dist/components/features/index.js +2 -2
- package/dist/components/help-center-pages/index.cjs +24 -24
- package/dist/components/help-center-pages/index.js +15 -15
- package/dist/components/index.cjs +138 -138
- package/dist/components/index.js +13 -13
- package/dist/components/meeting-scheduler/index.cjs +40 -40
- package/dist/components/meeting-scheduler/index.js +4 -4
- package/dist/components/navigation/index.cjs +3 -3
- package/dist/components/navigation/index.js +2 -2
- package/dist/components/onboarding-guides/index.cjs +7 -7
- package/dist/components/onboarding-guides/index.js +6 -6
- package/dist/components/popover.d.ts.map +1 -1
- package/dist/components/related-content/index.cjs +5 -5
- package/dist/components/related-content/index.js +4 -4
- package/dist/components/tickets/index.cjs +7 -7
- package/dist/components/tickets/index.js +6 -6
- package/dist/components/ui/autocomplete.d.ts.map +1 -1
- package/dist/components/ui/file-upload.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +3 -3
- package/dist/components/ui/index.js +2 -2
- package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +1 -1
- package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +1 -1
- package/dist/components/ui/search-input.d.ts.map +1 -1
- package/dist/components/ui/searchable-select.d.ts.map +1 -1
- package/dist/components/ui/tag-select-dropdown.d.ts.map +1 -1
- package/dist/components/ui/tags-manager.d.ts.map +1 -1
- package/dist/hooks/index.cjs +4 -2
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.js +3 -1
- package/dist/hooks/ui/index.d.ts +1 -0
- package/dist/hooks/ui/index.d.ts.map +1 -1
- package/dist/hooks/ui/use-keyboard-collision-padding.d.ts +2 -0
- package/dist/hooks/ui/use-keyboard-collision-padding.d.ts.map +1 -0
- package/dist/index.cjs +5 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -2
- package/dist/utils/social-embed-cache.d.ts +16 -16
- package/dist/utils/social-embed-cache.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/chat-input.tsx +84 -32
- package/src/components/popover.tsx +22 -14
- package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +1 -5
- package/src/components/ui/autocomplete.tsx +9 -2
- package/src/components/ui/file-upload.tsx +5 -1
- package/src/components/ui/markdown/rich/__tests__/shortcodes.test.ts +58 -0
- package/src/components/ui/markdown/rich/embed-overrides.tsx +13 -7
- package/src/components/ui/markdown/rich/shortcodes.ts +15 -0
- package/src/components/ui/search-input.tsx +9 -2
- package/src/components/ui/searchable-select.tsx +9 -2
- package/src/components/ui/tag-select-dropdown.tsx +8 -2
- package/src/components/ui/tags-manager.tsx +9 -2
- package/src/hooks/ui/index.ts +1 -0
- package/src/hooks/ui/use-keyboard-collision-padding.ts +101 -0
- package/src/utils/social-embed-cache.ts +63 -336
- package/dist/chunk-GS4HJA2G.js.map +0 -1
- package/dist/chunk-LIUARTOZ.js.map +0 -1
- package/dist/chunk-SXLEPNY2.cjs.map +0 -1
- package/dist/chunk-UPHN2VRZ.cjs.map +0 -1
- /package/dist/{chunk-5U67WTAS.js.map → chunk-EHPQKXXW.js.map} +0 -0
- /package/dist/{chunk-6W3ULZ4X.js.map → chunk-JVO5CYMK.js.map} +0 -0
- /package/dist/{chunk-4QKXNWH5.js.map → chunk-K6566PEB.js.map} +0 -0
- /package/dist/{chunk-YLB6XXO6.js.map → chunk-KLFGP6PR.js.map} +0 -0
- /package/dist/{chunk-6YXN5RHW.js.map → chunk-LIQJAC6Z.js.map} +0 -0
- /package/dist/{chunk-46FKXLNE.js.map → chunk-LIX5OUHH.js.map} +0 -0
- /package/dist/{chunk-RCBRCZUF.js.map → chunk-LQPHB2YF.js.map} +0 -0
- /package/dist/{chunk-2XGHEJZK.js.map → chunk-MZVFZMQ6.js.map} +0 -0
- /package/dist/{chunk-6SMLYZLH.js.map → chunk-N3AEJTCK.js.map} +0 -0
- /package/dist/{chunk-LE3BJ5H2.js.map → chunk-NB6BP6JB.js.map} +0 -0
- /package/dist/{chunk-MVGL5NNJ.js.map → chunk-PLGITXT7.js.map} +0 -0
- /package/dist/{chunk-U555TMPC.js.map → chunk-QUVIT4JP.js.map} +0 -0
- /package/dist/{chunk-XN4JKIJY.js.map → chunk-VPDTDKO5.js.map} +0 -0
- /package/dist/{chunk-2TUOBFPK.js.map → chunk-Y72MXG5N.js.map} +0 -0
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
useImageEdgeColor,
|
|
40
40
|
useIsTruncated,
|
|
41
41
|
useIsomorphicLayoutEffect,
|
|
42
|
+
useKeyboardCollisionPadding,
|
|
42
43
|
useLgUp,
|
|
43
44
|
useLocalStorage,
|
|
44
45
|
useMarqueeEngine,
|
|
@@ -51,7 +52,7 @@ import {
|
|
|
51
52
|
useResetOnPageHidden,
|
|
52
53
|
useSuppressCloneFocus,
|
|
53
54
|
useToast
|
|
54
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-4A736Z6S.js";
|
|
55
56
|
import {
|
|
56
57
|
init_next_navigation,
|
|
57
58
|
usePathname,
|
|
@@ -6530,6 +6531,7 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6530
6531
|
// contenteditable div, not a <textarea>, so spreading them would warn.
|
|
6531
6532
|
} = rest;
|
|
6532
6533
|
const [value, setValue] = useState10("");
|
|
6534
|
+
const [hasChips, setHasChips] = useState10(false);
|
|
6533
6535
|
const [focused, setFocused] = useState10(false);
|
|
6534
6536
|
const [isStopping, setIsStopping] = useState10(false);
|
|
6535
6537
|
const [previewDismissed, setPreviewDismissed] = useState10(false);
|
|
@@ -6565,26 +6567,32 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6565
6567
|
if (typeof caret === "number") placeCaretAtOffset(el, caret);
|
|
6566
6568
|
else placeCaretAtEnd(el);
|
|
6567
6569
|
}
|
|
6570
|
+
setHasChips(el.querySelector("[data-token]") !== null);
|
|
6568
6571
|
}
|
|
6572
|
+
valueRef.current = next;
|
|
6569
6573
|
setValue(next);
|
|
6570
6574
|
}, []);
|
|
6571
6575
|
const fire = useCallback3(
|
|
6572
6576
|
(message2) => {
|
|
6573
6577
|
const can = (message2.length > 0 || allowEmptySend) && !sending && !disabled;
|
|
6574
6578
|
if (!can || !onSend) return;
|
|
6575
|
-
const
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6579
|
+
const sentMeta = metaRef.current;
|
|
6580
|
+
metaRef.current = /* @__PURE__ */ new Map();
|
|
6581
|
+
applyValue("");
|
|
6582
|
+
shouldRefocusRef.current = true;
|
|
6583
|
+
focusEditor();
|
|
6584
|
+
const restore = () => {
|
|
6585
|
+
if (valueRef.current.length > 0) return;
|
|
6586
|
+
metaRef.current = sentMeta;
|
|
6587
|
+
applyValue(message2);
|
|
6581
6588
|
};
|
|
6589
|
+
const result = onSend(message2);
|
|
6582
6590
|
if (result instanceof Promise) {
|
|
6583
6591
|
void result.then((ok) => {
|
|
6584
|
-
if (ok
|
|
6592
|
+
if (ok === false) restore();
|
|
6585
6593
|
});
|
|
6586
|
-
} else if (result
|
|
6587
|
-
|
|
6594
|
+
} else if (result === false) {
|
|
6595
|
+
restore();
|
|
6588
6596
|
}
|
|
6589
6597
|
},
|
|
6590
6598
|
[allowEmptySend, sending, disabled, onSend, focusEditor, applyValue]
|
|
@@ -6673,6 +6681,7 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6673
6681
|
const syncFromDom = useCallback3(() => {
|
|
6674
6682
|
const el = editorRef.current;
|
|
6675
6683
|
if (!el) return;
|
|
6684
|
+
setHasChips(el.querySelector("[data-token]") !== null);
|
|
6676
6685
|
setValue(serialize(el));
|
|
6677
6686
|
}, []);
|
|
6678
6687
|
const handleInput = useCallback3(() => {
|
|
@@ -6778,8 +6787,7 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6778
6787
|
const hasContent2 = value.trim().length > 0 || allowEmptySend;
|
|
6779
6788
|
const sendDisabled = sending || disabled || !hasContent2;
|
|
6780
6789
|
const isEmpty = value.length === 0;
|
|
6781
|
-
const
|
|
6782
|
-
const showPreview = !isDisabled && !!previewText && !previewDismissed;
|
|
6790
|
+
const showPreview = !sending && !disabled && !!previewText && !previewDismissed;
|
|
6783
6791
|
return /* @__PURE__ */ jsx30(
|
|
6784
6792
|
"div",
|
|
6785
6793
|
{
|
|
@@ -6813,23 +6821,24 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6813
6821
|
},
|
|
6814
6822
|
className: cn(
|
|
6815
6823
|
// `items-center` keeps the empty single-line text AND a mention chip
|
|
6816
|
-
// vertically centered the same way. `py-1.5`
|
|
6817
|
-
// editor's `leading-9` (36px) →
|
|
6818
|
-
//
|
|
6819
|
-
// (incl. its ~3.5px vertical-align overhead), so there's almost
|
|
6820
|
-
// slack for the chip to drift in → it reads as centered
|
|
6821
|
-
//
|
|
6824
|
+
// vertically centered the same way. With a chip in the box, `py-1.5`
|
|
6825
|
+
// (6px) pairs with the editor's `leading-9` (36px) → that row is
|
|
6826
|
+
// 36 + 2*6 = 48px. The 36px line box is just barely above the 32px
|
|
6827
|
+
// chip (incl. its ~3.5px vertical-align overhead), so there's almost
|
|
6828
|
+
// no slack for the chip to drift in → it reads as centered.
|
|
6829
|
+
// A chipless row is shorter than its content box and the `min-h-*`
|
|
6830
|
+
// here is what sets its height: 48px from `md` up, 44px below.
|
|
6822
6831
|
"flex w-full items-center gap-2 px-3 py-1.5 min-h-11 md:min-h-12 cursor-text group transition-colors duration-200",
|
|
6823
6832
|
!hideBorder && "rounded-[6px] border bg-ods-card border-ods-border",
|
|
6824
|
-
!hideBorder && (focused ? "border-ods-accent" : !
|
|
6825
|
-
!hideBorder &&
|
|
6833
|
+
!hideBorder && (focused ? "border-ods-accent" : !disabled && "hover:bg-ods-bg-hover hover:border-ods-border-hover"),
|
|
6834
|
+
!hideBorder && disabled && "!cursor-not-allowed bg-ods-bg",
|
|
6826
6835
|
hideBorder && "bg-transparent"
|
|
6827
6836
|
),
|
|
6828
6837
|
children: [
|
|
6829
6838
|
startIcon && /* @__PURE__ */ jsx30("span", { className: "flex h-6 shrink-0 items-center", children: startIcon }),
|
|
6830
6839
|
/* @__PURE__ */ jsxs23("div", { className: "relative flex-1 min-w-0", children: [
|
|
6831
|
-
isEmpty && !showPreview && /* @__PURE__ */ jsx30("span", { className: "pointer-events-none absolute left-0 top-0 select-none text-h4
|
|
6832
|
-
showPreview && /* @__PURE__ */ jsx30("p", { className: "pointer-events-none absolute inset-x-0 top-0 m-0 select-none truncate text-h4
|
|
6840
|
+
isEmpty && !showPreview && /* @__PURE__ */ jsx30("span", { className: "pointer-events-none absolute left-0 top-0 select-none text-h4 text-ods-text-secondary", children: disabled ? "Connection lost. Waiting to reconnect..." : placeholder }),
|
|
6841
|
+
showPreview && /* @__PURE__ */ jsx30("p", { className: cn("pointer-events-none absolute inset-x-0 top-0 m-0 select-none truncate text-h4 text-ods-text-secondary", hasChips && "!leading-9"), children: previewText }),
|
|
6833
6842
|
/* @__PURE__ */ jsx30(
|
|
6834
6843
|
"div",
|
|
6835
6844
|
{
|
|
@@ -6838,7 +6847,7 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6838
6847
|
role: "textbox",
|
|
6839
6848
|
"aria-multiline": "true",
|
|
6840
6849
|
"aria-label": typeof placeholder === "string" ? placeholder : "Message",
|
|
6841
|
-
contentEditable: !
|
|
6850
|
+
contentEditable: !disabled,
|
|
6842
6851
|
suppressContentEditableWarning: true,
|
|
6843
6852
|
spellCheck: true,
|
|
6844
6853
|
onInput: handleInput,
|
|
@@ -6861,17 +6870,25 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6861
6870
|
// see the preview comment above) and is only made transparent;
|
|
6862
6871
|
// the absolutely-positioned single-line preview paints over it.
|
|
6863
6872
|
showPreview && "opacity-0",
|
|
6864
|
-
// `leading-9` (36px) sits just above the 32px chip's
|
|
6865
|
-
// (~35.5px incl. vertical-align overhead): the LINE
|
|
6866
|
-
// height (deterministic 48px, no overflow) AND the
|
|
6867
|
-
// keeps the chip centered
|
|
6868
|
-
// `
|
|
6869
|
-
//
|
|
6870
|
-
//
|
|
6871
|
-
//
|
|
6872
|
-
|
|
6873
|
+
// WITH chips, `leading-9` (36px) sits just above the 32px chip's
|
|
6874
|
+
// line-box need (~35.5px incl. vertical-align overhead): the LINE
|
|
6875
|
+
// drives row height (deterministic 48px, no overflow) AND the
|
|
6876
|
+
// near-zero slack keeps the chip centered against the `align-top`
|
|
6877
|
+
// `h-9` wrapper `buildChipEl` gives it. ~4px gap between wrapped
|
|
6878
|
+
// chip rows.
|
|
6879
|
+
// WITHOUT chips there is nothing tall to center, and forcing the
|
|
6880
|
+
// same 36px box on 14px phone text (`text-h4`) put a blank line's
|
|
6881
|
+
// worth of air between every wrapped row — so plain drafts keep
|
|
6882
|
+
// `text-h4`'s own responsive line-height (20px / 24px at md).
|
|
6883
|
+
// `min-h-*` pins the single-line box even when EMPTY: a
|
|
6884
|
+
// non-editable (`contentEditable=false`, i.e. `disabled`) empty div
|
|
6885
|
+
// would otherwise collapse to 0px, and `items-center` would
|
|
6886
|
+
// re-center the shorter wrapper in the row — dropping the `top-0`
|
|
6887
|
+
// placeholder down.
|
|
6888
|
+
"text-h4 text-ods-text-primary",
|
|
6889
|
+
hasChips ? "min-h-9 !leading-9" : "min-h-[var(--font-line-space-h4-body)]",
|
|
6873
6890
|
"scrollbar-thin scrollbar-track-transparent scrollbar-thumb-ods-border/30 hover:scrollbar-thumb-ods-text-secondary/30",
|
|
6874
|
-
|
|
6891
|
+
disabled && "cursor-not-allowed"
|
|
6875
6892
|
)
|
|
6876
6893
|
}
|
|
6877
6894
|
)
|
|
@@ -17422,6 +17439,7 @@ function AutocompleteInner(props, ref) {
|
|
|
17422
17439
|
};
|
|
17423
17440
|
const [isOpen, setIsOpen] = useState34(false);
|
|
17424
17441
|
const [highlightedIndex, setHighlightedIndex] = useState34(-1);
|
|
17442
|
+
const keyboardPadding = useKeyboardCollisionPadding();
|
|
17425
17443
|
const containerRef = useRef24(null);
|
|
17426
17444
|
const hiddenTagsPopupRef = useRef24(null);
|
|
17427
17445
|
const isInvalid = invalid || !!error;
|
|
@@ -17728,12 +17746,14 @@ function AutocompleteInner(props, ref) {
|
|
|
17728
17746
|
className: cn(
|
|
17729
17747
|
"z-50 w-[var(--radix-popover-trigger-width)] mt-1",
|
|
17730
17748
|
"bg-ods-card border border-ods-border rounded-[4px]",
|
|
17749
|
+
"flex flex-col overflow-hidden max-h-[var(--radix-popper-available-height)]",
|
|
17731
17750
|
"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
17732
17751
|
"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2",
|
|
17733
17752
|
dropdownClassName
|
|
17734
17753
|
),
|
|
17735
17754
|
sideOffset: 4,
|
|
17736
17755
|
align: "start",
|
|
17756
|
+
collisionPadding: { bottom: keyboardPadding },
|
|
17737
17757
|
onOpenAutoFocus: (e) => {
|
|
17738
17758
|
e.preventDefault();
|
|
17739
17759
|
autoLimitTags.inputRef.current?.focus();
|
|
@@ -17743,8 +17763,8 @@ function AutocompleteInner(props, ref) {
|
|
|
17743
17763
|
e.preventDefault();
|
|
17744
17764
|
}
|
|
17745
17765
|
},
|
|
17746
|
-
children: /* @__PURE__ */ jsxs84(ScrollAreaPrimitive.Root, { className: "overflow-hidden", children: [
|
|
17747
|
-
/* @__PURE__ */ jsx110(ScrollAreaPrimitive.Viewport, { className: "max-h-[240px] w-full [&>div]:!block", children: /* @__PURE__ */ jsx110("div", { role: "listbox", children: loading ? /* @__PURE__ */ jsx110("div", { className: "px-3 py-2 text-ods-text-secondary text-h6", children: loadingText }) : filteredOptions.length === 0 ? showCreateOption ? isCreateTooLong ? /* @__PURE__ */ jsxs84("div", { className: "flex items-center h-11 md:h-12 px-[var(--spacing-system-mf)] text-h5 text-ods-error min-w-0", children: [
|
|
17766
|
+
children: /* @__PURE__ */ jsxs84(ScrollAreaPrimitive.Root, { className: "flex min-h-0 flex-col overflow-hidden", children: [
|
|
17767
|
+
/* @__PURE__ */ jsx110(ScrollAreaPrimitive.Viewport, { className: "min-h-0 max-h-[240px] w-full [&>div]:!block", children: /* @__PURE__ */ jsx110("div", { role: "listbox", children: loading ? /* @__PURE__ */ jsx110("div", { className: "px-3 py-2 text-ods-text-secondary text-h6", children: loadingText }) : filteredOptions.length === 0 ? showCreateOption ? isCreateTooLong ? /* @__PURE__ */ jsxs84("div", { className: "flex items-center h-11 md:h-12 px-[var(--spacing-system-mf)] text-h5 text-ods-error min-w-0", children: [
|
|
17748
17768
|
"Maximum ",
|
|
17749
17769
|
maxCreateLength,
|
|
17750
17770
|
" characters"
|
|
@@ -19632,6 +19652,7 @@ function SearchableSelect({
|
|
|
19632
19652
|
}) {
|
|
19633
19653
|
const [isOpen, setIsOpen] = React54.useState(false);
|
|
19634
19654
|
const [search, setSearch] = React54.useState("");
|
|
19655
|
+
const keyboardPadding = useKeyboardCollisionPadding();
|
|
19635
19656
|
React54.useEffect(() => {
|
|
19636
19657
|
if (!isOpen) setSearch("");
|
|
19637
19658
|
}, [isOpen]);
|
|
@@ -19683,8 +19704,10 @@ function SearchableSelect({
|
|
|
19683
19704
|
{
|
|
19684
19705
|
align,
|
|
19685
19706
|
sideOffset: 6,
|
|
19707
|
+
collisionPadding: { bottom: keyboardPadding },
|
|
19686
19708
|
className: cn(
|
|
19687
19709
|
"z-50 min-w-[var(--radix-popover-trigger-width)] bg-ods-card border border-ods-border rounded-md shadow-lg overflow-hidden",
|
|
19710
|
+
"flex flex-col max-h-[var(--radix-popper-available-height)]",
|
|
19688
19711
|
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
19689
19712
|
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
19690
19713
|
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
@@ -19692,7 +19715,7 @@ function SearchableSelect({
|
|
|
19692
19715
|
contentClassName
|
|
19693
19716
|
),
|
|
19694
19717
|
children: [
|
|
19695
|
-
/* @__PURE__ */ jsx124("div", { className: "border-b border-ods-border", children: /* @__PURE__ */ jsx124(
|
|
19718
|
+
/* @__PURE__ */ jsx124("div", { className: "shrink-0 border-b border-ods-border", children: /* @__PURE__ */ jsx124(
|
|
19696
19719
|
Input,
|
|
19697
19720
|
{
|
|
19698
19721
|
autoFocus: true,
|
|
@@ -19703,7 +19726,7 @@ function SearchableSelect({
|
|
|
19703
19726
|
className: "rounded-none border-0"
|
|
19704
19727
|
}
|
|
19705
19728
|
) }),
|
|
19706
|
-
/* @__PURE__ */ jsx124("div", { className: "max-h-80 overflow-y-auto py-[var(--spacing-system-xs)]", role: "listbox", children: isLoading ? /* @__PURE__ */ jsx124("div", { className: "px-[var(--spacing-system-sf)] py-[var(--spacing-system-s)] text-h5 text-ods-text-secondary", children: loadingText }) : filtered.length === 0 ? /* @__PURE__ */ jsx124("div", { className: "px-[var(--spacing-system-sf)] py-[var(--spacing-system-s)] text-h5 text-ods-text-secondary", children: emptyText }) : filtered.map((opt) => {
|
|
19729
|
+
/* @__PURE__ */ jsx124("div", { className: "min-h-0 max-h-80 overflow-y-auto py-[var(--spacing-system-xs)]", role: "listbox", children: isLoading ? /* @__PURE__ */ jsx124("div", { className: "px-[var(--spacing-system-sf)] py-[var(--spacing-system-s)] text-h5 text-ods-text-secondary", children: loadingText }) : filtered.length === 0 ? /* @__PURE__ */ jsx124("div", { className: "px-[var(--spacing-system-sf)] py-[var(--spacing-system-s)] text-h5 text-ods-text-secondary", children: emptyText }) : filtered.map((opt) => {
|
|
19707
19730
|
const isSelected = value === opt.value;
|
|
19708
19731
|
return /* @__PURE__ */ jsx124(
|
|
19709
19732
|
"button",
|
|
@@ -20530,6 +20553,7 @@ function TagSelectDropdown({
|
|
|
20530
20553
|
}) {
|
|
20531
20554
|
const [isOpen, setIsOpen] = React63.useState(false);
|
|
20532
20555
|
const [search, setSearch] = React63.useState("");
|
|
20556
|
+
const keyboardPadding = useKeyboardCollisionPadding();
|
|
20533
20557
|
React63.useEffect(() => {
|
|
20534
20558
|
if (!isOpen) setSearch("");
|
|
20535
20559
|
}, [isOpen]);
|
|
@@ -20573,15 +20597,17 @@ function TagSelectDropdown({
|
|
|
20573
20597
|
{
|
|
20574
20598
|
align,
|
|
20575
20599
|
sideOffset: 6,
|
|
20600
|
+
collisionPadding: { bottom: keyboardPadding },
|
|
20576
20601
|
className: cn(
|
|
20577
20602
|
"z-50 w-72 bg-ods-card border border-ods-border rounded-[6px] shadow-lg overflow-hidden",
|
|
20603
|
+
"flex flex-col max-h-[var(--radix-popper-available-height)]",
|
|
20578
20604
|
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
20579
20605
|
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
20580
20606
|
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
20581
20607
|
"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2"
|
|
20582
20608
|
),
|
|
20583
20609
|
children: [
|
|
20584
|
-
/* @__PURE__ */ jsx135("div", { className: "border-b border-ods-border", children: /* @__PURE__ */ jsx135(
|
|
20610
|
+
/* @__PURE__ */ jsx135("div", { className: "shrink-0 border-b border-ods-border", children: /* @__PURE__ */ jsx135(
|
|
20585
20611
|
Input,
|
|
20586
20612
|
{
|
|
20587
20613
|
autoFocus: true,
|
|
@@ -20598,7 +20624,7 @@ function TagSelectDropdown({
|
|
|
20598
20624
|
className: "rounded-none border-0"
|
|
20599
20625
|
}
|
|
20600
20626
|
) }),
|
|
20601
|
-
/* @__PURE__ */ jsxs105("div", { className: "max-h-72 overflow-y-auto py-[var(--spacing-system-xs)]", role: "listbox", children: [
|
|
20627
|
+
/* @__PURE__ */ jsxs105("div", { className: "min-h-0 max-h-72 overflow-y-auto py-[var(--spacing-system-xs)]", role: "listbox", children: [
|
|
20602
20628
|
ordered.map((opt) => {
|
|
20603
20629
|
const isSelected = selectedIds.includes(opt.id);
|
|
20604
20630
|
return /* @__PURE__ */ jsxs105(
|
|
@@ -20839,6 +20865,7 @@ function TagsManager({
|
|
|
20839
20865
|
}) {
|
|
20840
20866
|
const [open, setOpen] = React65.useState(false);
|
|
20841
20867
|
const [search, setSearch] = React65.useState("");
|
|
20868
|
+
const keyboardPadding = useKeyboardCollisionPadding();
|
|
20842
20869
|
const [editingId, setEditingId] = React65.useState(null);
|
|
20843
20870
|
const [editingName, setEditingName] = React65.useState("");
|
|
20844
20871
|
const editInputRef = React65.useRef(null);
|
|
@@ -20989,6 +21016,7 @@ function TagsManager({
|
|
|
20989
21016
|
className: cn(
|
|
20990
21017
|
"z-50 w-[var(--radix-popover-trigger-width)] mt-1",
|
|
20991
21018
|
"bg-ods-card border border-ods-border rounded",
|
|
21019
|
+
"flex flex-col overflow-hidden max-h-[var(--radix-popper-available-height)]",
|
|
20992
21020
|
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
20993
21021
|
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
20994
21022
|
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
@@ -20996,6 +21024,7 @@ function TagsManager({
|
|
|
20996
21024
|
),
|
|
20997
21025
|
sideOffset: 4,
|
|
20998
21026
|
align: "start",
|
|
21027
|
+
collisionPadding: { bottom: keyboardPadding },
|
|
20999
21028
|
onOpenAutoFocus: (e) => {
|
|
21000
21029
|
e.preventDefault();
|
|
21001
21030
|
inputRef.current?.focus();
|
|
@@ -21005,8 +21034,8 @@ function TagsManager({
|
|
|
21005
21034
|
e.preventDefault();
|
|
21006
21035
|
}
|
|
21007
21036
|
},
|
|
21008
|
-
children: /* @__PURE__ */ jsxs107(ScrollAreaPrimitive2.Root, { className: "overflow-hidden", children: [
|
|
21009
|
-
/* @__PURE__ */ jsx138(ScrollAreaPrimitive2.Viewport, { className: "max-h-60 w-full", children: /* @__PURE__ */ jsxs107("div", { role: "listbox", children: [
|
|
21037
|
+
children: /* @__PURE__ */ jsxs107(ScrollAreaPrimitive2.Root, { className: "flex min-h-0 flex-col overflow-hidden", children: [
|
|
21038
|
+
/* @__PURE__ */ jsx138(ScrollAreaPrimitive2.Viewport, { className: "min-h-0 max-h-60 w-full", children: /* @__PURE__ */ jsxs107("div", { role: "listbox", children: [
|
|
21010
21039
|
filtered.map((tag) => {
|
|
21011
21040
|
const isSelected = selectedIds.includes(tag.id);
|
|
21012
21041
|
const isEditing = editingId === tag.id;
|
|
@@ -23109,9 +23138,8 @@ function useRichMarkdownRuntime() {
|
|
|
23109
23138
|
import { useState as useState50, useEffect as useEffect41, useRef as useRef33 } from "react";
|
|
23110
23139
|
|
|
23111
23140
|
// src/utils/social-embed-cache.ts
|
|
23112
|
-
var cachingRequests = /* @__PURE__ */ new Map();
|
|
23113
23141
|
var dataCache = /* @__PURE__ */ new Map();
|
|
23114
|
-
var
|
|
23142
|
+
var inflightRequests = /* @__PURE__ */ new Map();
|
|
23115
23143
|
var SocialEmbedCache = class _SocialEmbedCache {
|
|
23116
23144
|
static getInstance() {
|
|
23117
23145
|
if (!_SocialEmbedCache.instance) {
|
|
@@ -23119,269 +23147,64 @@ var SocialEmbedCache = class _SocialEmbedCache {
|
|
|
23119
23147
|
}
|
|
23120
23148
|
return _SocialEmbedCache.instance;
|
|
23121
23149
|
}
|
|
23122
|
-
// Check if data exists in memory cache
|
|
23123
23150
|
getFromMemory(url) {
|
|
23124
23151
|
return dataCache.get(url) || null;
|
|
23125
23152
|
}
|
|
23126
|
-
// Store data in memory cache
|
|
23127
23153
|
setInMemory(url, data) {
|
|
23128
23154
|
dataCache.set(url, data);
|
|
23129
23155
|
}
|
|
23130
|
-
|
|
23131
|
-
|
|
23132
|
-
|
|
23133
|
-
|
|
23134
|
-
const response = await fetch(`${options.apiEndpoint}?url=${encodeURIComponent(options.url)}&cache-only=true`);
|
|
23135
|
-
if (response.ok) {
|
|
23136
|
-
const data = await response.json();
|
|
23137
|
-
console.log(`\u2705 [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] Server cache hit: ${options.url}`);
|
|
23138
|
-
return data;
|
|
23139
|
-
} else if (response.status === 404) {
|
|
23140
|
-
console.log(`\u{1F4A8} [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] No server cache available for: ${options.url}`);
|
|
23141
|
-
return null;
|
|
23142
|
-
}
|
|
23143
|
-
} catch (error) {
|
|
23144
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] Server cache check failed for: ${options.url}`, error);
|
|
23145
|
-
}
|
|
23146
|
-
return null;
|
|
23147
|
-
}
|
|
23148
|
-
// Helper method to update server cache asynchronously
|
|
23149
|
-
async updateServerCache(apiEndpoint, url, data) {
|
|
23150
|
-
try {
|
|
23151
|
-
console.log(`\u{1F4BE} [Cache] Updating server cache for: ${url}`);
|
|
23152
|
-
await fetch(`${apiEndpoint}?url=${encodeURIComponent(url)}`, {
|
|
23153
|
-
method: "POST",
|
|
23154
|
-
headers: { "Content-Type": "application/json" },
|
|
23155
|
-
body: JSON.stringify(data)
|
|
23156
|
-
});
|
|
23157
|
-
console.log(`\u2705 [Cache] Server cache updated for: ${url}`);
|
|
23158
|
-
} catch (error) {
|
|
23159
|
-
console.log(`\u274C [Cache] Server cache update failed for: ${url}`, error);
|
|
23160
|
-
}
|
|
23161
|
-
}
|
|
23162
|
-
// Store data in server cache (with deduplication)
|
|
23163
|
-
async setInServer(options, data) {
|
|
23164
|
-
const cacheKey = `${options.platform}-${options.url}`;
|
|
23165
|
-
if (cachingRequests.has(cacheKey)) {
|
|
23166
|
-
console.log(`\u23ED\uFE0F [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] Server cache update skipped (already in progress): ${options.url}`);
|
|
23167
|
-
return;
|
|
23168
|
-
}
|
|
23169
|
-
console.log(`\u{1F4BE} [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] Updating server cache for: ${options.url}`);
|
|
23170
|
-
const cachePromise = fetch(`${options.apiEndpoint}?url=${encodeURIComponent(options.url)}`, {
|
|
23171
|
-
method: "POST",
|
|
23172
|
-
headers: { "Content-Type": "application/json" },
|
|
23173
|
-
body: JSON.stringify(data)
|
|
23174
|
-
}).then(() => {
|
|
23175
|
-
console.log(`\u2705 [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] Server cache updated successfully: ${options.url}`);
|
|
23176
|
-
cachingRequests.delete(cacheKey);
|
|
23177
|
-
}).catch((error) => {
|
|
23178
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] Server cache update failed: ${options.url}`, error);
|
|
23179
|
-
cachingRequests.delete(cacheKey);
|
|
23180
|
-
});
|
|
23181
|
-
cachingRequests.set(cacheKey, cachePromise);
|
|
23182
|
-
await cachePromise;
|
|
23183
|
-
}
|
|
23184
|
-
// Direct fetch with platform-specific logic
|
|
23185
|
-
async fetchDirect(options) {
|
|
23186
|
-
try {
|
|
23187
|
-
console.log(`\u{1F504} [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Direct] Fetching content: ${options.url}`);
|
|
23188
|
-
const result = await options.directFetcher();
|
|
23189
|
-
console.log(`\u2705 [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Direct] Fetch successful: ${options.url}`);
|
|
23190
|
-
return result;
|
|
23191
|
-
} catch (error) {
|
|
23192
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Direct] Fetch failed: ${options.url}`, error);
|
|
23193
|
-
return null;
|
|
23194
|
-
}
|
|
23195
|
-
}
|
|
23196
|
-
// Unified cache hierarchy: Memory → Server → Direct
|
|
23156
|
+
/**
|
|
23157
|
+
* Memory → proxy. Kept the historical name so the embed clients'
|
|
23158
|
+
* call sites are unchanged.
|
|
23159
|
+
*/
|
|
23197
23160
|
async fetchWithHierarchy(options) {
|
|
23198
|
-
const { url, platform, onDataUpdate, onError, onLoading
|
|
23199
|
-
const platformName = platform.charAt(0).toUpperCase() + platform.slice(1);
|
|
23200
|
-
this.scheduleAsyncRefresh(platform, url, dataValidator, options.apiEndpoint);
|
|
23201
|
-
console.log(`\u{1F50D} [${platformName} Cache] Checking memory cache for: ${url}`);
|
|
23161
|
+
const { url, platform, apiEndpoint, dataValidator, onDataUpdate, onError, onLoading } = options;
|
|
23202
23162
|
const memoryData = this.getFromMemory(url);
|
|
23203
23163
|
if (memoryData && dataValidator(memoryData)) {
|
|
23204
|
-
console.log(`\u{1F48E} [${platformName} Cache] Memory cache hit for: ${url}`);
|
|
23205
23164
|
onDataUpdate(memoryData);
|
|
23206
23165
|
onLoading(false);
|
|
23207
23166
|
return;
|
|
23208
23167
|
}
|
|
23209
|
-
console.log(`\u{1F50D} [${platformName} Cache] No memory cache, checking server cache for: ${url}`);
|
|
23210
|
-
const serverCacheData = await this.getFromServer(options);
|
|
23211
|
-
if (serverCacheData && dataValidator(serverCacheData)) {
|
|
23212
|
-
console.log(`\u{1F3AF} [${platformName} Cache] Server cache hit (cached data) for: ${url}`);
|
|
23213
|
-
onDataUpdate(serverCacheData);
|
|
23214
|
-
this.setInMemory(url, serverCacheData);
|
|
23215
|
-
onLoading(false);
|
|
23216
|
-
return;
|
|
23217
|
-
}
|
|
23218
|
-
console.log(`\u{1F50D} [${platformName} Cache] No server cache, attempting direct fetch for: ${url}`);
|
|
23219
|
-
if (platform === "reddit") {
|
|
23220
|
-
try {
|
|
23221
|
-
const directResponse = await fetch(url, {
|
|
23222
|
-
method: "GET",
|
|
23223
|
-
headers: {
|
|
23224
|
-
"Accept": "application/json"
|
|
23225
|
-
},
|
|
23226
|
-
signal: AbortSignal.timeout(1e4)
|
|
23227
|
-
});
|
|
23228
|
-
if (directResponse.ok) {
|
|
23229
|
-
const directData = await directResponse.json();
|
|
23230
|
-
if (directData && dataValidator(directData)) {
|
|
23231
|
-
console.log(`\u2705 [${platformName} Direct] Browser direct fetch successful for: ${url}`);
|
|
23232
|
-
onDataUpdate(directData);
|
|
23233
|
-
this.setInMemory(url, directData);
|
|
23234
|
-
onLoading(false);
|
|
23235
|
-
setTimeout(() => {
|
|
23236
|
-
this.updateServerCache(options.apiEndpoint, url, directData);
|
|
23237
|
-
}, 0);
|
|
23238
|
-
return;
|
|
23239
|
-
}
|
|
23240
|
-
}
|
|
23241
|
-
console.log(`\u{1F4A8} [${platformName} Direct] Browser direct fetch failed (${directResponse.status}), trying server proxy...`);
|
|
23242
|
-
} catch (directError) {
|
|
23243
|
-
console.log(`\u{1F4A8} [${platformName} Direct] Browser direct fetch failed, trying server proxy...`, directError);
|
|
23244
|
-
}
|
|
23245
|
-
}
|
|
23246
|
-
console.log(`\u{1F50D} [${platformName} Cache] Trying server proxy for: ${url}`);
|
|
23247
23168
|
try {
|
|
23248
|
-
const
|
|
23249
|
-
if (
|
|
23250
|
-
|
|
23251
|
-
|
|
23252
|
-
|
|
23253
|
-
|
|
23254
|
-
console.log(`\u{1F3AF} [${platformName} Proxy] Server cache hit (cached data) for: ${url}`);
|
|
23255
|
-
} else if (cacheStatus === "MISS-FETCHED") {
|
|
23256
|
-
console.log(`\u{1F504} [${platformName} Proxy] Server processed fresh fetch (now cached) for: ${url}`);
|
|
23257
|
-
} else {
|
|
23258
|
-
console.log(`\u2705 [${platformName} Proxy] Server returned data (${cacheStatus}) for: ${url}`);
|
|
23259
|
-
}
|
|
23260
|
-
onDataUpdate(serverData);
|
|
23261
|
-
this.setInMemory(url, serverData);
|
|
23262
|
-
onLoading(false);
|
|
23263
|
-
return;
|
|
23264
|
-
} else {
|
|
23265
|
-
console.log(`\u26A0\uFE0F [${platformName} Proxy] Server returned data but validation failed for: ${url}`);
|
|
23266
|
-
throw new Error("Server proxy returned invalid data shape");
|
|
23267
|
-
}
|
|
23268
|
-
} else {
|
|
23269
|
-
let errorData = null;
|
|
23270
|
-
try {
|
|
23271
|
-
errorData = await response.json();
|
|
23272
|
-
} catch {
|
|
23273
|
-
}
|
|
23274
|
-
if (response.status === 404 && errorData?.error && errorData?.message) {
|
|
23275
|
-
console.log(`\u{1F6AB} [${platformName} Proxy] Content unavailable: ${errorData.message}`);
|
|
23276
|
-
onError(errorData.message);
|
|
23277
|
-
onLoading(false);
|
|
23278
|
-
return;
|
|
23279
|
-
}
|
|
23280
|
-
if (errorData?.error) {
|
|
23281
|
-
throw new Error(`Server error: ${errorData.error}`);
|
|
23282
|
-
}
|
|
23283
|
-
throw new Error(`Server proxy failed: ${response.status}`);
|
|
23169
|
+
const data = await this.fetchFromProxy(url, apiEndpoint, dataValidator);
|
|
23170
|
+
if (data) {
|
|
23171
|
+
this.setInMemory(url, data);
|
|
23172
|
+
onDataUpdate(data);
|
|
23173
|
+
onLoading(false);
|
|
23174
|
+
return;
|
|
23284
23175
|
}
|
|
23176
|
+
onError(`This ${platform === "reddit" ? "Reddit post" : "tweet"} could not be loaded.`);
|
|
23285
23177
|
} catch (error) {
|
|
23286
|
-
console.log(`\u274C [${
|
|
23178
|
+
console.log(`\u274C [${platform} embed] Proxy fetch failed for: ${url}`, error);
|
|
23287
23179
|
onError(`Unable to load ${platform} content`);
|
|
23288
|
-
onLoading(false);
|
|
23289
23180
|
}
|
|
23181
|
+
onLoading(false);
|
|
23290
23182
|
}
|
|
23291
|
-
|
|
23292
|
-
|
|
23293
|
-
|
|
23294
|
-
|
|
23295
|
-
|
|
23296
|
-
|
|
23297
|
-
|
|
23298
|
-
|
|
23299
|
-
|
|
23300
|
-
fetch(`${apiEndpoint}?url=${encodeURIComponent(url)}
|
|
23301
|
-
|
|
23302
|
-
|
|
23303
|
-
|
|
23304
|
-
|
|
23305
|
-
|
|
23306
|
-
|
|
23307
|
-
}).then((data) => {
|
|
23308
|
-
if (data && dataValidator(data)) {
|
|
23309
|
-
this.setInMemory(url, data);
|
|
23310
|
-
console.log(`\u2705 [${platformName} Async] Background refresh completed for: ${url}`);
|
|
23311
|
-
} else if (data) {
|
|
23312
|
-
console.log(`\u274C [${platformName} Async] Background refresh failed (invalid data) for: ${url}`);
|
|
23313
|
-
}
|
|
23314
|
-
}).catch((error) => console.log(`\u274C [${platformName} Async] Background refresh failed for: ${url}`, error));
|
|
23315
|
-
}, 1e3);
|
|
23316
|
-
}
|
|
23317
|
-
// Background refresh to keep cache fresh (with request deduplication)
|
|
23318
|
-
async backgroundRefresh(options, currentData) {
|
|
23319
|
-
const refreshKey = `refresh-${options.platform}-${options.url}`;
|
|
23320
|
-
const now = Date.now();
|
|
23321
|
-
const lastRefresh = refreshTimestamps.get(refreshKey);
|
|
23322
|
-
if (lastRefresh && now - lastRefresh < 3e4) {
|
|
23323
|
-
console.log(`\u23ED\uFE0F [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Background] Refresh skipped (recent refresh): ${options.url}`);
|
|
23324
|
-
return;
|
|
23325
|
-
}
|
|
23326
|
-
if (cachingRequests.has(refreshKey)) {
|
|
23327
|
-
console.log(`\u23ED\uFE0F [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Background] Refresh skipped (already in progress): ${options.url}`);
|
|
23328
|
-
return;
|
|
23329
|
-
}
|
|
23330
|
-
const refreshPromise = (async () => {
|
|
23331
|
-
try {
|
|
23332
|
-
console.log(`\u{1F504} [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Background] Starting background refresh for: ${options.url}`);
|
|
23333
|
-
refreshTimestamps.set(refreshKey, now);
|
|
23334
|
-
const freshData = await this.fetchDirect(options);
|
|
23335
|
-
if (freshData && options.dataValidator(freshData)) {
|
|
23336
|
-
this.setInMemory(options.url, freshData);
|
|
23337
|
-
await this.setInServer(options, freshData);
|
|
23338
|
-
console.log(`\u2705 [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Background] Background refresh completed for: ${options.url}`);
|
|
23339
|
-
} else {
|
|
23340
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Background] Background refresh failed (invalid data) for: ${options.url}`);
|
|
23341
|
-
}
|
|
23342
|
-
} catch (error) {
|
|
23343
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Background] Background refresh failed for: ${options.url}`, error);
|
|
23344
|
-
} finally {
|
|
23345
|
-
cachingRequests.delete(refreshKey);
|
|
23183
|
+
/**
|
|
23184
|
+
* Returns the validated payload, `null` for a structured "content
|
|
23185
|
+
* unavailable" 404, and throws for everything else. Concurrent calls for
|
|
23186
|
+
* the same URL share one request.
|
|
23187
|
+
*/
|
|
23188
|
+
fetchFromProxy(url, apiEndpoint, dataValidator) {
|
|
23189
|
+
const inflight = inflightRequests.get(url);
|
|
23190
|
+
if (inflight) return inflight;
|
|
23191
|
+
const request = (async () => {
|
|
23192
|
+
const response = await fetch(`${apiEndpoint}?url=${encodeURIComponent(url)}`, {
|
|
23193
|
+
signal: AbortSignal.timeout(15e3)
|
|
23194
|
+
});
|
|
23195
|
+
if (response.ok) {
|
|
23196
|
+
const data = await response.json();
|
|
23197
|
+
if (data && dataValidator(data)) return data;
|
|
23198
|
+
throw new Error("Server proxy returned invalid data shape");
|
|
23346
23199
|
}
|
|
23200
|
+
if (response.status === 404) return null;
|
|
23201
|
+
throw new Error(`Server proxy failed: ${response.status}`);
|
|
23347
23202
|
})();
|
|
23348
|
-
|
|
23349
|
-
|
|
23350
|
-
|
|
23351
|
-
|
|
23352
|
-
|
|
23353
|
-
const refreshKey = `silent-refresh-${options.platform}-${options.url}`;
|
|
23354
|
-
const now = Date.now();
|
|
23355
|
-
const lastRefresh = refreshTimestamps.get(refreshKey);
|
|
23356
|
-
if (lastRefresh && now - lastRefresh < 3e5) {
|
|
23357
|
-
console.log(`\u23ED\uFE0F [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Silent] Silent refresh skipped (recent refresh): ${options.url}`);
|
|
23358
|
-
return;
|
|
23359
|
-
}
|
|
23360
|
-
if (cachingRequests.has(refreshKey)) {
|
|
23361
|
-
console.log(`\u23ED\uFE0F [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Silent] Silent refresh skipped (already in progress): ${options.url}`);
|
|
23362
|
-
return;
|
|
23363
|
-
}
|
|
23364
|
-
setTimeout(() => {
|
|
23365
|
-
const refreshPromise = (async () => {
|
|
23366
|
-
try {
|
|
23367
|
-
console.log(`\u{1F504} [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Silent] Starting silent background refresh for: ${options.url}`);
|
|
23368
|
-
refreshTimestamps.set(refreshKey, now);
|
|
23369
|
-
const freshData = await this.fetchDirect(options);
|
|
23370
|
-
if (freshData && options.dataValidator(freshData)) {
|
|
23371
|
-
this.setInMemory(options.url, freshData);
|
|
23372
|
-
await this.setInServer(options, freshData);
|
|
23373
|
-
console.log(`\u2705 [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Silent] Silent refresh completed for: ${options.url}`);
|
|
23374
|
-
} else {
|
|
23375
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Silent] Silent refresh failed (invalid data) for: ${options.url}`);
|
|
23376
|
-
}
|
|
23377
|
-
} catch (error) {
|
|
23378
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Silent] Silent refresh failed for: ${options.url}`, error);
|
|
23379
|
-
} finally {
|
|
23380
|
-
cachingRequests.delete(refreshKey);
|
|
23381
|
-
}
|
|
23382
|
-
})();
|
|
23383
|
-
cachingRequests.set(refreshKey, refreshPromise);
|
|
23384
|
-
}, 0);
|
|
23203
|
+
inflightRequests.set(
|
|
23204
|
+
url,
|
|
23205
|
+
request.finally(() => inflightRequests.delete(url))
|
|
23206
|
+
);
|
|
23207
|
+
return inflightRequests.get(url);
|
|
23385
23208
|
}
|
|
23386
23209
|
};
|
|
23387
23210
|
var socialCache = SocialEmbedCache.getInstance();
|
|
@@ -25019,13 +24842,15 @@ function buildRichEmbedOverrides({
|
|
|
25019
24842
|
}
|
|
25020
24843
|
return standard.div(divProps);
|
|
25021
24844
|
},
|
|
25022
|
-
//
|
|
25023
|
-
// `<blockquote class="reddit-embed-bq">…<a href="post-url">`
|
|
25024
|
-
//
|
|
25025
|
-
//
|
|
25026
|
-
//
|
|
25027
|
-
//
|
|
25028
|
-
//
|
|
24845
|
+
// Pasted-from-the-platform embed markup lives in published blog posts as
|
|
24846
|
+
// `<blockquote class="reddit-embed-bq">…<a href="post-url">` (58 blocks
|
|
24847
|
+
// across 9 posts) — and Twitter's equivalent is
|
|
24848
|
+
// `<blockquote class="twitter-tweet">…<a href="status-url">`. Each pair
|
|
24849
|
+
// ships a `widgets.js` loader script, which `processShortcodes` strips
|
|
24850
|
+
// from the source text (Step 1.5). The composition rehydrates the
|
|
24851
|
+
// blockquote itself: extract the post URL from the first matching link
|
|
24852
|
+
// and render the platform's embed-client SSOT. Other blockquotes fall
|
|
24853
|
+
// through to the engine's base blockquote.
|
|
25029
24854
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25030
24855
|
blockquote: (bqProps) => {
|
|
25031
24856
|
const { node, className } = bqProps;
|
|
@@ -25034,6 +24859,10 @@ function buildRichEmbedOverrides({
|
|
|
25034
24859
|
const postUrl = findFirstHref(node, /reddit\.com/);
|
|
25035
24860
|
if (postUrl) return /* @__PURE__ */ jsx169(RedditEmbedClient, { url: postUrl });
|
|
25036
24861
|
}
|
|
24862
|
+
if (classNames.includes("twitter-tweet")) {
|
|
24863
|
+
const tweetUrl = findFirstHref(node, /(?:twitter\.com|x\.com)\/[^/]+\/status\//);
|
|
24864
|
+
if (tweetUrl) return /* @__PURE__ */ jsx169(TwitterEmbedClient, { url: tweetUrl });
|
|
24865
|
+
}
|
|
25037
24866
|
return standard.blockquote(bqProps);
|
|
25038
24867
|
},
|
|
25039
24868
|
// In-article images: MarkdownImage reads `transformImageSrc` from the
|
|
@@ -25120,6 +24949,10 @@ var processShortcodes = (content) => {
|
|
|
25120
24949
|
codeBlocks.push(match2);
|
|
25121
24950
|
return placeholder;
|
|
25122
24951
|
});
|
|
24952
|
+
processedContent = processedContent.replace(
|
|
24953
|
+
/<script\b[^>]{0,2000}>[\s\S]{0,20000}?<\/script\s{0,10}>/gi,
|
|
24954
|
+
""
|
|
24955
|
+
);
|
|
25123
24956
|
const markdownLinks = [];
|
|
25124
24957
|
processedContent = processedContent.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match2) => {
|
|
25125
24958
|
const placeholder = `__MARKDOWN_LINK_${markdownLinks.length}__`;
|
|
@@ -46188,6 +46021,7 @@ function SearchInput({
|
|
|
46188
46021
|
const debouncedValue = useDebounce(currentValue, debounceMs);
|
|
46189
46022
|
const [isOpen, setIsOpen] = React132.useState(false);
|
|
46190
46023
|
const [highlightedIndex, setHighlightedIndex] = React132.useState(-1);
|
|
46024
|
+
const keyboardPadding = useKeyboardCollisionPadding();
|
|
46191
46025
|
const containerRef = React132.useRef(null);
|
|
46192
46026
|
const currentPlaceholder = filterChips.length > 0 ? "Add filter..." : placeholder;
|
|
46193
46027
|
const {
|
|
@@ -46447,6 +46281,7 @@ function SearchInput({
|
|
|
46447
46281
|
className: cn(
|
|
46448
46282
|
"z-50 w-[var(--radix-popover-trigger-width)] mt-1",
|
|
46449
46283
|
"bg-ods-card border border-ods-border rounded-[6px] overflow-hidden shadow-lg",
|
|
46284
|
+
"flex flex-col max-h-[var(--radix-popper-available-height)]",
|
|
46450
46285
|
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
46451
46286
|
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
46452
46287
|
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
@@ -46455,6 +46290,7 @@ function SearchInput({
|
|
|
46455
46290
|
),
|
|
46456
46291
|
sideOffset: 4,
|
|
46457
46292
|
align: "start",
|
|
46293
|
+
collisionPadding: { bottom: keyboardPadding },
|
|
46458
46294
|
onOpenAutoFocus: (e) => {
|
|
46459
46295
|
e.preventDefault();
|
|
46460
46296
|
inputRef.current?.focus();
|
|
@@ -46464,8 +46300,8 @@ function SearchInput({
|
|
|
46464
46300
|
e.preventDefault();
|
|
46465
46301
|
}
|
|
46466
46302
|
},
|
|
46467
|
-
children: /* @__PURE__ */ jsxs281(ScrollAreaPrimitive3.Root, { className: "overflow-hidden", children: [
|
|
46468
|
-
/* @__PURE__ */ jsx357(ScrollAreaPrimitive3.Viewport, { className: "max-h-[320px] w-full", children: /* @__PURE__ */ jsx357("div", { role: "listbox", children: renderDropdownContent() }) }),
|
|
46303
|
+
children: /* @__PURE__ */ jsxs281(ScrollAreaPrimitive3.Root, { className: "flex min-h-0 flex-col overflow-hidden", children: [
|
|
46304
|
+
/* @__PURE__ */ jsx357(ScrollAreaPrimitive3.Viewport, { className: "min-h-0 max-h-[320px] w-full", children: /* @__PURE__ */ jsx357("div", { role: "listbox", children: renderDropdownContent() }) }),
|
|
46469
46305
|
/* @__PURE__ */ jsx357(ScrollAreaPrimitive3.Scrollbar, { className: "hidden", orientation: "vertical", children: /* @__PURE__ */ jsx357(ScrollAreaPrimitive3.Thumb, {}) })
|
|
46470
46306
|
] })
|
|
46471
46307
|
}
|
|
@@ -47303,7 +47139,8 @@ function FileUpload({
|
|
|
47303
47139
|
return;
|
|
47304
47140
|
}
|
|
47305
47141
|
try {
|
|
47306
|
-
|
|
47142
|
+
const picked = await pickFiles();
|
|
47143
|
+
if (picked.length > 0) handleFiles(picked);
|
|
47307
47144
|
} catch (err) {
|
|
47308
47145
|
setValidationError(err instanceof Error ? err.message : "Could not open the file picker");
|
|
47309
47146
|
}
|
|
@@ -47657,19 +47494,23 @@ import * as PopoverPrimitive7 from "@radix-ui/react-popover";
|
|
|
47657
47494
|
import { jsx as jsx363 } from "react/jsx-runtime";
|
|
47658
47495
|
var Popover2 = PopoverPrimitive7.Root;
|
|
47659
47496
|
var PopoverTrigger = PopoverPrimitive7.Trigger;
|
|
47660
|
-
var PopoverContent = React137.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) =>
|
|
47661
|
-
|
|
47662
|
-
{
|
|
47663
|
-
|
|
47664
|
-
|
|
47665
|
-
|
|
47666
|
-
|
|
47667
|
-
|
|
47668
|
-
|
|
47669
|
-
|
|
47670
|
-
|
|
47671
|
-
|
|
47672
|
-
)
|
|
47497
|
+
var PopoverContent = React137.forwardRef(({ className, align = "center", sideOffset = 4, collisionPadding, ...props }, ref) => {
|
|
47498
|
+
const keyboardPadding = useKeyboardCollisionPadding();
|
|
47499
|
+
return /* @__PURE__ */ jsx363(PopoverPrimitive7.Portal, { children: /* @__PURE__ */ jsx363(
|
|
47500
|
+
PopoverPrimitive7.Content,
|
|
47501
|
+
{
|
|
47502
|
+
ref,
|
|
47503
|
+
align,
|
|
47504
|
+
sideOffset,
|
|
47505
|
+
collisionPadding: collisionPadding ?? { bottom: keyboardPadding },
|
|
47506
|
+
className: cn(
|
|
47507
|
+
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
47508
|
+
className
|
|
47509
|
+
),
|
|
47510
|
+
...props
|
|
47511
|
+
}
|
|
47512
|
+
) });
|
|
47513
|
+
});
|
|
47673
47514
|
PopoverContent.displayName = PopoverPrimitive7.Content.displayName;
|
|
47674
47515
|
|
|
47675
47516
|
// src/components/ui/color-preset-select.tsx
|
|
@@ -62267,4 +62108,4 @@ export {
|
|
|
62267
62108
|
LogsList,
|
|
62268
62109
|
assets
|
|
62269
62110
|
};
|
|
62270
|
-
//# sourceMappingURL=chunk-
|
|
62111
|
+
//# sourceMappingURL=chunk-4DTUUM5V.js.map
|