@tightknitai/block-kitchen 0.10.3 → 0.10.5
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/README.md +20 -7
- package/dist/helpers.d.cts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.cjs +495 -272
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +495 -272
- package/dist/index.js.map +1 -1
- package/dist/{palette-TGNFqyja.d.cts → palette-Sz27861i.d.cts} +9 -6
- package/dist/{palette-TGNFqyja.d.ts → palette-Sz27861i.d.ts} +9 -6
- package/dist/palette.d.cts +1 -1
- package/dist/palette.d.ts +1 -1
- package/dist/styles.css +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -14,14 +14,14 @@ var nanoid = require('nanoid');
|
|
|
14
14
|
var reactSlot = require('@radix-ui/react-slot');
|
|
15
15
|
var classVarianceAuthority = require('class-variance-authority');
|
|
16
16
|
var LabelPrimitive = require('@radix-ui/react-label');
|
|
17
|
+
require('slack-blocks-to-jsx/dist/style.css');
|
|
18
|
+
var slackBlocksToJsx = require('slack-blocks-to-jsx');
|
|
17
19
|
var utilities = require('@dnd-kit/utilities');
|
|
18
20
|
var PopoverPrimitive = require('@radix-ui/react-popover');
|
|
19
21
|
var RadioGroupPrimitive = require('@radix-ui/react-radio-group');
|
|
20
22
|
var Link = require('@tiptap/extension-link');
|
|
21
23
|
var react = require('@tiptap/react');
|
|
22
24
|
var StarterKit = require('@tiptap/starter-kit');
|
|
23
|
-
require('slack-blocks-to-jsx/dist/style.css');
|
|
24
|
-
var slackBlocksToJsx = require('slack-blocks-to-jsx');
|
|
25
25
|
|
|
26
26
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
27
27
|
|
|
@@ -3054,6 +3054,128 @@ var Label = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__
|
|
|
3054
3054
|
}
|
|
3055
3055
|
));
|
|
3056
3056
|
Label.displayName = LabelPrimitive__namespace.Root.displayName;
|
|
3057
|
+
function SlackBlockPreview({
|
|
3058
|
+
block,
|
|
3059
|
+
hooks,
|
|
3060
|
+
theme = "light"
|
|
3061
|
+
}) {
|
|
3062
|
+
const rootRef = React.useRef(null);
|
|
3063
|
+
const safeBlock = React.useMemo(() => sanitizeBlock(block), [block]);
|
|
3064
|
+
React.useEffect(() => {
|
|
3065
|
+
const root = rootRef.current;
|
|
3066
|
+
if (!root) return;
|
|
3067
|
+
for (const wrapper of root.querySelectorAll(
|
|
3068
|
+
".slack_blocks_to_jsx__image_media_trigger, .slack_blocks_to_jsx__video_title"
|
|
3069
|
+
)) {
|
|
3070
|
+
for (const btn of wrapper.querySelectorAll("button:not([aria-label])")) {
|
|
3071
|
+
const title = wrapper.querySelector(".slack_blocks_to_jsx__image_title")?.textContent?.trim();
|
|
3072
|
+
btn.setAttribute("aria-label", title ? `Toggle ${title}` : "Toggle media");
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
for (const a of root.querySelectorAll("a[href]")) {
|
|
3076
|
+
const href = a.getAttribute("href");
|
|
3077
|
+
if (!isSafeHref(href)) {
|
|
3078
|
+
a.setAttribute("href", "#");
|
|
3079
|
+
a.setAttribute("data-bk-blocked-href", "1");
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
for (const img of root.querySelectorAll("img[src]")) {
|
|
3083
|
+
const src = img.getAttribute("src");
|
|
3084
|
+
if (!isSafeImageSrc(src)) {
|
|
3085
|
+
img.removeAttribute("src");
|
|
3086
|
+
img.setAttribute("data-bk-blocked-src", "1");
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
});
|
|
3090
|
+
return (
|
|
3091
|
+
// The library scopes all of its CSS under `#slack_blocks_to_jsx` and
|
|
3092
|
+
// depends on the `slack_blocks_to_jsx styles_enabled` classes plus the
|
|
3093
|
+
// `data-theme` attribute for its button / mention / divider styling
|
|
3094
|
+
// (e.g. button reset + `bg-green-primary` for primary). `<Message
|
|
3095
|
+
// withoutWrapper>` skips that wrapper entirely, so we re-create it
|
|
3096
|
+
// here without the avatar / timestamp chrome.
|
|
3097
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: rootRef, id: "slack_blocks_to_jsx", "data-theme": theme, className: "slack_blocks_to_jsx styles_enabled", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3098
|
+
slackBlocksToJsx.Message,
|
|
3099
|
+
{
|
|
3100
|
+
time: /* @__PURE__ */ new Date(),
|
|
3101
|
+
name: "",
|
|
3102
|
+
logo: "",
|
|
3103
|
+
withoutWrapper: true,
|
|
3104
|
+
theme,
|
|
3105
|
+
blocks: [safeBlock],
|
|
3106
|
+
hooks
|
|
3107
|
+
}
|
|
3108
|
+
) })
|
|
3109
|
+
);
|
|
3110
|
+
}
|
|
3111
|
+
var PLACEHOLDER_TIME = "10:37 AM";
|
|
3112
|
+
function SlackMessageFrame({
|
|
3113
|
+
workspaceName,
|
|
3114
|
+
authorName,
|
|
3115
|
+
authorIcon,
|
|
3116
|
+
time = PLACEHOLDER_TIME,
|
|
3117
|
+
isDark,
|
|
3118
|
+
children
|
|
3119
|
+
}) {
|
|
3120
|
+
const displayName = authorName ?? workspaceName ?? "Your app";
|
|
3121
|
+
const initial = displayName.slice(0, 1).toUpperCase();
|
|
3122
|
+
const safeIcon = authorIcon && isSafeImageSrc(authorIcon) ? authorIcon : null;
|
|
3123
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3124
|
+
"div",
|
|
3125
|
+
{
|
|
3126
|
+
className: cn(
|
|
3127
|
+
"flex flex-col overflow-hidden rounded-md border",
|
|
3128
|
+
isDark ? "border-[#2c2d30] bg-[#1a1d21]" : "border-[#e8e8e8] bg-white"
|
|
3129
|
+
),
|
|
3130
|
+
children: [
|
|
3131
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3132
|
+
"div",
|
|
3133
|
+
{
|
|
3134
|
+
className: cn("flex items-center gap-2 px-5 pt-3 pb-1 text-xs", isDark ? "text-white/60" : "text-[#616061]"),
|
|
3135
|
+
children: [
|
|
3136
|
+
safeIcon ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: safeIcon, alt: "", className: "h-7 w-7 shrink-0 rounded object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3137
|
+
"span",
|
|
3138
|
+
{
|
|
3139
|
+
className: cn(
|
|
3140
|
+
"inline-flex h-7 w-7 items-center justify-center rounded text-[12px] font-semibold",
|
|
3141
|
+
isDark ? "bg-white/10 text-white" : "bg-[#4a154b]/10 text-[#1d1c1d]"
|
|
3142
|
+
),
|
|
3143
|
+
children: initial
|
|
3144
|
+
}
|
|
3145
|
+
),
|
|
3146
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-bold text-sm", isDark ? "text-white" : "text-[#1d1c1d]"), children: displayName }),
|
|
3147
|
+
time ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: time }) : null
|
|
3148
|
+
]
|
|
3149
|
+
}
|
|
3150
|
+
),
|
|
3151
|
+
children
|
|
3152
|
+
]
|
|
3153
|
+
}
|
|
3154
|
+
);
|
|
3155
|
+
}
|
|
3156
|
+
function SlackMessagePreview({
|
|
3157
|
+
blocks,
|
|
3158
|
+
hooks,
|
|
3159
|
+
theme = "light",
|
|
3160
|
+
workspaceName,
|
|
3161
|
+
authorName,
|
|
3162
|
+
authorIcon,
|
|
3163
|
+
time,
|
|
3164
|
+
emptyLabel = "This message has no blocks to preview."
|
|
3165
|
+
}) {
|
|
3166
|
+
const isDark = theme === "dark";
|
|
3167
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3168
|
+
SlackMessageFrame,
|
|
3169
|
+
{
|
|
3170
|
+
workspaceName,
|
|
3171
|
+
authorName,
|
|
3172
|
+
authorIcon,
|
|
3173
|
+
time,
|
|
3174
|
+
isDark,
|
|
3175
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex min-w-0 flex-col gap-1 px-5 pb-3", isDark ? "bg-[#1a1d21]" : "bg-white"), children: blocks.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("py-1 text-sm", isDark ? "text-white/60" : "text-[#616061]"), children: emptyLabel }) : blocks.map((block, index) => /* @__PURE__ */ jsxRuntime.jsx(SlackBlockPreview, { block, hooks, theme }, `${block.type}-${index}`)) })
|
|
3176
|
+
}
|
|
3177
|
+
);
|
|
3178
|
+
}
|
|
3057
3179
|
var POLL_INTERVAL_MS = 2500;
|
|
3058
3180
|
var MAX_POLLS = 24;
|
|
3059
3181
|
function useSlackSignIn(loadStatus, { open, enabled }) {
|
|
@@ -3127,6 +3249,13 @@ function SlackSignInButton({ onClick, polling }) {
|
|
|
3127
3249
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, {})
|
|
3128
3250
|
] }) });
|
|
3129
3251
|
}
|
|
3252
|
+
var LINK_DEBOUNCE_MS = 400;
|
|
3253
|
+
var LINK_HELP_TEXT = 'Click the \u2807menu while hovering over the message in Slack (or right-click), and select "Copy Link".';
|
|
3254
|
+
var LINK_HELP_LABEL = "Where to find a message link";
|
|
3255
|
+
var TABS = [
|
|
3256
|
+
{ id: "recent", label: "Pick from Recent" },
|
|
3257
|
+
{ id: "link", label: "Direct Link" }
|
|
3258
|
+
];
|
|
3130
3259
|
function recentToResult(msg) {
|
|
3131
3260
|
return {
|
|
3132
3261
|
ok: true,
|
|
@@ -3151,6 +3280,16 @@ function previewText(m) {
|
|
|
3151
3280
|
}
|
|
3152
3281
|
return `${m.blocks.length} block${m.blocks.length === 1 ? "" : "s"}`;
|
|
3153
3282
|
}
|
|
3283
|
+
function formatTs(ts) {
|
|
3284
|
+
const seconds = Number(ts);
|
|
3285
|
+
if (!ts || !Number.isFinite(seconds) || seconds <= 0) {
|
|
3286
|
+
return "";
|
|
3287
|
+
}
|
|
3288
|
+
return new Date(seconds * 1e3).toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
|
|
3289
|
+
}
|
|
3290
|
+
function editableLabel(editableVia) {
|
|
3291
|
+
return editableVia === "user" ? "You" : "Bot";
|
|
3292
|
+
}
|
|
3154
3293
|
function LoadMessageDialog({
|
|
3155
3294
|
open,
|
|
3156
3295
|
onOpenChange,
|
|
@@ -3158,10 +3297,14 @@ function LoadMessageDialog({
|
|
|
3158
3297
|
loadRecentMessages,
|
|
3159
3298
|
loadChannels,
|
|
3160
3299
|
onLoaded,
|
|
3161
|
-
onOpenAsNew
|
|
3300
|
+
onOpenAsNew,
|
|
3301
|
+
previewHooks,
|
|
3302
|
+
previewTheme = "light"
|
|
3162
3303
|
}) {
|
|
3163
3304
|
const [link, setLink] = React.useState("");
|
|
3164
|
-
const [
|
|
3305
|
+
const [linkStatus, setLinkStatus] = React.useState({ kind: "idle" });
|
|
3306
|
+
const [emptyLinkError, setEmptyLinkError] = React.useState(null);
|
|
3307
|
+
const [committing, setCommitting] = React.useState(false);
|
|
3165
3308
|
const [channels, setChannels] = React.useState(null);
|
|
3166
3309
|
const [channelsError, setChannelsError] = React.useState(null);
|
|
3167
3310
|
const [channelId, setChannelId] = React.useState("");
|
|
@@ -3169,8 +3312,14 @@ function LoadMessageDialog({
|
|
|
3169
3312
|
const [recentError, setRecentError] = React.useState(null);
|
|
3170
3313
|
const [selectedRecent, setSelectedRecent] = React.useState(null);
|
|
3171
3314
|
const [signInPolling, setSignInPolling] = React.useState(false);
|
|
3315
|
+
const [tab, setTab] = React.useState("recent");
|
|
3172
3316
|
const inputRef = React.useRef(null);
|
|
3173
3317
|
const signInPollRef = React.useRef(null);
|
|
3318
|
+
const resolvedLinkRef = React.useRef(null);
|
|
3319
|
+
const linkRequestRef = React.useRef(0);
|
|
3320
|
+
const domId = React.useId();
|
|
3321
|
+
const tabDomId = (id) => `${domId}-${id}-tab`;
|
|
3322
|
+
const panelDomId = (id) => `${domId}-${id}-panel`;
|
|
3174
3323
|
const onLoadMessageRef = React.useRef(onLoadMessage);
|
|
3175
3324
|
const loadRecentMessagesRef = React.useRef(loadRecentMessages);
|
|
3176
3325
|
const loadChannelsRef = React.useRef(loadChannels);
|
|
@@ -3180,16 +3329,22 @@ function LoadMessageDialog({
|
|
|
3180
3329
|
loadChannelsRef.current = loadChannels;
|
|
3181
3330
|
});
|
|
3182
3331
|
const hasRecent = !!loadRecentMessages && !!loadChannels;
|
|
3332
|
+
const activeTab = hasRecent ? tab : "link";
|
|
3183
3333
|
React.useEffect(() => {
|
|
3184
3334
|
if (!open) {
|
|
3185
3335
|
return;
|
|
3186
3336
|
}
|
|
3187
3337
|
setLink("");
|
|
3188
|
-
|
|
3338
|
+
setLinkStatus({ kind: "idle" });
|
|
3339
|
+
setEmptyLinkError(null);
|
|
3340
|
+
setCommitting(false);
|
|
3189
3341
|
setChannelId("");
|
|
3190
3342
|
setRecent(null);
|
|
3191
3343
|
setRecentError(null);
|
|
3192
3344
|
setSelectedRecent(null);
|
|
3345
|
+
setTab("recent");
|
|
3346
|
+
resolvedLinkRef.current = null;
|
|
3347
|
+
linkRequestRef.current += 1;
|
|
3193
3348
|
}, [open]);
|
|
3194
3349
|
React.useEffect(() => {
|
|
3195
3350
|
const load = loadChannelsRef.current;
|
|
@@ -3248,27 +3403,71 @@ function LoadMessageDialog({
|
|
|
3248
3403
|
}
|
|
3249
3404
|
return stopSignInPoll;
|
|
3250
3405
|
}, [open, stopSignInPoll]);
|
|
3406
|
+
const resolveLink = React.useCallback(async (trimmed) => {
|
|
3407
|
+
const requestId = ++linkRequestRef.current;
|
|
3408
|
+
setLinkStatus({ kind: "loading" });
|
|
3409
|
+
try {
|
|
3410
|
+
const result = await onLoadMessageRef.current({ link: trimmed });
|
|
3411
|
+
if (linkRequestRef.current !== requestId) {
|
|
3412
|
+
return null;
|
|
3413
|
+
}
|
|
3414
|
+
resolvedLinkRef.current = trimmed;
|
|
3415
|
+
setLinkStatus(
|
|
3416
|
+
result.ok ? { kind: "ready", result } : { kind: "not-editable", reason: result.reason, blocks: result.blocks, oauthUrl: result.oauthUrl }
|
|
3417
|
+
);
|
|
3418
|
+
return result;
|
|
3419
|
+
} catch (e) {
|
|
3420
|
+
if (linkRequestRef.current !== requestId) {
|
|
3421
|
+
return null;
|
|
3422
|
+
}
|
|
3423
|
+
resolvedLinkRef.current = trimmed;
|
|
3424
|
+
setLinkStatus({ kind: "error", error: e instanceof Error ? e.message : "Failed to load message." });
|
|
3425
|
+
return null;
|
|
3426
|
+
}
|
|
3427
|
+
}, []);
|
|
3428
|
+
React.useEffect(() => {
|
|
3429
|
+
if (!open) {
|
|
3430
|
+
return;
|
|
3431
|
+
}
|
|
3432
|
+
const trimmed = link.trim();
|
|
3433
|
+
if (!trimmed) {
|
|
3434
|
+
linkRequestRef.current += 1;
|
|
3435
|
+
resolvedLinkRef.current = null;
|
|
3436
|
+
setLinkStatus({ kind: "idle" });
|
|
3437
|
+
return;
|
|
3438
|
+
}
|
|
3439
|
+
if (resolvedLinkRef.current === trimmed) {
|
|
3440
|
+
return;
|
|
3441
|
+
}
|
|
3442
|
+
const timer = setTimeout(() => {
|
|
3443
|
+
if (resolvedLinkRef.current !== trimmed) {
|
|
3444
|
+
void resolveLink(trimmed);
|
|
3445
|
+
}
|
|
3446
|
+
}, LINK_DEBOUNCE_MS);
|
|
3447
|
+
return () => clearTimeout(timer);
|
|
3448
|
+
}, [open, link, resolveLink]);
|
|
3251
3449
|
const handleLoad = async () => {
|
|
3252
3450
|
stopSignInPoll();
|
|
3253
|
-
if (
|
|
3254
|
-
|
|
3451
|
+
if (activeTab === "recent") {
|
|
3452
|
+
if (selectedRecent) {
|
|
3453
|
+
onLoaded(recentToResult(selectedRecent));
|
|
3454
|
+
}
|
|
3255
3455
|
return;
|
|
3256
3456
|
}
|
|
3257
3457
|
const trimmed = link.trim();
|
|
3258
3458
|
if (!trimmed) {
|
|
3259
|
-
|
|
3459
|
+
setEmptyLinkError("Paste a Slack message link first.");
|
|
3260
3460
|
return;
|
|
3261
3461
|
}
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
setStatus({ kind: "error", error: e instanceof Error ? e.message : "Failed to load message." });
|
|
3462
|
+
if (linkStatus.kind === "ready" && resolvedLinkRef.current === trimmed) {
|
|
3463
|
+
onLoaded(linkStatus.result);
|
|
3464
|
+
return;
|
|
3465
|
+
}
|
|
3466
|
+
setCommitting(true);
|
|
3467
|
+
const result = await resolveLink(trimmed);
|
|
3468
|
+
setCommitting(false);
|
|
3469
|
+
if (result?.ok) {
|
|
3470
|
+
onLoaded(result);
|
|
3272
3471
|
}
|
|
3273
3472
|
};
|
|
3274
3473
|
const startFindSignIn = (oauthUrl) => {
|
|
@@ -3300,191 +3499,301 @@ function LoadMessageDialog({
|
|
|
3300
3499
|
});
|
|
3301
3500
|
}, POLL_INTERVAL_MS2);
|
|
3302
3501
|
};
|
|
3303
|
-
const
|
|
3304
|
-
const
|
|
3502
|
+
const preview = activeTab === "recent" ? selectedRecent ? { kind: "ready", target: { ...selectedRecent, editableVia: selectedRecent.editableVia ?? "bot" } } : { kind: "empty" } : linkStatus.kind === "idle" ? { kind: "empty" } : linkStatus.kind === "ready" ? { kind: "ready", target: linkStatus.result } : linkStatus;
|
|
3503
|
+
const canLoad = activeTab === "recent" ? !!selectedRecent : !!link.trim();
|
|
3504
|
+
const panelProps = (id) => hasRecent ? { role: "tabpanel", id: panelDomId(id), "aria-labelledby": tabDomId(id) } : {};
|
|
3305
3505
|
return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3306
3506
|
DialogContent,
|
|
3307
3507
|
{
|
|
3308
|
-
className: "w-[calc(100vw-1.5rem)] max-w-
|
|
3508
|
+
className: "flex max-h-[85svh] w-[calc(100vw-1.5rem)] max-w-4xl flex-col rounded-lg max-lg:max-w-lg",
|
|
3309
3509
|
onOpenAutoFocus: (e) => {
|
|
3510
|
+
if (hasRecent) {
|
|
3511
|
+
return;
|
|
3512
|
+
}
|
|
3310
3513
|
e.preventDefault();
|
|
3311
3514
|
inputRef.current?.focus();
|
|
3312
3515
|
},
|
|
3313
3516
|
children: [
|
|
3314
|
-
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
3517
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { className: "shrink-0", children: [
|
|
3315
3518
|
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Find an existing message" }),
|
|
3316
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3317
|
-
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: hasRecent ? "Paste a Slack message link, or pick a recent message your app posted." : `Paste a Slack message link (Slack's "Copy link") to load its blocks for editing.` }),
|
|
3318
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
3319
|
-
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3320
|
-
"button",
|
|
3321
|
-
{
|
|
3322
|
-
type: "button",
|
|
3323
|
-
"aria-label": "How to copy a message link",
|
|
3324
|
-
className: "mt-0.5 shrink-0 rounded text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
3325
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Info, { className: "h-3.5 w-3.5" })
|
|
3326
|
-
}
|
|
3327
|
-
) }),
|
|
3328
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TooltipContent, { className: "max-w-xs leading-relaxed", children: [
|
|
3329
|
-
"In Slack, hover over the message and click the ",
|
|
3330
|
-
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: "\u22EE More actions" }),
|
|
3331
|
-
" button (or right-click the message), then choose ",
|
|
3332
|
-
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Copy link" }),
|
|
3333
|
-
"."
|
|
3334
|
-
] })
|
|
3335
|
-
] })
|
|
3336
|
-
] })
|
|
3519
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: hasRecent ? "Pick a recent message your app posted, or paste a Slack message link. Preview it before loading." : `Paste a Slack message link (Slack's "Copy link") to preview it and load its blocks for editing.` })
|
|
3337
3520
|
] }),
|
|
3338
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-4", children: [
|
|
3339
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-
|
|
3340
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3341
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3342
|
-
|
|
3521
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "-mx-1 flex min-h-0 min-w-0 flex-1 px-1 max-lg:flex-col max-lg:gap-4 max-lg:overflow-y-auto lg:flex-row lg:gap-5 lg:overflow-hidden", children: [
|
|
3522
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 shrink-0 flex-col gap-3 lg:min-h-0 lg:w-[19rem]", children: [
|
|
3523
|
+
hasRecent && /* @__PURE__ */ jsxRuntime.jsx(TabStrip, { activeTab, onSelect: setTab, tabDomId, panelDomId }),
|
|
3524
|
+
activeTab === "recent" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3525
|
+
"div",
|
|
3343
3526
|
{
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3527
|
+
...panelProps("recent"),
|
|
3528
|
+
className: "-mx-1 flex min-w-0 flex-col gap-2 px-1 lg:min-h-0 lg:flex-1 lg:overflow-hidden",
|
|
3529
|
+
children: [
|
|
3530
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 flex-col gap-1.5", children: [
|
|
3531
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "recent-channel-picker", children: "Channel" }),
|
|
3532
|
+
channels === null && !channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Loading channels\u2026" }),
|
|
3533
|
+
channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive", children: channelsError }),
|
|
3534
|
+
channels && channels.length === 0 && !channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "No public channels available." }),
|
|
3535
|
+
channels && channels.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3536
|
+
"select",
|
|
3537
|
+
{
|
|
3538
|
+
id: "recent-channel-picker",
|
|
3539
|
+
value: channelId,
|
|
3540
|
+
onChange: (e) => setChannelId(e.target.value),
|
|
3541
|
+
className: "flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
3542
|
+
children: [
|
|
3543
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: "Select a channel\u2026" }),
|
|
3544
|
+
channels.map((c) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: c.id, children: [
|
|
3545
|
+
"#",
|
|
3546
|
+
c.name
|
|
3547
|
+
] }, c.id))
|
|
3548
|
+
]
|
|
3549
|
+
}
|
|
3550
|
+
)
|
|
3551
|
+
] }),
|
|
3552
|
+
!channelId && channels && channels.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 text-xs text-muted-foreground", children: "Select a channel to see recent messages." }),
|
|
3553
|
+
channelId && recent === null && !recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 text-xs text-muted-foreground", children: "Loading recent messages\u2026" }),
|
|
3554
|
+
channelId && recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 text-xs text-destructive", children: recentError }),
|
|
3555
|
+
channelId && recent && recent.length === 0 && !recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 text-xs text-muted-foreground", children: "No recent messages from this app in this channel." }),
|
|
3556
|
+
channelId && recent && recent.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-0 min-w-0 flex-col gap-1 overflow-y-auto max-lg:max-h-60 lg:flex-1", children: recent.map((m) => {
|
|
3557
|
+
const asUser = (m.editableVia ?? "bot") === "user";
|
|
3558
|
+
const authorName = m.username || (asUser ? "You" : "App bot");
|
|
3559
|
+
const safeIcon = isSafeImageSrc(m.iconUrl) ? m.iconUrl : void 0;
|
|
3560
|
+
const isSelected = selectedRecent?.channelId === m.channelId && selectedRecent?.ts === m.ts;
|
|
3561
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3562
|
+
"button",
|
|
3563
|
+
{
|
|
3564
|
+
type: "button",
|
|
3565
|
+
"aria-pressed": isSelected,
|
|
3566
|
+
onClick: () => {
|
|
3567
|
+
setSelectedRecent(m);
|
|
3568
|
+
},
|
|
3569
|
+
className: cn(
|
|
3570
|
+
// Inset rings so the scroll container's overflow clip
|
|
3571
|
+
// can't shave the corners off the selected outline.
|
|
3572
|
+
"flex min-w-0 items-start gap-2.5 rounded-md border border-input bg-background px-3 py-2 text-left hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring",
|
|
3573
|
+
isSelected && "border-primary! bg-accent ring-1 ring-inset ring-primary"
|
|
3574
|
+
),
|
|
3575
|
+
children: [
|
|
3576
|
+
safeIcon ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: safeIcon, alt: "", className: "h-9 w-9 shrink-0 rounded-md object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3577
|
+
"span",
|
|
3578
|
+
{
|
|
3579
|
+
"aria-hidden": true,
|
|
3580
|
+
className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-muted text-sm font-semibold text-muted-foreground",
|
|
3581
|
+
children: authorName.charAt(0).toUpperCase()
|
|
3582
|
+
}
|
|
3583
|
+
),
|
|
3584
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col gap-0.5", children: [
|
|
3585
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
|
|
3586
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-semibold text-foreground", children: authorName }),
|
|
3587
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 rounded border px-1 py-px text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: asUser ? "You" : "Bot" })
|
|
3588
|
+
] }),
|
|
3589
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
3590
|
+
new Date(Number(m.ts) * 1e3).toLocaleString(),
|
|
3591
|
+
" ",
|
|
3592
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono", children: [
|
|
3593
|
+
"(",
|
|
3594
|
+
m.ts,
|
|
3595
|
+
")"
|
|
3596
|
+
] })
|
|
3597
|
+
] }),
|
|
3598
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-2 text-sm text-foreground", children: previewText(m) })
|
|
3599
|
+
] })
|
|
3600
|
+
]
|
|
3601
|
+
},
|
|
3602
|
+
`${m.channelId}:${m.ts}`
|
|
3603
|
+
);
|
|
3604
|
+
}) })
|
|
3605
|
+
]
|
|
3606
|
+
}
|
|
3607
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3608
|
+
"div",
|
|
3609
|
+
{
|
|
3610
|
+
...panelProps("link"),
|
|
3611
|
+
className: "-mx-1 flex min-w-0 flex-col gap-2 px-1 lg:min-h-0 lg:flex-1 lg:overflow-y-auto",
|
|
3612
|
+
children: [
|
|
3613
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
3614
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
3615
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "message-link", children: "Message link" }),
|
|
3616
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
3617
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3618
|
+
"button",
|
|
3619
|
+
{
|
|
3620
|
+
type: "button",
|
|
3621
|
+
"aria-label": LINK_HELP_LABEL,
|
|
3622
|
+
className: "flex h-4 w-4 items-center justify-center rounded-full text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
3623
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Info, { className: "h-3.5 w-3.5" })
|
|
3624
|
+
}
|
|
3625
|
+
) }),
|
|
3626
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "right", children: LINK_HELP_TEXT })
|
|
3627
|
+
] })
|
|
3628
|
+
] }),
|
|
3629
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3630
|
+
Input,
|
|
3631
|
+
{
|
|
3632
|
+
ref: inputRef,
|
|
3633
|
+
id: "message-link",
|
|
3634
|
+
value: link,
|
|
3635
|
+
onChange: (e) => {
|
|
3636
|
+
setLink(e.target.value);
|
|
3637
|
+
setEmptyLinkError(null);
|
|
3638
|
+
stopSignInPoll();
|
|
3639
|
+
},
|
|
3640
|
+
onKeyDown: (e) => {
|
|
3641
|
+
if (e.key === "Enter" && !committing) {
|
|
3642
|
+
e.preventDefault();
|
|
3643
|
+
handleLoad();
|
|
3644
|
+
}
|
|
3645
|
+
},
|
|
3646
|
+
placeholder: "https://your-workspace.slack.com/archives/C\u2026/p\u2026",
|
|
3647
|
+
autoComplete: "off",
|
|
3648
|
+
spellCheck: false
|
|
3649
|
+
}
|
|
3650
|
+
)
|
|
3651
|
+
] }),
|
|
3652
|
+
emptyLinkError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-2 text-xs text-destructive", children: emptyLinkError })
|
|
3653
|
+
]
|
|
3364
3654
|
}
|
|
3365
3655
|
)
|
|
3366
3656
|
] }),
|
|
3367
|
-
|
|
3368
|
-
|
|
3657
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3658
|
+
PreviewPane,
|
|
3659
|
+
{
|
|
3660
|
+
state: preview,
|
|
3661
|
+
hooks: previewHooks,
|
|
3662
|
+
theme: previewTheme,
|
|
3663
|
+
emptyHint: activeTab === "recent" ? "Select a recent message to preview it here." : "Paste a message link to preview it here.",
|
|
3664
|
+
signInPolling,
|
|
3665
|
+
onSignIn: startFindSignIn,
|
|
3666
|
+
onOpenAsNew
|
|
3667
|
+
}
|
|
3668
|
+
)
|
|
3669
|
+
] }),
|
|
3670
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { className: "shrink-0", children: [
|
|
3671
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "ghost", onClick: () => onOpenChange(false), children: "Cancel" }),
|
|
3672
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", onClick: handleLoad, disabled: committing || !canLoad, children: committing ? "Loading\u2026" : "Load message" })
|
|
3673
|
+
] })
|
|
3674
|
+
]
|
|
3675
|
+
}
|
|
3676
|
+
) });
|
|
3677
|
+
}
|
|
3678
|
+
function TabStrip({
|
|
3679
|
+
activeTab,
|
|
3680
|
+
onSelect,
|
|
3681
|
+
tabDomId,
|
|
3682
|
+
panelDomId
|
|
3683
|
+
}) {
|
|
3684
|
+
const tabRefs = React.useRef({});
|
|
3685
|
+
const moveTo = (next) => {
|
|
3686
|
+
onSelect(next);
|
|
3687
|
+
tabRefs.current[next]?.focus();
|
|
3688
|
+
};
|
|
3689
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "tablist", "aria-label": "Message source", className: "flex shrink-0 gap-1 rounded-md bg-muted p-1", children: TABS.map((entry, index) => {
|
|
3690
|
+
const selected = entry.id === activeTab;
|
|
3691
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3692
|
+
"button",
|
|
3693
|
+
{
|
|
3694
|
+
ref: (node) => {
|
|
3695
|
+
tabRefs.current[entry.id] = node;
|
|
3696
|
+
},
|
|
3697
|
+
type: "button",
|
|
3698
|
+
role: "tab",
|
|
3699
|
+
id: tabDomId(entry.id),
|
|
3700
|
+
"aria-selected": selected,
|
|
3701
|
+
"aria-controls": panelDomId(entry.id),
|
|
3702
|
+
tabIndex: selected ? 0 : -1,
|
|
3703
|
+
onClick: () => onSelect(entry.id),
|
|
3704
|
+
onKeyDown: (e) => {
|
|
3705
|
+
if (e.key === "ArrowRight" || e.key === "ArrowLeft") {
|
|
3706
|
+
e.preventDefault();
|
|
3707
|
+
const delta = e.key === "ArrowRight" ? 1 : -1;
|
|
3708
|
+
moveTo(TABS[(index + delta + TABS.length) % TABS.length].id);
|
|
3709
|
+
} else if (e.key === "Home") {
|
|
3710
|
+
e.preventDefault();
|
|
3711
|
+
moveTo(TABS[0].id);
|
|
3712
|
+
} else if (e.key === "End") {
|
|
3713
|
+
e.preventDefault();
|
|
3714
|
+
moveTo(TABS[TABS.length - 1].id);
|
|
3715
|
+
}
|
|
3716
|
+
},
|
|
3717
|
+
className: cn(
|
|
3718
|
+
"flex-1 rounded-sm px-3 py-1.5 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
3719
|
+
selected ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
|
|
3720
|
+
),
|
|
3721
|
+
children: entry.label
|
|
3722
|
+
},
|
|
3723
|
+
entry.id
|
|
3724
|
+
);
|
|
3725
|
+
}) });
|
|
3726
|
+
}
|
|
3727
|
+
function PreviewPane({
|
|
3728
|
+
state,
|
|
3729
|
+
hooks,
|
|
3730
|
+
theme,
|
|
3731
|
+
emptyHint,
|
|
3732
|
+
signInPolling,
|
|
3733
|
+
onSignIn,
|
|
3734
|
+
onOpenAsNew
|
|
3735
|
+
}) {
|
|
3736
|
+
const target = state.kind === "ready" ? state.target : null;
|
|
3737
|
+
const signInUrl = state.kind === "not-editable" && state.oauthUrl && isSafeHref(state.oauthUrl) ? state.oauthUrl : null;
|
|
3738
|
+
const verdictBlocks = state.kind === "not-editable" ? state.blocks : void 0;
|
|
3739
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 shrink-0 flex-col gap-2 lg:min-h-0 lg:flex-1", children: [
|
|
3740
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 flex-wrap items-center gap-2", children: [
|
|
3741
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: "Preview" }),
|
|
3742
|
+
target?.channelName || target?.channelId ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded border px-1.5 py-px text-[10px] font-medium text-muted-foreground", children: target.channelName ? `#${target.channelName}` : target.channelId }) : null,
|
|
3743
|
+
target?.editableVia ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "rounded border px-1.5 py-px text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: [
|
|
3744
|
+
"Editable as ",
|
|
3745
|
+
editableLabel(target.editableVia)
|
|
3746
|
+
] }) : null
|
|
3747
|
+
] }),
|
|
3748
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3749
|
+
"div",
|
|
3750
|
+
{
|
|
3751
|
+
role: "region",
|
|
3752
|
+
"aria-label": "Message preview",
|
|
3753
|
+
tabIndex: 0,
|
|
3754
|
+
className: "flex flex-1 flex-col gap-3 overflow-y-auto rounded-md border bg-muted/40 p-3 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring max-lg:max-h-72 max-lg:min-h-32 lg:min-h-0",
|
|
3755
|
+
children: [
|
|
3756
|
+
state.kind === "not-editable" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 flex-col gap-2 rounded-md border border-amber-200! bg-amber-50 p-3 text-xs text-amber-800", children: [
|
|
3369
3757
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
|
|
3370
3758
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "mt-0.5 h-3.5 w-3.5 shrink-0" }),
|
|
3371
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children:
|
|
3759
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: state.reason })
|
|
3372
3760
|
] }),
|
|
3373
|
-
signInUrl && /* @__PURE__ */ jsxRuntime.jsx(SlackSignInButton, { onClick: () =>
|
|
3374
|
-
|
|
3761
|
+
signInUrl && /* @__PURE__ */ jsxRuntime.jsx(SlackSignInButton, { onClick: () => onSignIn(signInUrl), polling: signInPolling }),
|
|
3762
|
+
verdictBlocks && verdictBlocks.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3375
3763
|
Button,
|
|
3376
3764
|
{
|
|
3377
3765
|
type: "button",
|
|
3378
3766
|
variant: "outline",
|
|
3379
3767
|
size: "sm",
|
|
3380
3768
|
className: "self-start",
|
|
3381
|
-
onClick: () => onOpenAsNew(
|
|
3769
|
+
onClick: () => onOpenAsNew(verdictBlocks),
|
|
3382
3770
|
children: "Open as a new message instead"
|
|
3383
3771
|
}
|
|
3384
3772
|
)
|
|
3385
3773
|
] }),
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
channels === null && !channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Loading channels\u2026" }),
|
|
3395
|
-
channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive", children: channelsError }),
|
|
3396
|
-
channels && channels.length === 0 && !channelsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "No public channels available." }),
|
|
3397
|
-
channels && channels.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3398
|
-
"select",
|
|
3399
|
-
{
|
|
3400
|
-
id: "recent-channel-picker",
|
|
3401
|
-
value: channelId,
|
|
3402
|
-
onChange: (e) => setChannelId(e.target.value),
|
|
3403
|
-
className: "flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
3404
|
-
children: [
|
|
3405
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: "Select a channel\u2026" }),
|
|
3406
|
-
channels.map((c) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: c.id, children: [
|
|
3407
|
-
"#",
|
|
3408
|
-
c.name
|
|
3409
|
-
] }, c.id))
|
|
3410
|
-
]
|
|
3411
|
-
}
|
|
3412
|
-
)
|
|
3413
|
-
] }),
|
|
3414
|
-
!channelId && channels && channels.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Select a channel to see recent messages." }),
|
|
3415
|
-
channelId && recent === null && !recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Loading recent messages\u2026" }),
|
|
3416
|
-
channelId && recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive", children: recentError }),
|
|
3417
|
-
channelId && recent && recent.length === 0 && !recentError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "No recent messages from this app in this channel." }),
|
|
3418
|
-
channelId && recent && recent.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex max-h-48 min-w-0 flex-col gap-1 overflow-y-auto", children: recent.map((m) => {
|
|
3419
|
-
const asUser = (m.editableVia ?? "bot") === "user";
|
|
3420
|
-
const authorName = m.username || (asUser ? "You" : "App bot");
|
|
3421
|
-
const safeIcon = isSafeImageSrc(m.iconUrl) ? m.iconUrl : void 0;
|
|
3422
|
-
const isSelected = selectedRecent?.channelId === m.channelId && selectedRecent?.ts === m.ts;
|
|
3423
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3424
|
-
"button",
|
|
3425
|
-
{
|
|
3426
|
-
type: "button",
|
|
3427
|
-
"aria-pressed": isSelected,
|
|
3428
|
-
onClick: () => {
|
|
3429
|
-
setSelectedRecent(m);
|
|
3430
|
-
setLink("");
|
|
3431
|
-
if (status.kind !== "idle" && status.kind !== "loading") {
|
|
3432
|
-
setStatus({ kind: "idle" });
|
|
3433
|
-
}
|
|
3434
|
-
},
|
|
3435
|
-
className: cn(
|
|
3436
|
-
// Inset rings so the scroll container's overflow clip
|
|
3437
|
-
// can't shave the corners off the selected outline.
|
|
3438
|
-
"flex min-w-0 items-start gap-2.5 rounded-md border border-input bg-background px-3 py-2 text-left hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring",
|
|
3439
|
-
isSelected && "border-primary! bg-accent ring-1 ring-inset ring-primary"
|
|
3440
|
-
),
|
|
3441
|
-
children: [
|
|
3442
|
-
safeIcon ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: safeIcon, alt: "", className: "h-9 w-9 shrink-0 rounded-md object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3443
|
-
"span",
|
|
3444
|
-
{
|
|
3445
|
-
"aria-hidden": true,
|
|
3446
|
-
className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-muted text-sm font-semibold text-muted-foreground",
|
|
3447
|
-
children: authorName.charAt(0).toUpperCase()
|
|
3448
|
-
}
|
|
3449
|
-
),
|
|
3450
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col gap-0.5", children: [
|
|
3451
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
|
|
3452
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-semibold text-foreground", children: authorName }),
|
|
3453
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 rounded border px-1 py-px text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: asUser ? "You" : "Bot" })
|
|
3454
|
-
] }),
|
|
3455
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
3456
|
-
new Date(Number(m.ts) * 1e3).toLocaleString(),
|
|
3457
|
-
" ",
|
|
3458
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono", children: [
|
|
3459
|
-
"(",
|
|
3460
|
-
m.ts,
|
|
3461
|
-
")"
|
|
3462
|
-
] })
|
|
3463
|
-
] }),
|
|
3464
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-2 text-sm text-foreground", children: previewText(m) })
|
|
3465
|
-
] })
|
|
3466
|
-
]
|
|
3467
|
-
},
|
|
3468
|
-
`${m.channelId}:${m.ts}`
|
|
3469
|
-
);
|
|
3470
|
-
}) })
|
|
3471
|
-
] })
|
|
3472
|
-
] }),
|
|
3473
|
-
/* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { children: [
|
|
3474
|
-
/* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "ghost", onClick: () => onOpenChange(false), children: "Cancel" }),
|
|
3475
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3476
|
-
Button,
|
|
3774
|
+
state.kind === "error" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 rounded-md border border-destructive/30 bg-destructive/5 p-2 text-xs text-destructive", children: state.error }),
|
|
3775
|
+
state.kind === "loading" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "m-auto flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
3776
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
3777
|
+
"Looking up that message\u2026"
|
|
3778
|
+
] }),
|
|
3779
|
+
state.kind === "empty" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "m-auto px-4 text-center text-sm text-muted-foreground", children: emptyHint }),
|
|
3780
|
+
target && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3781
|
+
SlackMessagePreview,
|
|
3477
3782
|
{
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3783
|
+
blocks: target.blocks,
|
|
3784
|
+
hooks,
|
|
3785
|
+
theme,
|
|
3786
|
+
workspaceName: target.workspaceName,
|
|
3787
|
+
authorName: target.username,
|
|
3788
|
+
authorIcon: target.iconUrl,
|
|
3789
|
+
time: formatTs(target.ts)
|
|
3482
3790
|
}
|
|
3483
|
-
)
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3791
|
+
) }),
|
|
3792
|
+
verdictBlocks && verdictBlocks.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(SlackMessagePreview, { blocks: verdictBlocks, hooks, theme, time: "" }) })
|
|
3793
|
+
]
|
|
3794
|
+
}
|
|
3795
|
+
)
|
|
3796
|
+
] });
|
|
3488
3797
|
}
|
|
3489
3798
|
var PALETTE_DRAG_PREFIX = "palette:";
|
|
3490
3799
|
function parsePaletteDragId(id) {
|
|
@@ -8707,60 +9016,6 @@ function dispatch(block, onChange) {
|
|
|
8707
9016
|
return null;
|
|
8708
9017
|
}
|
|
8709
9018
|
}
|
|
8710
|
-
function SlackBlockPreview({
|
|
8711
|
-
block,
|
|
8712
|
-
hooks,
|
|
8713
|
-
theme = "light"
|
|
8714
|
-
}) {
|
|
8715
|
-
const rootRef = React.useRef(null);
|
|
8716
|
-
const safeBlock = React.useMemo(() => sanitizeBlock(block), [block]);
|
|
8717
|
-
React.useEffect(() => {
|
|
8718
|
-
const root = rootRef.current;
|
|
8719
|
-
if (!root) return;
|
|
8720
|
-
for (const wrapper of root.querySelectorAll(
|
|
8721
|
-
".slack_blocks_to_jsx__image_media_trigger, .slack_blocks_to_jsx__video_title"
|
|
8722
|
-
)) {
|
|
8723
|
-
for (const btn of wrapper.querySelectorAll("button:not([aria-label])")) {
|
|
8724
|
-
const title = wrapper.querySelector(".slack_blocks_to_jsx__image_title")?.textContent?.trim();
|
|
8725
|
-
btn.setAttribute("aria-label", title ? `Toggle ${title}` : "Toggle media");
|
|
8726
|
-
}
|
|
8727
|
-
}
|
|
8728
|
-
for (const a of root.querySelectorAll("a[href]")) {
|
|
8729
|
-
const href = a.getAttribute("href");
|
|
8730
|
-
if (!isSafeHref(href)) {
|
|
8731
|
-
a.setAttribute("href", "#");
|
|
8732
|
-
a.setAttribute("data-bk-blocked-href", "1");
|
|
8733
|
-
}
|
|
8734
|
-
}
|
|
8735
|
-
for (const img of root.querySelectorAll("img[src]")) {
|
|
8736
|
-
const src = img.getAttribute("src");
|
|
8737
|
-
if (!isSafeImageSrc(src)) {
|
|
8738
|
-
img.removeAttribute("src");
|
|
8739
|
-
img.setAttribute("data-bk-blocked-src", "1");
|
|
8740
|
-
}
|
|
8741
|
-
}
|
|
8742
|
-
});
|
|
8743
|
-
return (
|
|
8744
|
-
// The library scopes all of its CSS under `#slack_blocks_to_jsx` and
|
|
8745
|
-
// depends on the `slack_blocks_to_jsx styles_enabled` classes plus the
|
|
8746
|
-
// `data-theme` attribute for its button / mention / divider styling
|
|
8747
|
-
// (e.g. button reset + `bg-green-primary` for primary). `<Message
|
|
8748
|
-
// withoutWrapper>` skips that wrapper entirely, so we re-create it
|
|
8749
|
-
// here without the avatar / timestamp chrome.
|
|
8750
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: rootRef, id: "slack_blocks_to_jsx", "data-theme": theme, className: "slack_blocks_to_jsx styles_enabled", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8751
|
-
slackBlocksToJsx.Message,
|
|
8752
|
-
{
|
|
8753
|
-
time: /* @__PURE__ */ new Date(),
|
|
8754
|
-
name: "",
|
|
8755
|
-
logo: "",
|
|
8756
|
-
withoutWrapper: true,
|
|
8757
|
-
theme,
|
|
8758
|
-
blocks: [safeBlock],
|
|
8759
|
-
hooks
|
|
8760
|
-
}
|
|
8761
|
-
) })
|
|
8762
|
-
);
|
|
8763
|
-
}
|
|
8764
9019
|
var BLOCK_TYPE_LABELS = {
|
|
8765
9020
|
section: "Section",
|
|
8766
9021
|
header: "Header",
|
|
@@ -9383,50 +9638,16 @@ function Surface({
|
|
|
9383
9638
|
{
|
|
9384
9639
|
"aria-label": "Block preview",
|
|
9385
9640
|
className: cn("flex min-w-0 flex-1 flex-col overflow-y-auto bg-muted p-3 sm:p-6"),
|
|
9386
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-2xl", children: previewSurface === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(ModalFrame, { isDark, children: blocksList }) : previewSurface === "app_home" ? /* @__PURE__ */ jsxRuntime.jsx(AppHomeFrame, { workspaceName, isDark, children: blocksList }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
9387
|
-
|
|
9388
|
-
|
|
9389
|
-
|
|
9390
|
-
|
|
9391
|
-
|
|
9392
|
-
|
|
9393
|
-
|
|
9394
|
-
|
|
9395
|
-
|
|
9396
|
-
}) {
|
|
9397
|
-
const displayName = authorName ?? workspaceName ?? "Your app";
|
|
9398
|
-
const initial = displayName.slice(0, 1).toUpperCase();
|
|
9399
|
-
const safeIcon = authorIcon && isSafeImageSrc(authorIcon) ? authorIcon : null;
|
|
9400
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9401
|
-
"div",
|
|
9402
|
-
{
|
|
9403
|
-
className: cn(
|
|
9404
|
-
"flex flex-col overflow-hidden rounded-md border",
|
|
9405
|
-
isDark ? "border-[#2c2d30] bg-[#1a1d21]" : "border-[#e8e8e8] bg-white"
|
|
9406
|
-
),
|
|
9407
|
-
children: [
|
|
9408
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9409
|
-
"div",
|
|
9410
|
-
{
|
|
9411
|
-
className: cn("flex items-center gap-2 px-5 pt-3 pb-1 text-xs", isDark ? "text-white/60" : "text-[#616061]"),
|
|
9412
|
-
children: [
|
|
9413
|
-
safeIcon ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: safeIcon, alt: "", className: "h-7 w-7 shrink-0 rounded object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
9414
|
-
"span",
|
|
9415
|
-
{
|
|
9416
|
-
className: cn(
|
|
9417
|
-
"inline-flex h-7 w-7 items-center justify-center rounded text-[12px] font-semibold",
|
|
9418
|
-
isDark ? "bg-white/10 text-white" : "bg-[#4a154b]/10 text-[#1d1c1d]"
|
|
9419
|
-
),
|
|
9420
|
-
children: initial
|
|
9421
|
-
}
|
|
9422
|
-
),
|
|
9423
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-bold text-sm", isDark ? "text-white" : "text-[#1d1c1d]"), children: displayName }),
|
|
9424
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "10:37 AM" })
|
|
9425
|
-
]
|
|
9426
|
-
}
|
|
9427
|
-
),
|
|
9428
|
-
children
|
|
9429
|
-
]
|
|
9641
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-2xl", children: previewSurface === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(ModalFrame, { isDark, children: blocksList }) : previewSurface === "app_home" ? /* @__PURE__ */ jsxRuntime.jsx(AppHomeFrame, { workspaceName, isDark, children: blocksList }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
9642
|
+
SlackMessageFrame,
|
|
9643
|
+
{
|
|
9644
|
+
workspaceName,
|
|
9645
|
+
authorName,
|
|
9646
|
+
authorIcon,
|
|
9647
|
+
isDark,
|
|
9648
|
+
children: blocksList
|
|
9649
|
+
}
|
|
9650
|
+
) })
|
|
9430
9651
|
}
|
|
9431
9652
|
);
|
|
9432
9653
|
}
|
|
@@ -10515,6 +10736,8 @@ function BlockKitchen(props) {
|
|
|
10515
10736
|
onLoadMessage: loading.onLoadMessage,
|
|
10516
10737
|
loadRecentMessages: loading.loadRecentMessages,
|
|
10517
10738
|
loadChannels: recentChannelSource,
|
|
10739
|
+
previewHooks: mergedPreviewHooks,
|
|
10740
|
+
previewTheme,
|
|
10518
10741
|
onLoaded: (result) => {
|
|
10519
10742
|
resetAll(result.blocks);
|
|
10520
10743
|
setEditTarget(toLoadedMessage(result));
|