discord2html 1.0.0
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/LICENSE +201 -0
- package/README.md +139 -0
- package/dist/chunk-3GDQP6AS.mjs +16 -0
- package/dist/chunk-3GDQP6AS.mjs.map +1 -0
- package/dist/index.d.mts +147 -0
- package/dist/index.d.ts +147 -0
- package/dist/index.js +7961 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1365 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lib-V24P5ASW.mjs +6588 -0
- package/dist/lib-V24P5ASW.mjs.map +1 -0
- package/package.json +87 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1365 @@
|
|
|
1
|
+
import "./chunk-3GDQP6AS.mjs";
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { AttachmentBuilder, version, Collection } from "discord.js";
|
|
5
|
+
|
|
6
|
+
// src/generator/index.tsx
|
|
7
|
+
import { prerenderToNodeStream } from "react-dom/static";
|
|
8
|
+
import React18 from "react";
|
|
9
|
+
|
|
10
|
+
// src/utils/buildProfiles.ts
|
|
11
|
+
import { UserFlags } from "discord.js";
|
|
12
|
+
async function buildProfiles(messages) {
|
|
13
|
+
const profiles = {};
|
|
14
|
+
for (const message of messages) {
|
|
15
|
+
const author = message.author;
|
|
16
|
+
if (!profiles[author.id]) {
|
|
17
|
+
profiles[author.id] = buildProfile(message.member, author);
|
|
18
|
+
}
|
|
19
|
+
if (message.interaction) {
|
|
20
|
+
const user = message.interaction.user;
|
|
21
|
+
if (!profiles[user.id]) {
|
|
22
|
+
profiles[user.id] = buildProfile(null, user);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (message.thread && message.thread.lastMessage) {
|
|
26
|
+
profiles[message.thread.lastMessage.author.id] = buildProfile(
|
|
27
|
+
message.thread.lastMessage.member,
|
|
28
|
+
message.thread.lastMessage.author
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return profiles;
|
|
33
|
+
}
|
|
34
|
+
function buildProfile(member, author) {
|
|
35
|
+
return {
|
|
36
|
+
author: member?.nickname ?? author.displayName ?? author.username,
|
|
37
|
+
avatar: member?.displayAvatarURL({ size: 64 }) ?? author.displayAvatarURL({ size: 64 }),
|
|
38
|
+
roleColor: member?.displayHexColor,
|
|
39
|
+
roleIcon: member?.roles.icon?.iconURL() ?? void 0,
|
|
40
|
+
roleName: member?.roles.hoist?.name ?? void 0,
|
|
41
|
+
bot: author.bot,
|
|
42
|
+
verified: author.flags?.has(UserFlags.VerifiedBot)
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/static/client.ts
|
|
47
|
+
var scrollToMessage = 'document.addEventListener("click",t=>{let e=t.target;if(!e)return;let o=e?.getAttribute("data-goto");if(o){let r=document.getElementById(`m-${o}`);r?(r.scrollIntoView({behavior:"smooth",block:"center"}),r.style.backgroundColor="rgba(148, 156, 247, 0.1)",r.style.transition="background-color 0.5s ease",setTimeout(()=>{r.style.backgroundColor="transparent"},1e3)):console.warn("Message ${goto} not found.")}});';
|
|
48
|
+
var revealSpoiler = 'const s=document.querySelectorAll(".discord-spoiler");s.forEach(s=>s.addEventListener("click",()=>{if(s.classList.contains("discord-spoiler")){s.classList.remove("discord-spoiler");s.classList.add("discord-spoiler--revealed");}}));';
|
|
49
|
+
|
|
50
|
+
// src/generator/index.tsx
|
|
51
|
+
import { readFileSync } from "fs";
|
|
52
|
+
import path from "path";
|
|
53
|
+
import { renderToString } from "@derockdev/discord-components-core/hydrate";
|
|
54
|
+
|
|
55
|
+
// src/generator/transcript.tsx
|
|
56
|
+
import { DiscordHeader, DiscordMessages as DiscordMessagesComponent } from "@derockdev/discord-components-react";
|
|
57
|
+
import { ChannelType as ChannelType2 } from "discord.js";
|
|
58
|
+
import React17 from "react";
|
|
59
|
+
|
|
60
|
+
// src/generator/renderers/content.tsx
|
|
61
|
+
import {
|
|
62
|
+
DiscordBold,
|
|
63
|
+
DiscordCodeBlock,
|
|
64
|
+
DiscordCustomEmoji,
|
|
65
|
+
DiscordInlineCode,
|
|
66
|
+
DiscordItalic,
|
|
67
|
+
DiscordMention,
|
|
68
|
+
DiscordQuote,
|
|
69
|
+
DiscordSpoiler,
|
|
70
|
+
DiscordTime,
|
|
71
|
+
DiscordUnderlined
|
|
72
|
+
} from "@derockdev/discord-components-react";
|
|
73
|
+
import parse from "discord-markdown-parser";
|
|
74
|
+
import { ChannelType } from "discord.js";
|
|
75
|
+
import React from "react";
|
|
76
|
+
|
|
77
|
+
// src/utils/utils.ts
|
|
78
|
+
import twemoji from "twemoji";
|
|
79
|
+
function formatBytes(bytes, decimals = 2) {
|
|
80
|
+
if (bytes === 0) return "0 Bytes";
|
|
81
|
+
const k = 1024;
|
|
82
|
+
const dm = decimals < 0 ? 0 : decimals;
|
|
83
|
+
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
84
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
85
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
|
86
|
+
}
|
|
87
|
+
function parseDiscordEmoji(emoji) {
|
|
88
|
+
if (emoji.id) {
|
|
89
|
+
return `https://cdn.discordapp.com/emojis/${emoji.id}.${emoji.animated ? "gif" : "png"}`;
|
|
90
|
+
}
|
|
91
|
+
const codepoints = twemoji.convert.toCodePoint(
|
|
92
|
+
emoji.name.indexOf(String.fromCharCode(8205)) < 0 ? emoji.name.replace(/\uFE0F/g, "") : emoji.name
|
|
93
|
+
).toLowerCase();
|
|
94
|
+
return `https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/svg/${codepoints}.svg`;
|
|
95
|
+
}
|
|
96
|
+
function streamToString(stream) {
|
|
97
|
+
const chunks = [];
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
stream.on("data", (chunk) => chunks.push(chunk));
|
|
100
|
+
stream.on("error", reject);
|
|
101
|
+
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/generator/renderers/content.tsx
|
|
106
|
+
async function MessageContent({ content, context }) {
|
|
107
|
+
if (context.type === 1 /* REPLY */ && content.length > 180) content = content.slice(0, 180) + "...";
|
|
108
|
+
const parsed = parse(
|
|
109
|
+
content,
|
|
110
|
+
context.type === 0 /* EMBED */ || context.type === 3 /* WEBHOOK */ ? "extended" : "normal"
|
|
111
|
+
);
|
|
112
|
+
const isOnlyEmojis = parsed.every(
|
|
113
|
+
(node) => ["emoji", "twemoji"].includes(node.type) || node.type === "text" && node.content.trim().length === 0
|
|
114
|
+
);
|
|
115
|
+
if (isOnlyEmojis) {
|
|
116
|
+
const emojis = parsed.filter((node) => ["emoji", "twemoji"].includes(node.type));
|
|
117
|
+
if (emojis.length <= 25) {
|
|
118
|
+
context._internal = {
|
|
119
|
+
largeEmojis: true
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return /* @__PURE__ */ React.createElement(MessageASTNodes, { nodes: parsed, context });
|
|
124
|
+
}
|
|
125
|
+
async function MessageASTNodes({
|
|
126
|
+
nodes,
|
|
127
|
+
context
|
|
128
|
+
}) {
|
|
129
|
+
if (Array.isArray(nodes)) {
|
|
130
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, nodes.map((node, i) => /* @__PURE__ */ React.createElement(MessageSingleASTNode, { node, context, key: i })));
|
|
131
|
+
} else {
|
|
132
|
+
return /* @__PURE__ */ React.createElement(MessageSingleASTNode, { node: nodes, context });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function MessageSingleASTNode({ node, context }) {
|
|
136
|
+
if (!node) return null;
|
|
137
|
+
const type = node.type;
|
|
138
|
+
switch (type) {
|
|
139
|
+
case "text":
|
|
140
|
+
return node.content;
|
|
141
|
+
case "link":
|
|
142
|
+
return /* @__PURE__ */ React.createElement("a", { href: node.target }, /* @__PURE__ */ React.createElement(MessageASTNodes, { nodes: node.content, context }));
|
|
143
|
+
case "url":
|
|
144
|
+
case "autolink":
|
|
145
|
+
return /* @__PURE__ */ React.createElement("a", { href: node.target, target: "_blank", rel: "noreferrer" }, /* @__PURE__ */ React.createElement(MessageASTNodes, { nodes: node.content, context }));
|
|
146
|
+
case "blockQuote":
|
|
147
|
+
if (context.type === 1 /* REPLY */) {
|
|
148
|
+
return /* @__PURE__ */ React.createElement(MessageASTNodes, { nodes: node.content, context });
|
|
149
|
+
}
|
|
150
|
+
return /* @__PURE__ */ React.createElement(DiscordQuote, null, /* @__PURE__ */ React.createElement(MessageASTNodes, { nodes: node.content, context }));
|
|
151
|
+
case "br":
|
|
152
|
+
case "newline":
|
|
153
|
+
if (context.type === 1 /* REPLY */) return " ";
|
|
154
|
+
return /* @__PURE__ */ React.createElement("br", null);
|
|
155
|
+
case "channel": {
|
|
156
|
+
const id = node.id;
|
|
157
|
+
const channel = await context.callbacks.resolveChannel(id);
|
|
158
|
+
return /* @__PURE__ */ React.createElement(DiscordMention, { type: channel ? channel.isDMBased() ? "channel" : getChannelType(channel.type) : "channel" }, channel ? channel.isDMBased() ? "DM Channel" : channel.name : `<#${id}>`);
|
|
159
|
+
}
|
|
160
|
+
case "role": {
|
|
161
|
+
const id = node.id;
|
|
162
|
+
const role = await context.callbacks.resolveRole(id);
|
|
163
|
+
return /* @__PURE__ */ React.createElement(DiscordMention, { type: "role", color: context.type === 1 /* REPLY */ ? void 0 : role?.hexColor }, role ? role.name : `<@&${id}>`);
|
|
164
|
+
}
|
|
165
|
+
case "user": {
|
|
166
|
+
const id = node.id;
|
|
167
|
+
const user = await context.callbacks.resolveUser(id);
|
|
168
|
+
return /* @__PURE__ */ React.createElement(DiscordMention, { type: "user" }, user ? user.displayName ?? user.username : `<@${id}>`);
|
|
169
|
+
}
|
|
170
|
+
case "here":
|
|
171
|
+
case "everyone":
|
|
172
|
+
return /* @__PURE__ */ React.createElement(DiscordMention, { type: "role", highlight: true }, `@${type}`);
|
|
173
|
+
case "codeBlock":
|
|
174
|
+
if (context.type !== 1 /* REPLY */) {
|
|
175
|
+
return /* @__PURE__ */ React.createElement(DiscordCodeBlock, { language: node.lang, code: node.content });
|
|
176
|
+
}
|
|
177
|
+
return /* @__PURE__ */ React.createElement(DiscordInlineCode, null, node.content);
|
|
178
|
+
case "inlineCode":
|
|
179
|
+
return /* @__PURE__ */ React.createElement(DiscordInlineCode, null, node.content);
|
|
180
|
+
case "em":
|
|
181
|
+
return /* @__PURE__ */ React.createElement(DiscordItalic, null, /* @__PURE__ */ React.createElement(MessageASTNodes, { nodes: node.content, context }));
|
|
182
|
+
case "strong":
|
|
183
|
+
return /* @__PURE__ */ React.createElement(DiscordBold, null, /* @__PURE__ */ React.createElement(MessageASTNodes, { nodes: node.content, context }));
|
|
184
|
+
case "underline":
|
|
185
|
+
return /* @__PURE__ */ React.createElement(DiscordUnderlined, null, /* @__PURE__ */ React.createElement(MessageASTNodes, { nodes: node.content, context }));
|
|
186
|
+
case "strikethrough":
|
|
187
|
+
return /* @__PURE__ */ React.createElement("s", null, /* @__PURE__ */ React.createElement(MessageASTNodes, { nodes: node.content, context }));
|
|
188
|
+
case "emoticon":
|
|
189
|
+
return typeof node.content === "string" ? node.content : /* @__PURE__ */ React.createElement(MessageASTNodes, { nodes: node.content, context });
|
|
190
|
+
case "spoiler":
|
|
191
|
+
return /* @__PURE__ */ React.createElement(DiscordSpoiler, null, /* @__PURE__ */ React.createElement(MessageASTNodes, { nodes: node.content, context }));
|
|
192
|
+
case "emoji":
|
|
193
|
+
case "twemoji":
|
|
194
|
+
return /* @__PURE__ */ React.createElement(
|
|
195
|
+
DiscordCustomEmoji,
|
|
196
|
+
{
|
|
197
|
+
name: node.name,
|
|
198
|
+
url: parseDiscordEmoji(node),
|
|
199
|
+
embedEmoji: context.type === 0 /* EMBED */,
|
|
200
|
+
largeEmoji: context._internal?.largeEmojis
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
case "timestamp":
|
|
204
|
+
return /* @__PURE__ */ React.createElement(DiscordTime, { timestamp: parseInt(node.timestamp) * 1e3, format: node.format });
|
|
205
|
+
default: {
|
|
206
|
+
console.log(`Unknown node type: ${type}`, node);
|
|
207
|
+
return typeof node.content === "string" ? node.content : /* @__PURE__ */ React.createElement(MessageASTNodes, { nodes: node.content, context });
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function getChannelType(channelType) {
|
|
212
|
+
switch (channelType) {
|
|
213
|
+
case ChannelType.GuildCategory:
|
|
214
|
+
case ChannelType.GuildAnnouncement:
|
|
215
|
+
case ChannelType.GuildText:
|
|
216
|
+
case ChannelType.DM:
|
|
217
|
+
case ChannelType.GroupDM:
|
|
218
|
+
case ChannelType.GuildDirectory:
|
|
219
|
+
case ChannelType.GuildMedia:
|
|
220
|
+
return "channel";
|
|
221
|
+
case ChannelType.GuildVoice:
|
|
222
|
+
case ChannelType.GuildStageVoice:
|
|
223
|
+
return "voice";
|
|
224
|
+
case ChannelType.PublicThread:
|
|
225
|
+
case ChannelType.PrivateThread:
|
|
226
|
+
case ChannelType.AnnouncementThread:
|
|
227
|
+
return "thread";
|
|
228
|
+
case ChannelType.GuildForum:
|
|
229
|
+
return "forum";
|
|
230
|
+
default:
|
|
231
|
+
return "channel";
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/generator/renderers/message.tsx
|
|
236
|
+
import {
|
|
237
|
+
DiscordAttachments as DiscordAttachments2,
|
|
238
|
+
DiscordCommand,
|
|
239
|
+
DiscordMessage as DiscordMessageComponent,
|
|
240
|
+
DiscordReaction as DiscordReaction2,
|
|
241
|
+
DiscordReactions as DiscordReactions2,
|
|
242
|
+
DiscordThread,
|
|
243
|
+
DiscordThreadMessage
|
|
244
|
+
} from "@derockdev/discord-components-react";
|
|
245
|
+
import React16 from "react";
|
|
246
|
+
|
|
247
|
+
// src/generator/renderers/attachment.tsx
|
|
248
|
+
import { DiscordAttachment, DiscordAttachments } from "@derockdev/discord-components-react";
|
|
249
|
+
import React2 from "react";
|
|
250
|
+
async function Attachments(props) {
|
|
251
|
+
if (props.message.attachments.size === 0) return /* @__PURE__ */ React2.createElement(React2.Fragment, null);
|
|
252
|
+
return /* @__PURE__ */ React2.createElement(DiscordAttachments, { slot: "attachments" }, props.message.attachments.map((attachment, id) => /* @__PURE__ */ React2.createElement(Attachment, { attachment, message: props.message, context: props.context, key: id })));
|
|
253
|
+
}
|
|
254
|
+
function getAttachmentType(attachment) {
|
|
255
|
+
const type = attachment.contentType?.split("/")?.[0] ?? "unknown";
|
|
256
|
+
if (["audio", "video", "image"].includes(type)) return type;
|
|
257
|
+
return "file";
|
|
258
|
+
}
|
|
259
|
+
async function Attachment({
|
|
260
|
+
attachment,
|
|
261
|
+
context,
|
|
262
|
+
message
|
|
263
|
+
}) {
|
|
264
|
+
let url = attachment.url;
|
|
265
|
+
const name = attachment.name;
|
|
266
|
+
const width = attachment.width;
|
|
267
|
+
const height = attachment.height;
|
|
268
|
+
const type = getAttachmentType(attachment);
|
|
269
|
+
if (type === "image") {
|
|
270
|
+
const downloaded = await context.callbacks.resolveImageSrc(
|
|
271
|
+
attachment.toJSON(),
|
|
272
|
+
message.toJSON()
|
|
273
|
+
);
|
|
274
|
+
if (downloaded !== null) {
|
|
275
|
+
url = downloaded ?? url;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return /* @__PURE__ */ React2.createElement(
|
|
279
|
+
DiscordAttachment,
|
|
280
|
+
{
|
|
281
|
+
type,
|
|
282
|
+
size: formatBytes(attachment.size),
|
|
283
|
+
key: attachment.id,
|
|
284
|
+
slot: "attachment",
|
|
285
|
+
url,
|
|
286
|
+
alt: name ?? void 0,
|
|
287
|
+
width: width ?? void 0,
|
|
288
|
+
height: height ?? void 0
|
|
289
|
+
}
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// src/generator/renderers/components.tsx
|
|
294
|
+
import { DiscordActionRow, DiscordAttachment as DiscordAttachment2, DiscordSpoiler as DiscordSpoiler2 } from "@derockdev/discord-components-react";
|
|
295
|
+
import {
|
|
296
|
+
ComponentType as ComponentType3
|
|
297
|
+
} from "discord.js";
|
|
298
|
+
import React12 from "react";
|
|
299
|
+
|
|
300
|
+
// src/generator/renderers/components/Select Menu.tsx
|
|
301
|
+
import React3 from "react";
|
|
302
|
+
import { ComponentType as ComponentType2 } from "discord.js";
|
|
303
|
+
|
|
304
|
+
// src/generator/renderers/components/utils.ts
|
|
305
|
+
import { ComponentType } from "discord.js";
|
|
306
|
+
|
|
307
|
+
// src/generator/renderers/components/styles.ts
|
|
308
|
+
import { ButtonStyle } from "discord.js";
|
|
309
|
+
var containerStyle = {
|
|
310
|
+
display: "grid",
|
|
311
|
+
gap: "4px",
|
|
312
|
+
width: "100%",
|
|
313
|
+
maxWidth: "500px",
|
|
314
|
+
borderRadius: "8px",
|
|
315
|
+
overflow: "hidden"
|
|
316
|
+
};
|
|
317
|
+
var baseImageStyle = {
|
|
318
|
+
overflow: "hidden",
|
|
319
|
+
position: "relative",
|
|
320
|
+
background: "#2b2d31"
|
|
321
|
+
};
|
|
322
|
+
var ButtonStyleMapping = {
|
|
323
|
+
[ButtonStyle.Primary]: "primary",
|
|
324
|
+
[ButtonStyle.Secondary]: "secondary",
|
|
325
|
+
[ButtonStyle.Success]: "success",
|
|
326
|
+
[ButtonStyle.Danger]: "destructive",
|
|
327
|
+
[ButtonStyle.Link]: "secondary",
|
|
328
|
+
[ButtonStyle.Premium]: "primary"
|
|
329
|
+
};
|
|
330
|
+
var globalStyles = `
|
|
331
|
+
.discord-container {
|
|
332
|
+
display: grid;
|
|
333
|
+
gap: 4px;
|
|
334
|
+
width: 100%;
|
|
335
|
+
max-width: 500px;
|
|
336
|
+
border-radius: 8px;
|
|
337
|
+
overflow: hidden;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.discord-base-image {
|
|
341
|
+
overflow: hidden;
|
|
342
|
+
position: relative;
|
|
343
|
+
background: #2b2d31;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.discord-button {
|
|
347
|
+
color: #ffffff !important;
|
|
348
|
+
padding: 2px 16px;
|
|
349
|
+
border-radius: 8px;
|
|
350
|
+
text-decoration: none !important;
|
|
351
|
+
display: inline-flex;
|
|
352
|
+
align-items: center;
|
|
353
|
+
justify-content: center;
|
|
354
|
+
font-size: 14px;
|
|
355
|
+
font-weight: 500;
|
|
356
|
+
height: 32px;
|
|
357
|
+
min-height: 32px;
|
|
358
|
+
min-width: 60px;
|
|
359
|
+
cursor: pointer;
|
|
360
|
+
font-family: Whitney, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
361
|
+
text-align: center;
|
|
362
|
+
box-sizing: border-box;
|
|
363
|
+
border: none;
|
|
364
|
+
outline: none;
|
|
365
|
+
transition: background-color 0.2s ease;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.discord-button-primary {
|
|
369
|
+
background-color: hsl(234.935 calc(1*85.556%) 64.706% /1);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.discord-button-secondary {
|
|
373
|
+
background-color: hsl(240 calc(1*4%) 60.784% /0.12156862745098039);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.discord-button-success {
|
|
377
|
+
background-color: hsl(145.97 calc(1*100%) 26.275% /1);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.discord-button-destructive {
|
|
381
|
+
background-color: hsl(355.636 calc(1*64.706%) 50% /1);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.discord-select-menu {
|
|
385
|
+
margin-top: 2px;
|
|
386
|
+
margin-bottom: 2px;
|
|
387
|
+
position: relative;
|
|
388
|
+
width: 100%;
|
|
389
|
+
max-width: 500px;
|
|
390
|
+
height: 40px;
|
|
391
|
+
background-color: #2b2d31;
|
|
392
|
+
border-radius: 4px;
|
|
393
|
+
color: #b5bac1;
|
|
394
|
+
cursor: pointer;
|
|
395
|
+
font-family: Whitney, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
396
|
+
font-size: 14px;
|
|
397
|
+
display: flex;
|
|
398
|
+
align-items: center;
|
|
399
|
+
padding: 0 8px;
|
|
400
|
+
justify-content: space-between;
|
|
401
|
+
box-sizing: border-box;
|
|
402
|
+
border: 1px solid #1e1f22;
|
|
403
|
+
}
|
|
404
|
+
`;
|
|
405
|
+
|
|
406
|
+
// src/generator/renderers/components/utils.ts
|
|
407
|
+
var SELECT_LABEL_MAP = {
|
|
408
|
+
[ComponentType.UserSelect]: "Select User",
|
|
409
|
+
[ComponentType.RoleSelect]: "Select Role",
|
|
410
|
+
[ComponentType.MentionableSelect]: "Select Mentionable",
|
|
411
|
+
[ComponentType.ChannelSelect]: "Select Channel",
|
|
412
|
+
[ComponentType.StringSelect]: "Make a Selection"
|
|
413
|
+
};
|
|
414
|
+
function getSelectTypeLabel(type) {
|
|
415
|
+
return SELECT_LABEL_MAP[type] ?? "Select Option";
|
|
416
|
+
}
|
|
417
|
+
function getGalleryLayout(count) {
|
|
418
|
+
switch (count) {
|
|
419
|
+
case 1:
|
|
420
|
+
return {
|
|
421
|
+
...containerStyle,
|
|
422
|
+
gridTemplateColumns: "1fr",
|
|
423
|
+
gridTemplateRows: "auto"
|
|
424
|
+
};
|
|
425
|
+
case 2:
|
|
426
|
+
return {
|
|
427
|
+
...containerStyle,
|
|
428
|
+
gridTemplateColumns: "1fr 1fr",
|
|
429
|
+
gridTemplateRows: "auto"
|
|
430
|
+
};
|
|
431
|
+
case 3:
|
|
432
|
+
case 4:
|
|
433
|
+
return {
|
|
434
|
+
...containerStyle,
|
|
435
|
+
gridTemplateColumns: "1fr 1fr",
|
|
436
|
+
gridTemplateRows: "1fr 1fr"
|
|
437
|
+
};
|
|
438
|
+
case 5:
|
|
439
|
+
return {
|
|
440
|
+
...containerStyle,
|
|
441
|
+
gridTemplateColumns: "1fr 1fr 1fr",
|
|
442
|
+
gridTemplateRows: "auto auto"
|
|
443
|
+
};
|
|
444
|
+
default:
|
|
445
|
+
if (count >= 7) {
|
|
446
|
+
return {
|
|
447
|
+
...containerStyle,
|
|
448
|
+
gridTemplateColumns: "1fr 1fr 1fr",
|
|
449
|
+
gridTemplateRows: "auto auto auto auto"
|
|
450
|
+
};
|
|
451
|
+
} else {
|
|
452
|
+
return {
|
|
453
|
+
...containerStyle,
|
|
454
|
+
gridTemplateColumns: "1fr 1fr 1fr",
|
|
455
|
+
gridTemplateRows: "auto"
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
function getImageStyle(idx, count) {
|
|
461
|
+
switch (count) {
|
|
462
|
+
case 3:
|
|
463
|
+
if (idx === 0) {
|
|
464
|
+
return {
|
|
465
|
+
...baseImageStyle,
|
|
466
|
+
gridRow: "1 / span 2",
|
|
467
|
+
gridColumn: "1",
|
|
468
|
+
aspectRatio: "1/2"
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
break;
|
|
472
|
+
case 5:
|
|
473
|
+
if (idx < 2) {
|
|
474
|
+
return {
|
|
475
|
+
...baseImageStyle,
|
|
476
|
+
gridRow: "1",
|
|
477
|
+
gridColumn: idx === 0 ? "1 / span 2" : "3"
|
|
478
|
+
};
|
|
479
|
+
} else {
|
|
480
|
+
return {
|
|
481
|
+
...baseImageStyle,
|
|
482
|
+
gridRow: "2",
|
|
483
|
+
gridColumn: `${idx - 2 + 1}`
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
case 7:
|
|
487
|
+
if (idx === 0) {
|
|
488
|
+
return {
|
|
489
|
+
...baseImageStyle,
|
|
490
|
+
gridRow: "1",
|
|
491
|
+
gridColumn: "1 / span 3"
|
|
492
|
+
};
|
|
493
|
+
} else if (idx <= 3) {
|
|
494
|
+
return {
|
|
495
|
+
...baseImageStyle,
|
|
496
|
+
gridRow: "2",
|
|
497
|
+
gridColumn: `${idx - 0}`
|
|
498
|
+
};
|
|
499
|
+
} else {
|
|
500
|
+
return {
|
|
501
|
+
...baseImageStyle,
|
|
502
|
+
gridRow: "3",
|
|
503
|
+
gridColumn: `${idx - 3}`
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
case 8:
|
|
507
|
+
if (idx < 2) {
|
|
508
|
+
return {
|
|
509
|
+
...baseImageStyle,
|
|
510
|
+
gridRow: "1",
|
|
511
|
+
gridColumn: idx === 0 ? "1 / span 2" : "3"
|
|
512
|
+
};
|
|
513
|
+
} else if (idx < 5) {
|
|
514
|
+
return {
|
|
515
|
+
...baseImageStyle,
|
|
516
|
+
gridRow: "2",
|
|
517
|
+
gridColumn: `${idx - 2 + 1}`
|
|
518
|
+
};
|
|
519
|
+
} else {
|
|
520
|
+
return {
|
|
521
|
+
...baseImageStyle,
|
|
522
|
+
gridRow: "3",
|
|
523
|
+
gridColumn: `${idx - 5 + 1}`
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
case 10:
|
|
527
|
+
if (idx === 0) {
|
|
528
|
+
return {
|
|
529
|
+
...baseImageStyle,
|
|
530
|
+
gridRow: "1",
|
|
531
|
+
gridColumn: "1 / span 3"
|
|
532
|
+
};
|
|
533
|
+
} else if (idx <= 3) {
|
|
534
|
+
return {
|
|
535
|
+
...baseImageStyle,
|
|
536
|
+
gridRow: "2",
|
|
537
|
+
gridColumn: `${idx - 0}`
|
|
538
|
+
};
|
|
539
|
+
} else if (idx <= 6) {
|
|
540
|
+
return {
|
|
541
|
+
...baseImageStyle,
|
|
542
|
+
gridRow: "3",
|
|
543
|
+
gridColumn: `${idx - 3}`
|
|
544
|
+
};
|
|
545
|
+
} else {
|
|
546
|
+
return {
|
|
547
|
+
...baseImageStyle,
|
|
548
|
+
gridRow: "4",
|
|
549
|
+
gridColumn: `${idx - 6}`
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return baseImageStyle;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// src/generator/renderers/components/Select Menu.tsx
|
|
557
|
+
function DiscordSelectMenu({
|
|
558
|
+
component
|
|
559
|
+
}) {
|
|
560
|
+
const isStringSelect = component.type === ComponentType2.StringSelect;
|
|
561
|
+
const placeholder = component.placeholder || getSelectTypeLabel(component.type);
|
|
562
|
+
return /* @__PURE__ */ React3.createElement("div", { className: "discord-select-menu" }, /* @__PURE__ */ React3.createElement("div", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, placeholder), /* @__PURE__ */ React3.createElement("div", { style: { display: "flex", alignItems: "center", marginLeft: "8px" } }, /* @__PURE__ */ React3.createElement("svg", { width: "24", height: "24", viewBox: "0 0 24 24" }, /* @__PURE__ */ React3.createElement("path", { fill: "currentColor", d: "M7 10L12 15L17 10H7Z" }))), isStringSelect && component.options && component.options.length > 0 && /* @__PURE__ */ React3.createElement(
|
|
563
|
+
"div",
|
|
564
|
+
{
|
|
565
|
+
style: {
|
|
566
|
+
display: "none",
|
|
567
|
+
position: "absolute",
|
|
568
|
+
top: "44px",
|
|
569
|
+
left: "0",
|
|
570
|
+
width: "100%",
|
|
571
|
+
backgroundColor: "#2b2d31",
|
|
572
|
+
borderRadius: "4px",
|
|
573
|
+
zIndex: 10,
|
|
574
|
+
border: "1px solid #1e1f22",
|
|
575
|
+
maxHeight: "320px",
|
|
576
|
+
overflowY: "auto"
|
|
577
|
+
}
|
|
578
|
+
},
|
|
579
|
+
component.options.map((option, idx) => /* @__PURE__ */ React3.createElement(
|
|
580
|
+
"div",
|
|
581
|
+
{
|
|
582
|
+
key: idx,
|
|
583
|
+
style: {
|
|
584
|
+
padding: "8px 12px",
|
|
585
|
+
cursor: "pointer",
|
|
586
|
+
display: "flex",
|
|
587
|
+
alignItems: "center",
|
|
588
|
+
borderBottom: idx < component.options.length - 1 ? "1px solid #1e1f22" : "none"
|
|
589
|
+
}
|
|
590
|
+
},
|
|
591
|
+
option.emoji && /* @__PURE__ */ React3.createElement(
|
|
592
|
+
"img",
|
|
593
|
+
{
|
|
594
|
+
src: parseDiscordEmoji(option.emoji),
|
|
595
|
+
alt: option.emoji.name ?? "emoji",
|
|
596
|
+
style: { width: "16px", height: "16px", marginRight: "8px", verticalAlign: "middle" }
|
|
597
|
+
}
|
|
598
|
+
),
|
|
599
|
+
/* @__PURE__ */ React3.createElement("span", null, option.label)
|
|
600
|
+
))
|
|
601
|
+
));
|
|
602
|
+
}
|
|
603
|
+
var Select_Menu_default = DiscordSelectMenu;
|
|
604
|
+
|
|
605
|
+
// src/generator/renderers/components/Container.tsx
|
|
606
|
+
import React4 from "react";
|
|
607
|
+
function DiscordContainer({ children }) {
|
|
608
|
+
return /* @__PURE__ */ React4.createElement(
|
|
609
|
+
"div",
|
|
610
|
+
{
|
|
611
|
+
style: {
|
|
612
|
+
display: "flex",
|
|
613
|
+
width: "500px",
|
|
614
|
+
flexDirection: "column",
|
|
615
|
+
backgroundColor: "#3f4248",
|
|
616
|
+
padding: "16px",
|
|
617
|
+
border: "1px solid #4f5359",
|
|
618
|
+
marginTop: "2px",
|
|
619
|
+
marginBottom: "2px",
|
|
620
|
+
borderRadius: "10px",
|
|
621
|
+
gap: "8px"
|
|
622
|
+
}
|
|
623
|
+
},
|
|
624
|
+
children
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
var Container_default = DiscordContainer;
|
|
628
|
+
|
|
629
|
+
// src/generator/renderers/components/section/Section.tsx
|
|
630
|
+
import React7 from "react";
|
|
631
|
+
|
|
632
|
+
// src/generator/renderers/components/section/SectionContent.tsx
|
|
633
|
+
import React5 from "react";
|
|
634
|
+
function SectionContent({ children }) {
|
|
635
|
+
return /* @__PURE__ */ React5.createElement(
|
|
636
|
+
"div",
|
|
637
|
+
{
|
|
638
|
+
style: {
|
|
639
|
+
display: "flex",
|
|
640
|
+
flexDirection: "column",
|
|
641
|
+
width: "100%"
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
children
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
var SectionContent_default = SectionContent;
|
|
648
|
+
|
|
649
|
+
// src/generator/renderers/components/section/SectionAccessory.tsx
|
|
650
|
+
import React6 from "react";
|
|
651
|
+
function SectionAccessory({ children }) {
|
|
652
|
+
if (!children) return null;
|
|
653
|
+
return /* @__PURE__ */ React6.createElement(
|
|
654
|
+
"div",
|
|
655
|
+
{
|
|
656
|
+
style: {
|
|
657
|
+
display: "flex",
|
|
658
|
+
width: "100%",
|
|
659
|
+
maxWidth: "500px",
|
|
660
|
+
justifyContent: "flex-end",
|
|
661
|
+
alignItems: "center"
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
children
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
var SectionAccessory_default = SectionAccessory;
|
|
668
|
+
|
|
669
|
+
// src/generator/renderers/components/section/Section.tsx
|
|
670
|
+
function DiscordSection({ children, accessory, id }) {
|
|
671
|
+
return /* @__PURE__ */ React7.createElement(
|
|
672
|
+
"div",
|
|
673
|
+
{
|
|
674
|
+
style: {
|
|
675
|
+
display: "flex",
|
|
676
|
+
flexDirection: "row",
|
|
677
|
+
width: "100%",
|
|
678
|
+
maxWidth: "500px"
|
|
679
|
+
}
|
|
680
|
+
},
|
|
681
|
+
/* @__PURE__ */ React7.createElement(SectionContent_default, null, children),
|
|
682
|
+
/* @__PURE__ */ React7.createElement(SectionAccessory_default, null, accessory && /* @__PURE__ */ React7.createElement(Component, { component: accessory, id }))
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
var Section_default = DiscordSection;
|
|
686
|
+
|
|
687
|
+
// src/generator/renderers/components/Media Gallery.tsx
|
|
688
|
+
import React8 from "react";
|
|
689
|
+
function DiscordMediaGallery({ component }) {
|
|
690
|
+
if (!component.items || component.items.length === 0) {
|
|
691
|
+
return null;
|
|
692
|
+
}
|
|
693
|
+
const count = component.items.length;
|
|
694
|
+
const imagesToShow = component.items.slice(0, 10);
|
|
695
|
+
const hasMore = component.items.length > 10;
|
|
696
|
+
return /* @__PURE__ */ React8.createElement("div", { style: getGalleryLayout(count) }, imagesToShow.map((media, idx) => /* @__PURE__ */ React8.createElement("div", { key: idx, style: getImageStyle(idx, count) }, /* @__PURE__ */ React8.createElement(
|
|
697
|
+
"img",
|
|
698
|
+
{
|
|
699
|
+
src: media.media.url,
|
|
700
|
+
alt: media.description || "Media content",
|
|
701
|
+
style: {
|
|
702
|
+
width: "100%",
|
|
703
|
+
height: "100%",
|
|
704
|
+
objectFit: "cover"
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
), hasMore && idx === imagesToShow.length - 1 && /* @__PURE__ */ React8.createElement(
|
|
708
|
+
"div",
|
|
709
|
+
{
|
|
710
|
+
style: {
|
|
711
|
+
position: "absolute",
|
|
712
|
+
top: 0,
|
|
713
|
+
left: 0,
|
|
714
|
+
width: "100%",
|
|
715
|
+
height: "100%",
|
|
716
|
+
display: "flex",
|
|
717
|
+
alignItems: "center",
|
|
718
|
+
justifyContent: "center",
|
|
719
|
+
backgroundColor: "rgba(0, 0, 0, 0.7)",
|
|
720
|
+
color: "white",
|
|
721
|
+
fontSize: "20px",
|
|
722
|
+
fontWeight: "bold"
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
"+",
|
|
726
|
+
component.items.length - 10
|
|
727
|
+
))));
|
|
728
|
+
}
|
|
729
|
+
var Media_Gallery_default = DiscordMediaGallery;
|
|
730
|
+
|
|
731
|
+
// src/generator/renderers/components/Spacing.tsx
|
|
732
|
+
import React9 from "react";
|
|
733
|
+
import { SeparatorSpacingSize } from "discord.js";
|
|
734
|
+
function DiscordSeparator({ divider, spacing }) {
|
|
735
|
+
return /* @__PURE__ */ React9.createElement(
|
|
736
|
+
"div",
|
|
737
|
+
{
|
|
738
|
+
style: {
|
|
739
|
+
width: "100%",
|
|
740
|
+
height: divider ? "1px" : "0px",
|
|
741
|
+
backgroundColor: "#4f5359",
|
|
742
|
+
margin: spacing === SeparatorSpacingSize.Large ? "8px 0" : "0"
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
var Spacing_default = DiscordSeparator;
|
|
748
|
+
|
|
749
|
+
// src/generator/renderers/components/Button.tsx
|
|
750
|
+
import React10 from "react";
|
|
751
|
+
function DiscordButton({ type, url, emoji, children }) {
|
|
752
|
+
return /* @__PURE__ */ React10.createElement("a", { href: url, target: "_blank", className: `discord-button discord-button-${type}` }, emoji && /* @__PURE__ */ React10.createElement("span", { style: { display: "flex", alignItems: "center" } }, /* @__PURE__ */ React10.createElement("img", { src: emoji, alt: "emoji", style: { width: "16px", height: "16px", marginRight: "8px" } })), /* @__PURE__ */ React10.createElement("span", { style: { display: "flex", alignItems: "center" } }, children), url && /* @__PURE__ */ React10.createElement("span", { style: { marginLeft: "8px", display: "flex", alignItems: "center" } }, /* @__PURE__ */ React10.createElement("svg", { role: "img", xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", fill: "none", viewBox: "0 0 24 24" }, /* @__PURE__ */ React10.createElement(
|
|
753
|
+
"path",
|
|
754
|
+
{
|
|
755
|
+
fill: "currentColor",
|
|
756
|
+
d: "M15 2a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 1 1-2 0V4.41l-4.3 4.3a1 1 0 1 1-1.4-1.42L19.58 3H16a1 1 0 0 1-1-1Z"
|
|
757
|
+
}
|
|
758
|
+
), /* @__PURE__ */ React10.createElement(
|
|
759
|
+
"path",
|
|
760
|
+
{
|
|
761
|
+
fill: "currentColor",
|
|
762
|
+
d: "M5 2a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-6a1 1 0 1 0-2 0v6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h6a1 1 0 1 0 0-2H5Z"
|
|
763
|
+
}
|
|
764
|
+
))));
|
|
765
|
+
}
|
|
766
|
+
var Button_default = DiscordButton;
|
|
767
|
+
|
|
768
|
+
// src/generator/renderers/components/Thumbnail.tsx
|
|
769
|
+
import React11 from "react";
|
|
770
|
+
function DiscordThumbnail({ url }) {
|
|
771
|
+
return /* @__PURE__ */ React11.createElement(
|
|
772
|
+
"img",
|
|
773
|
+
{
|
|
774
|
+
src: url,
|
|
775
|
+
alt: "Thumbnail",
|
|
776
|
+
style: {
|
|
777
|
+
width: "85px",
|
|
778
|
+
height: "85px",
|
|
779
|
+
objectFit: "cover",
|
|
780
|
+
borderRadius: "8px"
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
var Thumbnail_default = DiscordThumbnail;
|
|
786
|
+
|
|
787
|
+
// src/generator/renderers/components.tsx
|
|
788
|
+
function ComponentRow({
|
|
789
|
+
component,
|
|
790
|
+
id,
|
|
791
|
+
context
|
|
792
|
+
}) {
|
|
793
|
+
switch (component.type) {
|
|
794
|
+
case ComponentType3.ActionRow:
|
|
795
|
+
return /* @__PURE__ */ React12.createElement(DiscordActionRow, { key: id }, /* @__PURE__ */ React12.createElement(React12.Fragment, null, component.components.map((nestedComponent, id2) => /* @__PURE__ */ React12.createElement(Component, { component: nestedComponent, id: id2, key: id2 }))));
|
|
796
|
+
case ComponentType3.Container:
|
|
797
|
+
return /* @__PURE__ */ React12.createElement(Container_default, { key: id }, /* @__PURE__ */ React12.createElement(React12.Fragment, null, component.components.map((nestedComponent, id2) => /* @__PURE__ */ React12.createElement(ComponentRow, { component: nestedComponent, id: id2, key: id2, context }))));
|
|
798
|
+
case ComponentType3.File:
|
|
799
|
+
return /* @__PURE__ */ React12.createElement(React12.Fragment, null, component.spoiler ? /* @__PURE__ */ React12.createElement(DiscordSpoiler2, { key: component.id, slot: "attachment" }, /* @__PURE__ */ React12.createElement(
|
|
800
|
+
DiscordAttachment2,
|
|
801
|
+
{
|
|
802
|
+
type: "file",
|
|
803
|
+
key: component.id,
|
|
804
|
+
slot: "attachment",
|
|
805
|
+
url: component.file.url,
|
|
806
|
+
alt: "Discord Attachment"
|
|
807
|
+
}
|
|
808
|
+
)) : /* @__PURE__ */ React12.createElement(
|
|
809
|
+
DiscordAttachment2,
|
|
810
|
+
{
|
|
811
|
+
type: "file",
|
|
812
|
+
key: component.id,
|
|
813
|
+
slot: "attachment",
|
|
814
|
+
url: component.file.url,
|
|
815
|
+
alt: "Discord Attachment"
|
|
816
|
+
}
|
|
817
|
+
));
|
|
818
|
+
case ComponentType3.MediaGallery:
|
|
819
|
+
return /* @__PURE__ */ React12.createElement(Media_Gallery_default, { component, key: id });
|
|
820
|
+
case ComponentType3.Section:
|
|
821
|
+
return /* @__PURE__ */ React12.createElement(Section_default, { key: id, accessory: component.accessory, id }, component.components.map((nestedComponent, id2) => /* @__PURE__ */ React12.createElement(ComponentRow, { component: nestedComponent, id: id2, key: id2, context })));
|
|
822
|
+
case ComponentType3.Separator:
|
|
823
|
+
return /* @__PURE__ */ React12.createElement(Spacing_default, { key: id, spacing: component.spacing, divider: component.divider });
|
|
824
|
+
case ComponentType3.TextDisplay:
|
|
825
|
+
return /* @__PURE__ */ React12.createElement(MessageContent, { key: id, content: component.content, context: { ...context, type: 2 /* NORMAL */ } });
|
|
826
|
+
default:
|
|
827
|
+
return null;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
function Component({
|
|
831
|
+
component,
|
|
832
|
+
id
|
|
833
|
+
}) {
|
|
834
|
+
switch (component.type) {
|
|
835
|
+
case ComponentType3.Button:
|
|
836
|
+
return /* @__PURE__ */ React12.createElement(
|
|
837
|
+
Button_default,
|
|
838
|
+
{
|
|
839
|
+
key: id,
|
|
840
|
+
type: ButtonStyleMapping[component.style] ?? "secondary",
|
|
841
|
+
url: component.url ?? void 0,
|
|
842
|
+
emoji: component.emoji ? parseDiscordEmoji(component.emoji) : void 0
|
|
843
|
+
},
|
|
844
|
+
component.label
|
|
845
|
+
);
|
|
846
|
+
case ComponentType3.StringSelect:
|
|
847
|
+
case ComponentType3.UserSelect:
|
|
848
|
+
case ComponentType3.RoleSelect:
|
|
849
|
+
case ComponentType3.MentionableSelect:
|
|
850
|
+
case ComponentType3.ChannelSelect:
|
|
851
|
+
return /* @__PURE__ */ React12.createElement(Select_Menu_default, { key: id, component });
|
|
852
|
+
case ComponentType3.Thumbnail:
|
|
853
|
+
return /* @__PURE__ */ React12.createElement(Thumbnail_default, { key: id, url: component.media.url });
|
|
854
|
+
default:
|
|
855
|
+
return null;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
// src/generator/renderers/embed.tsx
|
|
860
|
+
import {
|
|
861
|
+
DiscordEmbed as DiscordEmbedComponent,
|
|
862
|
+
DiscordEmbedDescription,
|
|
863
|
+
DiscordEmbedField,
|
|
864
|
+
DiscordEmbedFields,
|
|
865
|
+
DiscordEmbedFooter
|
|
866
|
+
} from "@derockdev/discord-components-react";
|
|
867
|
+
import React13 from "react";
|
|
868
|
+
|
|
869
|
+
// src/utils/embeds.ts
|
|
870
|
+
function calculateInlineIndex(fields, currentFieldIndex) {
|
|
871
|
+
const startIndex = currentFieldIndex - 1;
|
|
872
|
+
for (let i = startIndex; i >= 0; i--) {
|
|
873
|
+
const field = fields[i];
|
|
874
|
+
if (!field) continue;
|
|
875
|
+
if (field.inline === false) {
|
|
876
|
+
const amount = startIndex - i;
|
|
877
|
+
return amount % 3 + 1;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
return currentFieldIndex % 3 + 1;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
// src/generator/renderers/embed.tsx
|
|
884
|
+
async function DiscordEmbed({ embed, context }) {
|
|
885
|
+
return /* @__PURE__ */ React13.createElement(
|
|
886
|
+
DiscordEmbedComponent,
|
|
887
|
+
{
|
|
888
|
+
embedTitle: embed.title ?? void 0,
|
|
889
|
+
slot: "embeds",
|
|
890
|
+
key: `${context.message.id}-e-${context.index}`,
|
|
891
|
+
authorImage: embed.author?.proxyIconURL ?? embed.author?.iconURL,
|
|
892
|
+
authorName: embed.author?.name,
|
|
893
|
+
authorUrl: embed.author?.url,
|
|
894
|
+
color: embed.hexColor ?? void 0,
|
|
895
|
+
image: embed.image?.proxyURL ?? embed.image?.url,
|
|
896
|
+
thumbnail: embed.thumbnail?.proxyURL ?? embed.thumbnail?.url,
|
|
897
|
+
url: embed.url ?? void 0
|
|
898
|
+
},
|
|
899
|
+
embed.description && /* @__PURE__ */ React13.createElement(DiscordEmbedDescription, { slot: "description" }, /* @__PURE__ */ React13.createElement(MessageContent, { content: embed.description, context: { ...context, type: 0 /* EMBED */ } })),
|
|
900
|
+
embed.fields.length > 0 && /* @__PURE__ */ React13.createElement(DiscordEmbedFields, { slot: "fields" }, embed.fields.map(async (field, id) => /* @__PURE__ */ React13.createElement(
|
|
901
|
+
DiscordEmbedField,
|
|
902
|
+
{
|
|
903
|
+
key: `${context.message.id}-e-${context.index}-f-${id}`,
|
|
904
|
+
fieldTitle: field.name,
|
|
905
|
+
inline: field.inline,
|
|
906
|
+
inlineIndex: calculateInlineIndex(embed.fields, id)
|
|
907
|
+
},
|
|
908
|
+
/* @__PURE__ */ React13.createElement(MessageContent, { content: field.value, context: { ...context, type: 0 /* EMBED */ } })
|
|
909
|
+
))),
|
|
910
|
+
embed.footer && /* @__PURE__ */ React13.createElement(
|
|
911
|
+
DiscordEmbedFooter,
|
|
912
|
+
{
|
|
913
|
+
slot: "footer",
|
|
914
|
+
footerImage: embed.footer.proxyIconURL ?? embed.footer.iconURL,
|
|
915
|
+
timestamp: embed.timestamp ?? void 0
|
|
916
|
+
},
|
|
917
|
+
embed.footer.text
|
|
918
|
+
)
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// src/generator/renderers/reply.tsx
|
|
923
|
+
import { DiscordReply } from "@derockdev/discord-components-react";
|
|
924
|
+
import { UserFlags as UserFlags2 } from "discord.js";
|
|
925
|
+
import React14 from "react";
|
|
926
|
+
async function MessageReply({ message, context }) {
|
|
927
|
+
if (!message.reference) return null;
|
|
928
|
+
if (message.reference.guildId !== message.guild?.id) return null;
|
|
929
|
+
const referencedMessage = context.messages.find((m) => m.id === message.reference.messageId);
|
|
930
|
+
if (!referencedMessage) return /* @__PURE__ */ React14.createElement(DiscordReply, { slot: "reply" }, "Message could not be loaded.");
|
|
931
|
+
const isCrossPost = referencedMessage.reference && referencedMessage.reference.guildId !== message.guild?.id;
|
|
932
|
+
const isCommand = referencedMessage.interaction !== null;
|
|
933
|
+
return /* @__PURE__ */ React14.createElement(
|
|
934
|
+
DiscordReply,
|
|
935
|
+
{
|
|
936
|
+
slot: "reply",
|
|
937
|
+
edited: !isCommand && referencedMessage.editedAt !== null,
|
|
938
|
+
attachment: referencedMessage.attachments.size > 0,
|
|
939
|
+
author: referencedMessage.member?.nickname ?? referencedMessage.author.displayName ?? referencedMessage.author.username,
|
|
940
|
+
avatar: referencedMessage.author.avatarURL({ size: 32 }) ?? void 0,
|
|
941
|
+
roleColor: referencedMessage.member?.displayHexColor ?? void 0,
|
|
942
|
+
bot: !isCrossPost && referencedMessage.author.bot,
|
|
943
|
+
verified: referencedMessage.author.flags?.has(UserFlags2.VerifiedBot),
|
|
944
|
+
op: message?.channel?.isThread?.() && referencedMessage.author.id === message?.channel?.ownerId,
|
|
945
|
+
server: isCrossPost ?? void 0,
|
|
946
|
+
command: isCommand
|
|
947
|
+
},
|
|
948
|
+
referencedMessage.content ? /* @__PURE__ */ React14.createElement("span", { "data-goto": referencedMessage.id }, /* @__PURE__ */ React14.createElement(MessageContent, { content: referencedMessage.content, context: { ...context, type: 1 /* REPLY */ } })) : isCommand ? /* @__PURE__ */ React14.createElement("em", { "data-goto": referencedMessage.id }, "Click to see command.") : /* @__PURE__ */ React14.createElement("em", { "data-goto": referencedMessage.id }, "Click to see attachment.")
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// src/generator/renderers/systemMessage.tsx
|
|
953
|
+
import { DiscordReaction, DiscordReactions, DiscordSystemMessage } from "@derockdev/discord-components-react";
|
|
954
|
+
import { MessageType } from "discord.js";
|
|
955
|
+
import React15 from "react";
|
|
956
|
+
async function SystemMessage({ message }) {
|
|
957
|
+
switch (message.type) {
|
|
958
|
+
case MessageType.RecipientAdd:
|
|
959
|
+
case MessageType.UserJoin:
|
|
960
|
+
return /* @__PURE__ */ React15.createElement(DiscordSystemMessage, { id: `m-${message.id}`, key: message.id, type: "join" }, /* @__PURE__ */ React15.createElement(JoinMessage, { member: message.member, fallbackUser: message.author }));
|
|
961
|
+
case MessageType.ChannelPinnedMessage:
|
|
962
|
+
return /* @__PURE__ */ React15.createElement(DiscordSystemMessage, { id: `m-${message.id}`, key: message.id, type: "pin" }, /* @__PURE__ */ React15.createElement(Highlight, { color: message.member?.roles.color?.hexColor }, message.author.displayName ?? message.author.username), " ", "pinned ", /* @__PURE__ */ React15.createElement("i", { "data-goto": message.reference?.messageId }, "a message"), " to this channel.", message.reactions.cache.size > 0 && /* @__PURE__ */ React15.createElement(DiscordReactions, { slot: "reactions" }, message.reactions.cache.map((reaction, id) => /* @__PURE__ */ React15.createElement(
|
|
963
|
+
DiscordReaction,
|
|
964
|
+
{
|
|
965
|
+
key: `${message.id}r${id}`,
|
|
966
|
+
name: reaction.emoji.name,
|
|
967
|
+
emoji: parseDiscordEmoji(reaction.emoji),
|
|
968
|
+
count: reaction.count
|
|
969
|
+
}
|
|
970
|
+
))));
|
|
971
|
+
case MessageType.GuildBoost:
|
|
972
|
+
case MessageType.GuildBoostTier1:
|
|
973
|
+
case MessageType.GuildBoostTier2:
|
|
974
|
+
case MessageType.GuildBoostTier3:
|
|
975
|
+
return /* @__PURE__ */ React15.createElement(DiscordSystemMessage, { id: `m-${message.id}`, key: message.id, type: "boost" }, /* @__PURE__ */ React15.createElement(Highlight, { color: message.member?.roles.color?.hexColor }, message.author.displayName ?? message.author.username), " ", "boosted the server!");
|
|
976
|
+
case MessageType.ThreadStarterMessage:
|
|
977
|
+
return /* @__PURE__ */ React15.createElement(DiscordSystemMessage, { id: `ms-${message.id}`, key: message.id, type: "thread" }, /* @__PURE__ */ React15.createElement(Highlight, { color: message.member?.roles.color?.hexColor }, message.author.displayName ?? message.author.username), " ", "started a thread: ", /* @__PURE__ */ React15.createElement("i", { "data-goto": message.reference?.messageId }, message.content));
|
|
978
|
+
// TODO: implement support for these:
|
|
979
|
+
case MessageType.Default:
|
|
980
|
+
case MessageType.RecipientRemove:
|
|
981
|
+
case MessageType.Call:
|
|
982
|
+
case MessageType.ChannelNameChange:
|
|
983
|
+
case MessageType.ChannelIconChange:
|
|
984
|
+
case MessageType.ChannelFollowAdd:
|
|
985
|
+
case MessageType.GuildDiscoveryDisqualified:
|
|
986
|
+
case MessageType.GuildDiscoveryRequalified:
|
|
987
|
+
case MessageType.GuildDiscoveryGracePeriodInitialWarning:
|
|
988
|
+
case MessageType.GuildDiscoveryGracePeriodFinalWarning:
|
|
989
|
+
case MessageType.ThreadCreated:
|
|
990
|
+
case MessageType.Reply:
|
|
991
|
+
case MessageType.ChatInputCommand:
|
|
992
|
+
case MessageType.GuildInviteReminder:
|
|
993
|
+
case MessageType.ContextMenuCommand:
|
|
994
|
+
case MessageType.AutoModerationAction:
|
|
995
|
+
case MessageType.RoleSubscriptionPurchase:
|
|
996
|
+
case MessageType.InteractionPremiumUpsell:
|
|
997
|
+
case MessageType.StageStart:
|
|
998
|
+
case MessageType.StageEnd:
|
|
999
|
+
case MessageType.StageSpeaker:
|
|
1000
|
+
case MessageType.StageRaiseHand:
|
|
1001
|
+
case MessageType.StageTopic:
|
|
1002
|
+
case MessageType.GuildApplicationPremiumSubscription:
|
|
1003
|
+
case MessageType.GuildIncidentAlertModeEnabled:
|
|
1004
|
+
case MessageType.GuildIncidentAlertModeDisabled:
|
|
1005
|
+
case MessageType.GuildIncidentReportRaid:
|
|
1006
|
+
case MessageType.GuildIncidentReportFalseAlarm:
|
|
1007
|
+
case MessageType.PurchaseNotification:
|
|
1008
|
+
case MessageType.PollResult:
|
|
1009
|
+
return void 0;
|
|
1010
|
+
default:
|
|
1011
|
+
return void 0;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
function Highlight({ children, color }) {
|
|
1015
|
+
return /* @__PURE__ */ React15.createElement("i", { style: { color: color ?? "white" } }, children);
|
|
1016
|
+
}
|
|
1017
|
+
var allJoinMessages = [
|
|
1018
|
+
"{user} just joined the server - glhf!",
|
|
1019
|
+
"{user} just joined. Everyone, look busy!",
|
|
1020
|
+
"{user} just joined. Can I get a heal?",
|
|
1021
|
+
"{user} joined your party.",
|
|
1022
|
+
"{user} joined. You must construct additional pylons.",
|
|
1023
|
+
"Ermagherd. {user} is here.",
|
|
1024
|
+
"Welcome, {user}. Stay awhile and listen.",
|
|
1025
|
+
"Welcome, {user}. We were expecting you ( \u0361\xB0 \u035C\u0296 \u0361\xB0)",
|
|
1026
|
+
"Welcome, {user}. We hope you brought pizza.",
|
|
1027
|
+
"Welcome {user}. Leave your weapons by the door.",
|
|
1028
|
+
"A wild {user} appeared.",
|
|
1029
|
+
"Swoooosh. {user} just landed.",
|
|
1030
|
+
"Brace yourselves {user} just joined the server.",
|
|
1031
|
+
"{user} just joined. Hide your bananas.",
|
|
1032
|
+
"{user} just arrived. Seems OP - please nerf.",
|
|
1033
|
+
"{user} just slid into the server.",
|
|
1034
|
+
"A {user} has spawned in the server.",
|
|
1035
|
+
"Big {user} showed up!",
|
|
1036
|
+
"Where's {user}? In the server!",
|
|
1037
|
+
"{user} hopped into the server. Kangaroo!!",
|
|
1038
|
+
"{user} just showed up. Hold my beer.",
|
|
1039
|
+
"Challenger approaching - {user} has appeared!",
|
|
1040
|
+
"It's a bird! It's a plane! Nevermind, it's just {user}.",
|
|
1041
|
+
"It's {user}! Praise the sun! \\\\[T]/",
|
|
1042
|
+
"Never gonna give {user} up. Never gonna let {user} down.",
|
|
1043
|
+
"Ha! {user} has joined! You activated my trap card!",
|
|
1044
|
+
"Cheers, love! {user} is here!",
|
|
1045
|
+
"Hey! Listen! {user} has joined!",
|
|
1046
|
+
"We've been expecting you {user}",
|
|
1047
|
+
"It's dangerous to go alone, take {user}!",
|
|
1048
|
+
"{user} has joined the server! It's super effective!",
|
|
1049
|
+
"Cheers, love! {user} is here!",
|
|
1050
|
+
"{user} is here, as the prophecy foretold.",
|
|
1051
|
+
"{user} has arrived. Party's over.",
|
|
1052
|
+
"Ready player {user}",
|
|
1053
|
+
"{user} is here to kick butt and chew bubblegum. And {user} is all out of gum.",
|
|
1054
|
+
"Hello. Is it {user} you're looking for?"
|
|
1055
|
+
];
|
|
1056
|
+
function JoinMessage({ member, fallbackUser }) {
|
|
1057
|
+
const randomMessage = allJoinMessages[Math.floor(Math.random() * allJoinMessages.length)];
|
|
1058
|
+
return randomMessage.split("{user}").flatMap((item, i) => [
|
|
1059
|
+
item,
|
|
1060
|
+
/* @__PURE__ */ React15.createElement(Highlight, { color: member?.roles.color?.hexColor, key: i }, member?.nickname ?? fallbackUser.displayName ?? fallbackUser.username)
|
|
1061
|
+
]).slice(0, -1);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
// src/generator/renderers/message.tsx
|
|
1065
|
+
async function DiscordMessage({
|
|
1066
|
+
message,
|
|
1067
|
+
context
|
|
1068
|
+
}) {
|
|
1069
|
+
if (message.system) return /* @__PURE__ */ React16.createElement(SystemMessage, { message });
|
|
1070
|
+
const isCrosspost = message.reference && message.reference.guildId !== message.guild?.id;
|
|
1071
|
+
return /* @__PURE__ */ React16.createElement(
|
|
1072
|
+
DiscordMessageComponent,
|
|
1073
|
+
{
|
|
1074
|
+
id: `m-${message.id}`,
|
|
1075
|
+
timestamp: message.createdAt.toISOString(),
|
|
1076
|
+
key: message.id,
|
|
1077
|
+
edited: message.editedAt !== null,
|
|
1078
|
+
server: isCrosspost ?? void 0,
|
|
1079
|
+
highlight: message.mentions.everyone,
|
|
1080
|
+
profile: message.author.id
|
|
1081
|
+
},
|
|
1082
|
+
/* @__PURE__ */ React16.createElement(MessageReply, { message, context }),
|
|
1083
|
+
message.interaction && /* @__PURE__ */ React16.createElement(
|
|
1084
|
+
DiscordCommand,
|
|
1085
|
+
{
|
|
1086
|
+
slot: "reply",
|
|
1087
|
+
profile: message.interaction.user.id,
|
|
1088
|
+
command: "/" + message.interaction.commandName
|
|
1089
|
+
}
|
|
1090
|
+
),
|
|
1091
|
+
message.content && /* @__PURE__ */ React16.createElement(
|
|
1092
|
+
MessageContent,
|
|
1093
|
+
{
|
|
1094
|
+
content: message.content,
|
|
1095
|
+
context: { ...context, type: message.webhookId ? 3 /* WEBHOOK */ : 2 /* NORMAL */ }
|
|
1096
|
+
}
|
|
1097
|
+
),
|
|
1098
|
+
/* @__PURE__ */ React16.createElement(Attachments, { message, context }),
|
|
1099
|
+
message.embeds.map((embed, id) => /* @__PURE__ */ React16.createElement(DiscordEmbed, { embed, context: { ...context, index: id, message }, key: id })),
|
|
1100
|
+
message.components.length > 0 && /* @__PURE__ */ React16.createElement(DiscordAttachments2, { slot: "components" }, message.components.map((component, id) => /* @__PURE__ */ React16.createElement(ComponentRow, { key: id, id, component, context }))),
|
|
1101
|
+
message.reactions.cache.size > 0 && /* @__PURE__ */ React16.createElement(DiscordReactions2, { slot: "reactions" }, message.reactions.cache.map((reaction, id) => /* @__PURE__ */ React16.createElement(
|
|
1102
|
+
DiscordReaction2,
|
|
1103
|
+
{
|
|
1104
|
+
key: `${message.id}r${id}`,
|
|
1105
|
+
name: reaction.emoji.name,
|
|
1106
|
+
emoji: parseDiscordEmoji(reaction.emoji),
|
|
1107
|
+
count: reaction.count
|
|
1108
|
+
}
|
|
1109
|
+
))),
|
|
1110
|
+
message.hasThread && message.thread && /* @__PURE__ */ React16.createElement(
|
|
1111
|
+
DiscordThread,
|
|
1112
|
+
{
|
|
1113
|
+
slot: "thread",
|
|
1114
|
+
name: message.thread.name,
|
|
1115
|
+
cta: message.thread.messageCount ? `${message.thread.messageCount} Message${message.thread.messageCount > 1 ? "s" : ""}` : "View Thread"
|
|
1116
|
+
},
|
|
1117
|
+
message.thread.lastMessage ? /* @__PURE__ */ React16.createElement(DiscordThreadMessage, { profile: message.thread.lastMessage.author.id }, /* @__PURE__ */ React16.createElement(
|
|
1118
|
+
MessageContent,
|
|
1119
|
+
{
|
|
1120
|
+
content: message.thread.lastMessage.content.length > 128 ? message.thread.lastMessage.content.substring(0, 125) + "..." : message.thread.lastMessage.content,
|
|
1121
|
+
context: { ...context, type: 1 /* REPLY */ }
|
|
1122
|
+
}
|
|
1123
|
+
)) : `Thread messages not saved.`
|
|
1124
|
+
)
|
|
1125
|
+
);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// src/generator/transcript.tsx
|
|
1129
|
+
async function DiscordMessages({ messages, channel, callbacks, ...options }) {
|
|
1130
|
+
return /* @__PURE__ */ React17.createElement(DiscordMessagesComponent, { style: { minHeight: "100vh" } }, /* @__PURE__ */ React17.createElement("style", { dangerouslySetInnerHTML: { __html: globalStyles } }), /* @__PURE__ */ React17.createElement(
|
|
1131
|
+
DiscordHeader,
|
|
1132
|
+
{
|
|
1133
|
+
guild: channel.isDMBased() ? "Direct Messages" : channel.guild.name,
|
|
1134
|
+
channel: channel.isDMBased() ? channel.type === ChannelType2.DM ? channel.recipient?.tag ?? "Unknown Recipient" : "Unknown Recipient" : channel.name,
|
|
1135
|
+
icon: channel.isDMBased() ? void 0 : channel.guild.iconURL({ size: 128 }) ?? void 0
|
|
1136
|
+
},
|
|
1137
|
+
channel.isThread() ? `Thread channel in ${channel.parent?.name ?? "Unknown Channel"}` : channel.isDMBased() ? `Direct Messages` : channel.isVoiceBased() ? `Voice Text Channel for ${channel.name}` : channel.type === ChannelType2.GuildCategory ? `Category Channel` : "topic" in channel && channel.topic ? /* @__PURE__ */ React17.createElement(
|
|
1138
|
+
MessageContent,
|
|
1139
|
+
{
|
|
1140
|
+
content: channel.topic,
|
|
1141
|
+
context: { messages, channel, callbacks, type: 1 /* REPLY */, ...options }
|
|
1142
|
+
}
|
|
1143
|
+
) : `This is the start of #${channel.name} channel.`
|
|
1144
|
+
), messages.map((message) => /* @__PURE__ */ React17.createElement(DiscordMessage, { message, context: { messages, channel, callbacks, ...options }, key: message.id })), /* @__PURE__ */ React17.createElement("div", { style: { textAlign: "center", width: "100%" } }, options.footerText ? options.footerText.replaceAll("{number}", messages.length.toString()).replaceAll("{s}", messages.length > 1 ? "s" : "") : `Exported ${messages.length} message${messages.length > 1 ? "s" : ""}.`, " ", options.poweredBy ? /* @__PURE__ */ React17.createElement("span", { style: { textAlign: "center" } }, "Powered by", " ", /* @__PURE__ */ React17.createElement("a", { href: "https://github.com/devjoseh/discord2html", style: { color: "lightblue" } }, "discord2html"), ".") : null));
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
// src/generator/index.tsx
|
|
1148
|
+
var discordComponentsVersion = "^3.6.1";
|
|
1149
|
+
try {
|
|
1150
|
+
const packagePath = path.join(__dirname, "..", "..", "package.json");
|
|
1151
|
+
const packageJSON = JSON.parse(readFileSync(packagePath, "utf8"));
|
|
1152
|
+
discordComponentsVersion = packageJSON.dependencies["@derockdev/discord-components-core"] ?? discordComponentsVersion;
|
|
1153
|
+
} catch {
|
|
1154
|
+
}
|
|
1155
|
+
async function render({ messages, channel, callbacks, ...options }) {
|
|
1156
|
+
const profiles = buildProfiles(messages);
|
|
1157
|
+
const { prelude } = await prerenderToNodeStream(
|
|
1158
|
+
/* @__PURE__ */ React18.createElement("html", null, /* @__PURE__ */ React18.createElement("head", null, /* @__PURE__ */ React18.createElement("meta", { charSet: "utf-8" }), /* @__PURE__ */ React18.createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }), /* @__PURE__ */ React18.createElement(
|
|
1159
|
+
"link",
|
|
1160
|
+
{
|
|
1161
|
+
rel: "icon",
|
|
1162
|
+
type: "image/png",
|
|
1163
|
+
href: options.favicon === "guild" ? channel.isDMBased() ? void 0 : channel.guild.iconURL({ size: 16, extension: "png" }) ?? void 0 : options.favicon
|
|
1164
|
+
}
|
|
1165
|
+
), /* @__PURE__ */ React18.createElement("title", null, channel.isDMBased() ? "Direct Messages" : channel.name), /* @__PURE__ */ React18.createElement(
|
|
1166
|
+
"script",
|
|
1167
|
+
{
|
|
1168
|
+
dangerouslySetInnerHTML: {
|
|
1169
|
+
__html: scrollToMessage
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
), !options.hydrate && /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement(
|
|
1173
|
+
"script",
|
|
1174
|
+
{
|
|
1175
|
+
dangerouslySetInnerHTML: {
|
|
1176
|
+
__html: `window.$discordMessage={profiles:${JSON.stringify(await profiles)}}`
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
), /* @__PURE__ */ React18.createElement(
|
|
1180
|
+
"script",
|
|
1181
|
+
{
|
|
1182
|
+
type: "module",
|
|
1183
|
+
src: `https://cdn.jsdelivr.net/npm/@derockdev/discord-components-core@${discordComponentsVersion}/dist/derockdev-discord-components-core/derockdev-discord-components-core.esm.js`
|
|
1184
|
+
}
|
|
1185
|
+
))), /* @__PURE__ */ React18.createElement(
|
|
1186
|
+
"body",
|
|
1187
|
+
{
|
|
1188
|
+
style: {
|
|
1189
|
+
margin: 0,
|
|
1190
|
+
minHeight: "100vh"
|
|
1191
|
+
}
|
|
1192
|
+
},
|
|
1193
|
+
/* @__PURE__ */ React18.createElement(DiscordMessages, { messages, channel, callbacks, ...options })
|
|
1194
|
+
), options.hydrate && /* @__PURE__ */ React18.createElement("script", { dangerouslySetInnerHTML: { __html: revealSpoiler } }))
|
|
1195
|
+
);
|
|
1196
|
+
const markup = await streamToString(prelude);
|
|
1197
|
+
if (options.hydrate) {
|
|
1198
|
+
const result = await renderToString(markup, {
|
|
1199
|
+
beforeHydrate: async (document) => {
|
|
1200
|
+
document.defaultView.$discordMessage = {
|
|
1201
|
+
profiles: await profiles
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
});
|
|
1205
|
+
return result.html;
|
|
1206
|
+
}
|
|
1207
|
+
return markup;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
// src/types.ts
|
|
1211
|
+
var ExportReturnType = /* @__PURE__ */ ((ExportReturnType2) => {
|
|
1212
|
+
ExportReturnType2["Buffer"] = "buffer";
|
|
1213
|
+
ExportReturnType2["String"] = "string";
|
|
1214
|
+
ExportReturnType2["Attachment"] = "attachment";
|
|
1215
|
+
return ExportReturnType2;
|
|
1216
|
+
})(ExportReturnType || {});
|
|
1217
|
+
|
|
1218
|
+
// src/downloader/images.ts
|
|
1219
|
+
import { request } from "undici";
|
|
1220
|
+
import debug from "debug";
|
|
1221
|
+
var _TranscriptImageDownloader = class _TranscriptImageDownloader {
|
|
1222
|
+
constructor() {
|
|
1223
|
+
this.log = _TranscriptImageDownloader.log;
|
|
1224
|
+
}
|
|
1225
|
+
/**
|
|
1226
|
+
* Sets the maximum file size for *each* individual image.
|
|
1227
|
+
* @param size The maximum file size in kilobytes
|
|
1228
|
+
*/
|
|
1229
|
+
withMaxSize(size) {
|
|
1230
|
+
this.maxFileSize = size;
|
|
1231
|
+
return this;
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Sets the compression quality for each image. This requires `sharp` to be installed.
|
|
1235
|
+
* Optionally, images can be converted to WebP format which is smaller in size.
|
|
1236
|
+
* @param quality The quality of the image (1 lowest - 100 highest). Lower quality means smaller file size.
|
|
1237
|
+
* @param convertToWebP Whether to convert the image to WebP format
|
|
1238
|
+
*/
|
|
1239
|
+
withCompression(quality = 80, convertToWebP = false, options = {}) {
|
|
1240
|
+
if (quality < 1 || quality > 100) throw new Error("Quality must be between 1 and 100");
|
|
1241
|
+
import("./lib-V24P5ASW.mjs").catch((err) => {
|
|
1242
|
+
console.error(err);
|
|
1243
|
+
console.error(
|
|
1244
|
+
`[discord2html] Failed to import 'sharp'. Image compression requires the 'sharp' package to be installed. Either install sharp or remove the compression options.`
|
|
1245
|
+
);
|
|
1246
|
+
});
|
|
1247
|
+
this.compression = { quality, convertToWebP, options };
|
|
1248
|
+
return this;
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Builds the image saving callback.
|
|
1252
|
+
*/
|
|
1253
|
+
build() {
|
|
1254
|
+
return async (attachment) => {
|
|
1255
|
+
if (!attachment.width || !attachment.height) return void 0;
|
|
1256
|
+
if (this.maxFileSize && attachment.size > this.maxFileSize * 1024) return void 0;
|
|
1257
|
+
this.log(`Fetching attachment ${attachment.id}: ${attachment.url}`);
|
|
1258
|
+
const response = await request(attachment.url).catch((err) => {
|
|
1259
|
+
console.error(`[discord2html] Failed to download image for transcript: `, err);
|
|
1260
|
+
return null;
|
|
1261
|
+
});
|
|
1262
|
+
if (!response) return void 0;
|
|
1263
|
+
const mimetype = response.headers["content-type"];
|
|
1264
|
+
const buffer = await response.body.arrayBuffer().then((res) => Buffer.from(res));
|
|
1265
|
+
this.log(`Finished fetching ${attachment.id} (${buffer.length} bytes)`);
|
|
1266
|
+
if (this.compression) {
|
|
1267
|
+
const sharp = await import("./lib-V24P5ASW.mjs");
|
|
1268
|
+
this.log(`Compressing ${attachment.id} with 'sharp'`);
|
|
1269
|
+
const sharpbuf = await sharp.default(buffer).webp({
|
|
1270
|
+
quality: this.compression.quality,
|
|
1271
|
+
force: this.compression.convertToWebP,
|
|
1272
|
+
effort: 2,
|
|
1273
|
+
...this.compression.options
|
|
1274
|
+
}).toBuffer({ resolveWithObject: true });
|
|
1275
|
+
this.log(`Finished compressing ${attachment.id} (${sharpbuf.info.size} bytes)`);
|
|
1276
|
+
return `data:image/${sharpbuf.info.format};base64,${sharpbuf.data.toString("base64")}`;
|
|
1277
|
+
}
|
|
1278
|
+
return `data:${mimetype};base64,${buffer.toString("base64")}`;
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
};
|
|
1282
|
+
_TranscriptImageDownloader.log = debug("discord2html:TranscriptImageDownloader");
|
|
1283
|
+
var TranscriptImageDownloader = _TranscriptImageDownloader;
|
|
1284
|
+
|
|
1285
|
+
// src/index.ts
|
|
1286
|
+
var versionPrefix = version.split(".")[0];
|
|
1287
|
+
if (versionPrefix !== "14" && versionPrefix !== "15") {
|
|
1288
|
+
console.error(
|
|
1289
|
+
`[discord2html] discord2html requires discord.js v14.x.x or v15.x.x, but you are using v${version}. For v13.x.x support, use the original package: "npm install discord-html-transcripts@^2".`
|
|
1290
|
+
);
|
|
1291
|
+
process.exit(1);
|
|
1292
|
+
}
|
|
1293
|
+
async function generateFromMessages(messages, channel, options = {}) {
|
|
1294
|
+
const transformedMessages = messages instanceof Collection ? Array.from(messages.values()) : messages;
|
|
1295
|
+
let resolveImageSrc = options.callbacks?.resolveImageSrc ?? ((attachment) => attachment.url);
|
|
1296
|
+
if (options.saveImages) {
|
|
1297
|
+
if (options.callbacks?.resolveImageSrc) {
|
|
1298
|
+
console.warn(
|
|
1299
|
+
`[discord2html] You have specified both saveImages and resolveImageSrc, please only specify one. resolveImageSrc will be used.`
|
|
1300
|
+
);
|
|
1301
|
+
} else {
|
|
1302
|
+
resolveImageSrc = new TranscriptImageDownloader().build();
|
|
1303
|
+
console.log("Using default downloader");
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
const html = await render({
|
|
1307
|
+
messages: transformedMessages,
|
|
1308
|
+
channel,
|
|
1309
|
+
saveImages: options.saveImages ?? false,
|
|
1310
|
+
callbacks: {
|
|
1311
|
+
resolveImageSrc,
|
|
1312
|
+
resolveChannel: async (id) => channel.client.channels.fetch(id).catch(() => null),
|
|
1313
|
+
resolveUser: async (id) => channel.client.users.fetch(id).catch(() => null),
|
|
1314
|
+
resolveRole: channel.isDMBased() ? () => null : async (id) => channel.guild?.roles.fetch(id).catch(() => null),
|
|
1315
|
+
...options.callbacks ?? {}
|
|
1316
|
+
},
|
|
1317
|
+
poweredBy: options.poweredBy ?? true,
|
|
1318
|
+
footerText: options.footerText ?? "Exported {number} message{s}.",
|
|
1319
|
+
favicon: options.favicon ?? "guild",
|
|
1320
|
+
hydrate: options.hydrate ?? false
|
|
1321
|
+
});
|
|
1322
|
+
if (options.returnType === "buffer" /* Buffer */) {
|
|
1323
|
+
return Buffer.from(html);
|
|
1324
|
+
}
|
|
1325
|
+
if (options.returnType === "string" /* String */) {
|
|
1326
|
+
return html;
|
|
1327
|
+
}
|
|
1328
|
+
return new AttachmentBuilder(Buffer.from(html), {
|
|
1329
|
+
name: options.filename ?? `transcript-${channel.id}.html`
|
|
1330
|
+
});
|
|
1331
|
+
}
|
|
1332
|
+
async function createTranscript(channel, options = {}) {
|
|
1333
|
+
if (!channel.isTextBased()) {
|
|
1334
|
+
throw new TypeError(`Provided channel must be text-based, received ${channel.type}`);
|
|
1335
|
+
}
|
|
1336
|
+
let allMessages = [];
|
|
1337
|
+
let lastMessageId;
|
|
1338
|
+
const { limit, filter } = options;
|
|
1339
|
+
const resolvedLimit = typeof limit === "undefined" || limit === -1 ? Infinity : limit;
|
|
1340
|
+
while (true) {
|
|
1341
|
+
const fetchLimitOptions = { limit: 100, before: lastMessageId };
|
|
1342
|
+
if (!lastMessageId) delete fetchLimitOptions.before;
|
|
1343
|
+
const messages = await channel.messages.fetch(fetchLimitOptions);
|
|
1344
|
+
const filteredMessages = typeof filter === "function" ? messages.filter(filter) : messages;
|
|
1345
|
+
allMessages.push(...filteredMessages.values());
|
|
1346
|
+
lastMessageId = messages.lastKey();
|
|
1347
|
+
if (messages.size < 100) break;
|
|
1348
|
+
if (allMessages.length >= resolvedLimit) break;
|
|
1349
|
+
}
|
|
1350
|
+
if (resolvedLimit < allMessages.length) allMessages = allMessages.slice(0, limit);
|
|
1351
|
+
return generateFromMessages(allMessages.reverse(), channel, options);
|
|
1352
|
+
}
|
|
1353
|
+
var index_default = {
|
|
1354
|
+
createTranscript,
|
|
1355
|
+
generateFromMessages
|
|
1356
|
+
};
|
|
1357
|
+
export {
|
|
1358
|
+
DiscordMessages,
|
|
1359
|
+
ExportReturnType,
|
|
1360
|
+
TranscriptImageDownloader,
|
|
1361
|
+
createTranscript,
|
|
1362
|
+
index_default as default,
|
|
1363
|
+
generateFromMessages
|
|
1364
|
+
};
|
|
1365
|
+
//# sourceMappingURL=index.mjs.map
|