discord-message-transcript-base 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/dist/assets/script.js +164 -0
- package/dist/assets/style.css +698 -0
- package/dist/core/error.d.ts +3 -0
- package/dist/core/error.js +7 -0
- package/dist/core/mappers.d.ts +2 -0
- package/dist/core/mappers.js +16 -0
- package/dist/core/markdown.d.ts +2 -0
- package/dist/core/markdown.js +175 -0
- package/dist/core/output.d.ts +3 -0
- package/dist/core/output.js +24 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +37 -0
- package/dist/renderers/html/css.d.ts +11 -0
- package/dist/renderers/html/css.js +720 -0
- package/dist/renderers/html/css.min.d.ts +1 -0
- package/dist/renderers/html/css.min.js +1 -0
- package/dist/renderers/html/html.d.ts +20 -0
- package/dist/renderers/html/html.js +441 -0
- package/dist/renderers/html/js.d.ts +3 -0
- package/dist/renderers/html/js.js +174 -0
- package/dist/types/types.d.ts +341 -0
- package/dist/types/types.js +54 -0
- package/package.json +43 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const MINIFIED_CSS = `body{background-color:#3a3c43;color:#dbdee1;font-family:"Whitney","Helvetica Neue",Helvetica,Arial,sans-serif;margin:0;padding:0;width:100%}header{height:fit-content;border-bottom:2px solid black;margin-top:2rem;padding-left:2rem;padding-bottom:1rem;display:flex;flex-direction:column;display:flex;flex-direction:row}a{text-decoration:none;color:#1E90FF}p{margin:0}h1{margin:.5rem 0}h2{margin:.3rem 0}h3{margin:.15rem}h4{margin:0}code{border:1px solid #202225;border-radius:.25rem}blockquote{margin:.5rem 0;border-left:.25rem solid #4f545c;padding:.4rem .6rem;border-radius:.25rem;color:#9f9fa6}.c1{display:flex;align-items:baseline;gap:.5rem}.c2{background-color:#5865f2;color:white;font-weight:600;font-size:80%;padding:.1rem .35rem;border-radius:.25rem;letter-spacing:.03rem;height:fit-content;width:fit-content;align-self:flex-start}.c3{background-color:#747F8D50;color:white;font-weight:600;font-size:70%;padding:.1rem .35rem;border-radius:.25rem;letter-spacing:.03rem;height:fit-content;width:fit-content;align-self:center}.c4{background-color:#5664fa41;padding:.2rem;border-radius:.25rem;transition:background-color .2s ease}.c4:hover{background-color:#5664fa7e}.c5{width:7rem;height:7rem;border-radius:50%;background-color:#4f545c;display:flex;align-items:center;justify-content:center;font-size:3rem;font-weight:600}.c6{display:flex;flex-direction:column;gap:.2rem;padding:.5rem;border-radius:1rem}.c6.highlight,.c6:hover{background-color:#40434b;transition:background-color .3s ease-in-out}.c7{display:flex;flex-direction:row;gap:1rem;padding:.5rem;border-radius:.25rem}.c8{width:3.5rem;height:3.5rem;border-radius:50%}.c9{display:flex;flex-direction:column;gap:.25rem}.c10{display:flex;flex-direction:row;gap:.75rem}.c11{margin:0}.c12{color:#999;font-size:77.5%;align-self:center}.c13{line-height:1.5}.c14{white-space:pre-wrap}.c15{font-size:85%;color:#808080}.c16{display:inline-block;background-color:#202225;color:#202225;padding:0 .2rem;border-radius:.2rem;cursor:pointer;transition:background-color .1s ease-in-out,color .1s ease-in-out}.c16.revealed{background-color:transparent;color:inherit}.c17{display:flex;align-items:center;gap:.5rem;font-size:.8rem;color:#b5bac1;cursor:pointer;margin-left:2rem}.c18{flex-shrink:0;width:2.25rem;height:2.25rem;color:#b5bac1}.c19{width:1.75rem;height:1.75rem;border-radius:50%;flex-shrink:0}.c20{font-weight:600;color:#dbdee1;margin-right:.3rem}.c21{background-color:#5865f2;color:white;font-weight:600;font-size:70%;padding:.1rem .3rem;border-radius:.25rem;letter-spacing:.03rem;height:fit-content;align-self:center;flex-shrink:0}.c22{flex-grow:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#b5bac1;font-size:.75rem}.c23{background-color:#2b2d31;border:.15rem solid #2b2d31;border-left:.25rem solid;border-radius:.25rem;padding:.5rem .75rem;margin-top:.5rem;display:flex;flex-direction:column;gap:.5rem;max-width:40rem;min-width:30rem}.c23 a{color:#00aff4;text-decoration:none}.c23 a:hover{text-decoration:underline}.c24{display:flex;justify-content:space-between;align-items:flex-start;gap:.5rem}.c25{display:flex;flex-direction:column;gap:.25rem}.c26{display:flex;align-items:center;gap:.5rem;font-size:.875rem;font-weight:500;color:#fff;margin-bottom:.5rem}.c27{width:1.5rem;height:1.5rem;border-radius:50%}.c28{color:#fff;font-weight:500}.c29{font-size:1rem;font-weight:700;color:#fff;margin-bottom:.75rem}.c30{max-width:80px;max-height:80px;object-fit:contain;border-radius:.25rem;flex-shrink:0}.c31{font-size:.875rem;color:#dcddde}.c32{display:flex;flex-wrap:wrap;gap:.5rem}.c33{flex:1;min-width:150px}.c34{font-size:.75rem;font-weight:700;color:#fff;margin-bottom:.25rem}.c35{font-size:.875rem;color:#dcddde}.c36{margin-top:.5rem;max-width:100%;height:auto}.c36 img{max-width:100%;max-height:300px;object-fit:contain;border-radius:.25rem}.c37{display:flex;align-items:center;gap:.5rem;font-size:.75rem;color:#999;margin-top:.5rem}.c38{width:1.25rem;height:1.25rem;border-radius:50%}.c39{color:#999}.c40,.c41{max-width:400px;height:auto;border-radius:.25rem;margin-top:.5rem}.c42{width:300px;margin-top:.5rem}.c43{background-color:#2b2d31;border:1px solid #202225;border-radius:.75rem;padding:.75rem;display:flex;align-items:center;gap:.75rem;max-width:400px;margin-top:.5rem;width:fit-content}.c44{width:2.5rem;height:2.5rem;fill:#b9bbbe;flex-shrink:0}.c45{display:flex;flex-direction:column;gap:.1rem;overflow:hidden;flex-grow:1}.c46{color:#fff;text-decoration:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.c47{font-size:.75rem;color:#72767d}.c48{display:block;flex-shrink:0}.c49{width:1.5rem;height:1.5rem;fill:#b9bbbe;transition:fill .2s ease}.c48:hover .c49{fill:#fff}.c50{position:relative;display:inline-block;border-radius:.5rem;overflow:hidden;cursor:pointer}.c50 .c51{filter:blur(64px);pointer-events:none;transition:filter .2s ease;width:100%;height:100%}.c50 .c52{position:absolute;inset:0;background:rgba(32,34,37,.85);color:#fff;font-weight:600;letter-spacing:.05em;display:flex;align-items:center;justify-content:center;z-index:2;user-select:none}.c50.revealed .c51{filter:none;pointer-events:auto}.c50.revealed .c52{display:none}.c53{display:flex;gap:.5rem;margin-top:.5rem}.c54{display:flex;align-items:center;gap:.5rem;padding:0 .8rem;height:2.5rem;border-radius:.6rem;color:white;font-weight:600;cursor:pointer;transition:filter .2s ease}.c54:hover{filter:brightness(1.1)}.c55{font-size:1.25rem}.c56{font-size:.875rem}.c57{display:flex;align-items:center;gap:.5rem;color:white;font-weight:600}.c58{width:1.25rem;height:1.25rem}.c59{width:100%;position:relative}.c60{background-color:#2b2d31;border:1px solid #202225;border-radius:.75rem;padding:.75rem;min-width:17.5rem;cursor:pointer;user-select:none}.c61{color:#808080}.c62{display:none;position:absolute;top:100%;left:0;width:100%;background-color:#2b2d31;border:1px solid #202225;border-radius:1rem;margin-top:.25rem;padding:.5rem;z-index:10;box-sizing:border-box}.c59.active .c62{display:block}.c63{display:flex;align-items:center;gap:.5rem;padding:.75rem;border-radius:.75rem;cursor:pointer;transition:background-color .2s ease}.c63:hover{background-color:#4f545c}.c64{font-size:1.25rem}.c65{display:flex;flex-direction:column}.c66{font-weight:500}.c67{font-size:.75rem;color:#808080}.c68{display:flex;flex-wrap:wrap;gap:.25rem;width:100%;max-width:40rem;aspect-ratio:1/1;border:1px solid #202225;padding:.35rem;overflow:hidden}.c69{flex-grow:1;flex-basis:0;min-width:30%;display:flex}.c70{width:100%;height:100%;object-fit:cover;display:block;border-radius:1rem}.c71{background-color:#2b2d31;border-radius:.5rem;padding:1rem;max-width:40rem;min-width:30rem;border-left:.25rem solid}.c72{display:flex;flex-direction:row;justify-content:space-between;padding:.5rem 0}.c73{margin-right:.5rem;margin-left:1rem}.c74{width:5rem;height:5rem;border-radius:.5rem}.c75{padding:.5rem 0}.c76{border:1px solid #808080}.c77{background-color:#2b2d31;border-radius:.5rem;padding:1rem;margin-top:.5rem;max-width:40rem;min-width:25rem}.c78{font-size:1.1rem;font-weight:700;margin-bottom:1rem;display:flex;align-items:center;gap:.5rem}.c79{display:flex;flex-direction:column;gap:.5rem}.c80{background-color:#3a3c42;border-radius:.3rem;padding:.75rem;cursor:pointer;border:1px solid transparent;transition:border-color .2s ease;position:relative;overflow:hidden}.c80:hover{border-color:#4d515a}.c81{position:absolute;top:0;left:0;height:100%;background-color:#5664fa7a;border-radius:.2rem;z-index:1}.c82{position:relative;z-index:2;display:flex;align-items:center;justify-content:space-between}.c83{display:flex;align-items:center;gap:.5rem}.c84{font-size:1.25rem}.c85{font-weight:500}.c86{font-size:.8rem;color:#b5bac1;font-weight:700}.c87{margin-top:1rem;font-size:.75rem;color:#949ba4}.c88{background-color:#2b2d31;border-radius:.5rem;padding:1rem;margin-top:.5rem;border:1px solid #3a3c42;min-width:20rem;max-width:40rem;display:flex;flex-direction:row;justify-content:space-between}.c89{display:flex;align-items:center;gap:.5rem;font-size:1rem;font-weight:600;margin-bottom:.4rem}.c90{color:#57f287;font-size:1.1em}.c91{font-size:.9rem;color:#b5bac1}.c92{margin-right:.5rem;margin-left:1rem;align-self:center}.c93{background-color:black;color:white;padding:.5rem 1rem;border-radius:.3rem;text-decoration:none;font-weight:500;transition:background-color .2s ease;cursor:pointer}.c93:hover{filter:brightness(1.1)}.c94{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.5rem}.c95{align-items:center;background-color:#2b2d31;border:1px solid #3a3c42;border-radius:1rem;padding:.25rem .6rem;font-size:1rem;color:#dcddde;font-weight:700;cursor:pointer}.c95:hover{filter:brightness(1.1)}`;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { JsonData } from "../../types/types.js";
|
|
2
|
+
export declare class Html {
|
|
3
|
+
data: JsonData;
|
|
4
|
+
dateFormat: Intl.DateTimeFormat;
|
|
5
|
+
constructor(data: JsonData);
|
|
6
|
+
private getIcon;
|
|
7
|
+
private headerBuilder;
|
|
8
|
+
private messagesBuilder;
|
|
9
|
+
toHTML(): string;
|
|
10
|
+
private pollBuilder;
|
|
11
|
+
private pollResultEmbedBuilder;
|
|
12
|
+
private embedBuilder;
|
|
13
|
+
private attachmentBuilder;
|
|
14
|
+
private componentBuilder;
|
|
15
|
+
private buttonBuilder;
|
|
16
|
+
private selectorBuilder;
|
|
17
|
+
private reactionsBuilder;
|
|
18
|
+
private spoilerAttachmentBuilder;
|
|
19
|
+
private svgBuilder;
|
|
20
|
+
}
|
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
import { CustomError } from "../../core/error.js";
|
|
2
|
+
import { markdownToHTML } from "../../core/markdown.js";
|
|
3
|
+
import { JsonButtonStyle, JsonComponentType } from "../../types/types.js";
|
|
4
|
+
import { ACTIONROW_CSS, ATTACHMENT_CSS, BUTTON_CSS, COMPONENTS_CSS, COMPONENTSV2_CSS, DEFAULT_CSS, EMBED_CSS, MESSAGE_CSS, POLL_CSS, POLL_RESULT_EMBED_CSS, REACTIONS_CSS } from "./css.js";
|
|
5
|
+
import { script } from "./js.js";
|
|
6
|
+
import packageJson from "./../../../package.json" with { type: 'json' };
|
|
7
|
+
const COUNT_UNIT = ["KB", "MB", "GB", "TB"];
|
|
8
|
+
const BUTTON_COLOR = ["black", "#5865f2", "#323538", "#32c05f", "#be3638", "#323538", "#5865f2"];
|
|
9
|
+
export class Html {
|
|
10
|
+
data;
|
|
11
|
+
dateFormat;
|
|
12
|
+
constructor(data) {
|
|
13
|
+
this.data = data;
|
|
14
|
+
try {
|
|
15
|
+
this.dateFormat = new Intl.DateTimeFormat(data.options.localDate, {
|
|
16
|
+
timeZone: data.options.timeZone,
|
|
17
|
+
day: '2-digit',
|
|
18
|
+
month: '2-digit',
|
|
19
|
+
year: 'numeric',
|
|
20
|
+
hour: '2-digit',
|
|
21
|
+
minute: '2-digit',
|
|
22
|
+
second: '2-digit'
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
throw new CustomError("[discord-message-transcript] Invalid LocalDate and/or TimeZone.");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
getIcon() {
|
|
30
|
+
const { guild, channel } = this.data;
|
|
31
|
+
if (guild) {
|
|
32
|
+
if (guild.icon) {
|
|
33
|
+
return `<img src="${guild.icon}" style="width: 7rem; height: 7rem; border-radius: 50%;">`;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return `<div class="guildInitialsIcon">${initials(guild.name)}</div>`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
return `<img src="${channel.img}" style="width: 7rem; height: 7rem; border-radius: 50%;">`;
|
|
41
|
+
}
|
|
42
|
+
function initials(name) {
|
|
43
|
+
const words = name.split(' ').filter(word => word.length > 0);
|
|
44
|
+
if (words.length >= 1) {
|
|
45
|
+
return words.map(word => word[0]).join('').substring(0, 3).toUpperCase();
|
|
46
|
+
}
|
|
47
|
+
return name.substring(0, 1).toUpperCase();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
headerBuilder() {
|
|
51
|
+
const { channel, guild } = this.data;
|
|
52
|
+
return `
|
|
53
|
+
<div style="display: flex; gap: 1.5rem; align-items: center; width 100vw">
|
|
54
|
+
${this.getIcon()}
|
|
55
|
+
<div style="display: flex; flex-direction: column; justify-content: center; gap: 1.25rem;">
|
|
56
|
+
${guild ? `<div id="guild" class="line">
|
|
57
|
+
<h4>Guild: </h4>
|
|
58
|
+
<h4 style="font-weight: normal;">${guild.name}</h4>
|
|
59
|
+
</div>` : ""}
|
|
60
|
+
${channel.parent ? `<div id="category" class="line">
|
|
61
|
+
<h4>Category: </h4>
|
|
62
|
+
<h4 style="font-weight: normal;">${channel.parent.name}</h4>
|
|
63
|
+
</div>` : ""}
|
|
64
|
+
<div id="channel" class="line">
|
|
65
|
+
<h4>Channel: </h4>
|
|
66
|
+
<h4 style="font-weight: normal;">${channel.name}</h4>
|
|
67
|
+
</div>
|
|
68
|
+
${channel.topic ? `<div id="topic" class="line">
|
|
69
|
+
<h4>Topic: </h4>
|
|
70
|
+
<h4 style="font-weight: normal;">${channel.topic}</h4>
|
|
71
|
+
</div>` : ""}
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
messagesBuilder() {
|
|
77
|
+
return this.data.messages.map(message => {
|
|
78
|
+
const date = new Date(message.createdTimestamp);
|
|
79
|
+
return `
|
|
80
|
+
<div class="messageDiv" id="${message.id}" data-author-id="${message.authorId}">
|
|
81
|
+
${message.references && message.references.messageId ?
|
|
82
|
+
`<div class="messageReply" data-id="${message.references.messageId}">
|
|
83
|
+
<svg class="messageReplySvg"><use href="#reply-icon"></use></svg>
|
|
84
|
+
<img class="messageReplyImg" src="">
|
|
85
|
+
<div class="replyBadges"></div>
|
|
86
|
+
<div class="messageReplyText"></div>
|
|
87
|
+
</div>` : ""}
|
|
88
|
+
<div class="messageBotton">
|
|
89
|
+
<img src="" class="messageImg">
|
|
90
|
+
<div class="messageDivRight">
|
|
91
|
+
<div class="messageUser">
|
|
92
|
+
<h3 class="messageUsername"></h3>
|
|
93
|
+
<div class="badges"></div>
|
|
94
|
+
<p class="messageTimeStamp">${this.dateFormat.format(date)}</p>
|
|
95
|
+
</div>
|
|
96
|
+
<div class="messageContent">${markdownToHTML(message.content, this.data.mentions, message.mentions, this.dateFormat)}</div>
|
|
97
|
+
${message.poll ? this.pollBuilder(message.poll) : ""}
|
|
98
|
+
${message.embeds.length > 0 ? this.embedBuilder(message, message.embeds) : ""}
|
|
99
|
+
${message.attachments.length > 0 ? this.attachmentBuilder(message.attachments) : ""}
|
|
100
|
+
${message.components.length > 0 ? this.componentBuilder(message, message.components) : ""}
|
|
101
|
+
${message.reactions.length > 0 ? this.reactionsBuilder(message.reactions) : ""}
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
`;
|
|
106
|
+
}).join("");
|
|
107
|
+
}
|
|
108
|
+
toHTML() {
|
|
109
|
+
const { options } = this.data;
|
|
110
|
+
const cssContent = `
|
|
111
|
+
${DEFAULT_CSS}
|
|
112
|
+
${MESSAGE_CSS}
|
|
113
|
+
${options.includePolls ? POLL_CSS + POLL_RESULT_EMBED_CSS : ""}
|
|
114
|
+
${options.includeEmbeds ? EMBED_CSS : ""}
|
|
115
|
+
${options.includeButtons || options.includeComponents ? ACTIONROW_CSS : ""}
|
|
116
|
+
${options.includeAttachments || options.includeV2Components ? ATTACHMENT_CSS : ""}
|
|
117
|
+
${options.includeButtons || options.includeV2Components ? BUTTON_CSS : ""}
|
|
118
|
+
${options.includeComponents ? COMPONENTS_CSS : ""}
|
|
119
|
+
${options.includeV2Components ? COMPONENTSV2_CSS : ""}
|
|
120
|
+
${options.includeReactions ? REACTIONS_CSS : ""}
|
|
121
|
+
`;
|
|
122
|
+
const jsContent = script(options.includeComponents, options.includePolls);
|
|
123
|
+
return `
|
|
124
|
+
<!DOCTYPE html>
|
|
125
|
+
<html lang="${options.localDate}">
|
|
126
|
+
<head>
|
|
127
|
+
<meta charset="UTF-8" />
|
|
128
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
129
|
+
<title>${options.fileName}</title>
|
|
130
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/styles/atom-one-dark.min.css">
|
|
131
|
+
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/highlight.min.js"></script>
|
|
132
|
+
${options.selfContained ? `<style>${cssContent}</style>` : `<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/discord-message-transcript-base@${packageJson.version}/dist/assets/style.css">`}
|
|
133
|
+
</head>
|
|
134
|
+
<body>
|
|
135
|
+
${this.svgBuilder()}
|
|
136
|
+
<header>
|
|
137
|
+
${this.headerBuilder()}
|
|
138
|
+
</header>
|
|
139
|
+
<main style="display: flex; flex-direction: column; padding: 2.25%;">
|
|
140
|
+
${this.messagesBuilder()}
|
|
141
|
+
</main>
|
|
142
|
+
${options.watermark ? `<footer>
|
|
143
|
+
<br>
|
|
144
|
+
<div style="padding: 1rem 0; font-weight: 700; text-align: center; font-size: 1.5rem; background-color: #2b2d31;">Transcript generated by <a href="https://github.com/HenriqueMairesse/discord-message-transcript">discord-message-transcript</a></div>
|
|
145
|
+
</footer> ` : ""}
|
|
146
|
+
<script id="authorData" type="application/json">
|
|
147
|
+
${JSON.stringify({ authors: this.data.authors })}
|
|
148
|
+
</script>
|
|
149
|
+
${options.selfContained ? `<script>${jsContent}</script>` : `<script src="https://cdn.jsdelivr.net/npm/discord-message-transcript-base@${packageJson.version}/dist/assets/script.js"></script>`}
|
|
150
|
+
</body>
|
|
151
|
+
</html>
|
|
152
|
+
`;
|
|
153
|
+
}
|
|
154
|
+
pollBuilder(poll) {
|
|
155
|
+
const totalVotes = poll.answers.reduce((acc, answer) => acc + answer.count, 0);
|
|
156
|
+
let footerText = `${totalVotes} votes`;
|
|
157
|
+
if (poll.isFinalized) {
|
|
158
|
+
footerText += ` • Poll closed`;
|
|
159
|
+
}
|
|
160
|
+
else if (poll.expiry) {
|
|
161
|
+
footerText += ` • ${poll.expiry}`;
|
|
162
|
+
}
|
|
163
|
+
return `
|
|
164
|
+
<div class="pollDiv">
|
|
165
|
+
<div class="pollQuestion">${poll.question}</div>
|
|
166
|
+
<div class="pollAnswers">
|
|
167
|
+
${poll.answers.map(answer => {
|
|
168
|
+
const voteCount = answer.count;
|
|
169
|
+
const percentage = totalVotes > 0 ? (voteCount / totalVotes) * 100 : 0;
|
|
170
|
+
return `
|
|
171
|
+
<div class="pollAnswer">
|
|
172
|
+
<div class="pollAnswerBar" style="width: ${percentage}%;"></div>
|
|
173
|
+
<div class="pollAnswerContent">
|
|
174
|
+
<div class="pollAnswerDetails">
|
|
175
|
+
${answer.emoji ? `<div class="pollAnswerEmoji">${answer.emoji.name}</div>` : ''}
|
|
176
|
+
<div class="pollAnswerText">${answer.text}</div>
|
|
177
|
+
</div>
|
|
178
|
+
<div class="pollAnswerVotes">${voteCount}</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
`;
|
|
182
|
+
}).join('')}
|
|
183
|
+
</div>
|
|
184
|
+
<div class="pollFooter">${footerText}</div>
|
|
185
|
+
</div>
|
|
186
|
+
`;
|
|
187
|
+
}
|
|
188
|
+
pollResultEmbedBuilder(embed, message) {
|
|
189
|
+
const getField = (name) => embed.fields?.find(f => f.name === name)?.value;
|
|
190
|
+
const winnerText = getField("victor_answer_text");
|
|
191
|
+
const emojiText = getField("victor_answer_emoji_name");
|
|
192
|
+
const winnerVotes = parseInt(getField("victor_answer_votes") ?? "0");
|
|
193
|
+
const totalVotes = parseInt(getField("total_votes") ?? "0");
|
|
194
|
+
const winnerPercentage = totalVotes > 0 ? (winnerVotes / totalVotes) * 100 : 0;
|
|
195
|
+
if (!winnerText && winnerVotes != 0)
|
|
196
|
+
return '';
|
|
197
|
+
return `
|
|
198
|
+
<div class="pollResultEmbed">
|
|
199
|
+
<div>
|
|
200
|
+
<div class="pollResultEmbedWinner">
|
|
201
|
+
${emojiText ? emojiText : ""}
|
|
202
|
+
${winnerText ?? "There was no winner"}
|
|
203
|
+
${winnerVotes != 0 ? `<span class="pollResultEmbedCheckmark">✔</span>` : ""}
|
|
204
|
+
</div>
|
|
205
|
+
<div class="pollResultEmbedSubtitle">${totalVotes} votes (${winnerPercentage.toFixed(1)}%)</div>
|
|
206
|
+
</div>
|
|
207
|
+
<div class="pollResultEmbedButtonDiv">
|
|
208
|
+
<div data-id="${message.references?.messageId ?? ""}" class="pollResultEmbedButton">View Poll</div>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
`;
|
|
212
|
+
}
|
|
213
|
+
embedBuilder(message, embeds) {
|
|
214
|
+
return embeds.map(embed => {
|
|
215
|
+
if (embed.type === 'poll_result')
|
|
216
|
+
return this.pollResultEmbedBuilder(embed, message);
|
|
217
|
+
if (!this.data.options.includeEmbeds)
|
|
218
|
+
return "";
|
|
219
|
+
const embedAuthor = embed.author ? (embed.author.url ? `<a class="embedHeaderLefttAuthorName" href="${embed.author.url}" target="_blank">${embed.author.name}</a>` : `<p class="embedHeaderLeftAuthorName">${embed.author.name}</p>`) : "";
|
|
220
|
+
const embedTitle = embed.title ? (embed.url ? `<a class="embedHeaderLeftTitle" href="${embed.url}" target="_blank">${embed.title}</a>` : `<p class="embedHeaderLeftTitle">${embed.title}</p>`) : "";
|
|
221
|
+
return `
|
|
222
|
+
<div class="embed" style="${embed.hexColor ? `border-left-color: ${embed.hexColor}` : ''}">
|
|
223
|
+
${embed.author || embed.title || embed.thumbnail || embed.description ? `
|
|
224
|
+
<div class="embedHeader">
|
|
225
|
+
<div class="embedHeaderLeft">
|
|
226
|
+
${embed.author ? `
|
|
227
|
+
<div class="embedHeaderLeftAuthor">
|
|
228
|
+
${embed.author.iconURL ? `<img class="embedHeaderLeftAuthorImg" src="${embed.author.iconURL}">` : ""}
|
|
229
|
+
${embedAuthor}
|
|
230
|
+
</div>` : ""}
|
|
231
|
+
${embedTitle}
|
|
232
|
+
${embed.description ? `<div class="embedDescription">${markdownToHTML(embed.description, this.data.mentions, message.mentions, this.dateFormat)}</div>` : ""}
|
|
233
|
+
</div>
|
|
234
|
+
${embed.thumbnail ? `<img class="embedHeaderThumbnail" src="${embed.thumbnail.url}">` : ""}
|
|
235
|
+
</div>` : ""}
|
|
236
|
+
${embed.fields && embed.fields.length > 0 ? `
|
|
237
|
+
<div class="embedFields">
|
|
238
|
+
${embed.fields.map(field => `
|
|
239
|
+
<div class="embedFieldsField" style="${field.inline ? 'display: inline-block;' : ''}">
|
|
240
|
+
<p class="embedFieldsFieldTitle">${field.name}</p>
|
|
241
|
+
<p class="embedFieldsFieldValue">${markdownToHTML(field.value, this.data.mentions, message.mentions, this.dateFormat)}</p>
|
|
242
|
+
</div>`).join("")}
|
|
243
|
+
</div>` : ""}
|
|
244
|
+
${embed.image ? `
|
|
245
|
+
<div class="embedImage">
|
|
246
|
+
<img src="${embed.image.url}">
|
|
247
|
+
</div>` : ""}
|
|
248
|
+
${embed.footer || embed.timestamp ? `
|
|
249
|
+
<div class="embedFooter">
|
|
250
|
+
${embed.footer?.iconURL ? `<img class="embedFooterImg" src="${embed.footer.iconURL}">` : ""}
|
|
251
|
+
${embed.footer?.text || embed.timestamp ? `<p class="embedFooterText">${embed.footer?.text ?? ''}${embed.footer?.text && embed.timestamp ? ' | ' : ''}${embed.timestamp ? this.dateFormat.format(new Date(embed.timestamp)) : ''}</p>` : ""}
|
|
252
|
+
</div>` : ""}
|
|
253
|
+
</div>
|
|
254
|
+
`;
|
|
255
|
+
}).join("");
|
|
256
|
+
}
|
|
257
|
+
attachmentBuilder(attachments) {
|
|
258
|
+
return attachments.map(attachment => {
|
|
259
|
+
let html = "";
|
|
260
|
+
if (attachment.contentType?.startsWith('image/')) {
|
|
261
|
+
html = `<img class="attachmentImage" src="${attachment.url}">`;
|
|
262
|
+
}
|
|
263
|
+
else if (attachment.contentType?.startsWith('video/')) {
|
|
264
|
+
html = `<video class="attachmentVideo" controls src="${attachment.url}"></video>`;
|
|
265
|
+
}
|
|
266
|
+
else if (attachment.contentType?.startsWith('audio/')) {
|
|
267
|
+
html = `<audio class="attachmentAudio" controls src="${attachment.url}"></audio>`;
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
let fileSize = attachment.size / 1024;
|
|
271
|
+
let count = 0;
|
|
272
|
+
while (fileSize > 512 && count < COUNT_UNIT.length - 1) {
|
|
273
|
+
fileSize = fileSize / 1024;
|
|
274
|
+
count++;
|
|
275
|
+
}
|
|
276
|
+
html = `
|
|
277
|
+
<div class="attachmentFile">
|
|
278
|
+
<div class="attachmentFileInfo">
|
|
279
|
+
<p class="attachmentFileName">${attachment.name ?? 'attachment'}</p>
|
|
280
|
+
<div class="attachmentFileSize">${fileSize.toFixed(2)} ${COUNT_UNIT[count]}</div>
|
|
281
|
+
</div>
|
|
282
|
+
<a class="attachmentDownload" href="${attachment.url}" target="_blank">
|
|
283
|
+
<svg class="attachmentDownloadIcon"><use href="#download-icon"></use></svg>
|
|
284
|
+
</a>
|
|
285
|
+
</div>
|
|
286
|
+
`;
|
|
287
|
+
}
|
|
288
|
+
return this.spoilerAttachmentBuilder(attachment.spoiler, html);
|
|
289
|
+
}).join("");
|
|
290
|
+
}
|
|
291
|
+
componentBuilder(message, components) {
|
|
292
|
+
return components.map(component => {
|
|
293
|
+
switch (component.type) {
|
|
294
|
+
case JsonComponentType.ActionRow: {
|
|
295
|
+
if (!component.components[0])
|
|
296
|
+
return "";
|
|
297
|
+
return `
|
|
298
|
+
<div class="actionRow">
|
|
299
|
+
${component.components[0].type == JsonComponentType.Button ? component.components.map(button => {
|
|
300
|
+
return button.type == JsonComponentType.Button ? this.buttonBuilder(button) : "";
|
|
301
|
+
}).join("") : this.selectorBuilder(component.components[0])}
|
|
302
|
+
</div>
|
|
303
|
+
`;
|
|
304
|
+
}
|
|
305
|
+
case JsonComponentType.Container: {
|
|
306
|
+
const html = `
|
|
307
|
+
<div class="container" style="${component.hexAccentColor ? `border-left-color: ${component.hexAccentColor}` : ''}">
|
|
308
|
+
${this.componentBuilder(message, component.components)}
|
|
309
|
+
</div>
|
|
310
|
+
`;
|
|
311
|
+
return this.spoilerAttachmentBuilder(component.spoiler, html);
|
|
312
|
+
}
|
|
313
|
+
case JsonComponentType.File: {
|
|
314
|
+
let fileSize = (component.size ?? 0) / 1024;
|
|
315
|
+
let count = 0;
|
|
316
|
+
while (fileSize > 512 && count < COUNT_UNIT.length - 1) {
|
|
317
|
+
fileSize = fileSize / 1024;
|
|
318
|
+
count++;
|
|
319
|
+
}
|
|
320
|
+
const html = `
|
|
321
|
+
<div class="attachmentFile">
|
|
322
|
+
<div class="attachmentFileInfo">
|
|
323
|
+
<p class="attachmentFileName">${component.fileName ?? 'file'}</p>
|
|
324
|
+
<div class="attachmentFileSize">${fileSize.toFixed(2)} ${COUNT_UNIT[count]}</div>
|
|
325
|
+
</div>
|
|
326
|
+
<a class="attachmentDownload" href="${component.url ?? ''}" target="_blank">
|
|
327
|
+
<svg class="attachmentDownloadIcon"><use href="#download-icon"></use></svg>
|
|
328
|
+
</a>
|
|
329
|
+
</div>
|
|
330
|
+
`;
|
|
331
|
+
return this.spoilerAttachmentBuilder(component.spoiler, html);
|
|
332
|
+
}
|
|
333
|
+
case JsonComponentType.MediaGallery: {
|
|
334
|
+
return `
|
|
335
|
+
<div class="mediaGallery">
|
|
336
|
+
${component.items.map(image => {
|
|
337
|
+
return `
|
|
338
|
+
<div class="mediaGalleryItem">
|
|
339
|
+
${this.spoilerAttachmentBuilder(image.spoiler, `<img class="mediaGalleryImg" src="${image.media.url}">`)}
|
|
340
|
+
</div>
|
|
341
|
+
`;
|
|
342
|
+
}).join("")}
|
|
343
|
+
</div>
|
|
344
|
+
`;
|
|
345
|
+
}
|
|
346
|
+
case JsonComponentType.Section: {
|
|
347
|
+
return `
|
|
348
|
+
<div class="section">
|
|
349
|
+
<div class="sectionLeft">
|
|
350
|
+
${this.componentBuilder(message, component.components)}
|
|
351
|
+
</div>
|
|
352
|
+
<div class="sectionRight">
|
|
353
|
+
${component.accessory.type == JsonComponentType.Button ? this.buttonBuilder(component.accessory)
|
|
354
|
+
: component.accessory.type == JsonComponentType.Thumbnail ? this.spoilerAttachmentBuilder(component.accessory.spoiler, `
|
|
355
|
+
<img class="sectionThumbnail" src="${component.accessory.media.url}">
|
|
356
|
+
`) : ""}
|
|
357
|
+
</div>
|
|
358
|
+
</div>
|
|
359
|
+
`;
|
|
360
|
+
}
|
|
361
|
+
case JsonComponentType.Separator: {
|
|
362
|
+
return `<hr class="separator" style="${component.divider ? "" : "visibility: hidden;"} ${component.spacing == 1 ? "margin: 0.15rem 0;" : "margin: 0.3rem 0;"}">`;
|
|
363
|
+
}
|
|
364
|
+
case JsonComponentType.TextDisplay: {
|
|
365
|
+
return `<div class="textDisplay">${markdownToHTML(component.content, this.data.mentions, message.mentions, this.dateFormat)}</div>`;
|
|
366
|
+
}
|
|
367
|
+
default:
|
|
368
|
+
return ``;
|
|
369
|
+
}
|
|
370
|
+
}).join("");
|
|
371
|
+
}
|
|
372
|
+
buttonBuilder(button) {
|
|
373
|
+
return `
|
|
374
|
+
<div class="button" style="background-color: ${BUTTON_COLOR[button.style]}">
|
|
375
|
+
${button.style == JsonButtonStyle.Link && button.url ? `
|
|
376
|
+
<a class="buttonLink" href="${button.url}" target="_blank">
|
|
377
|
+
${button.emoji ? `<p class="buttonEmoji">${button.emoji}</p>` : ""}
|
|
378
|
+
${button.label ? `<p class="buttonLabel">${button.label}</p>` : ""}
|
|
379
|
+
<svg class="buttonLinkIcon"><use href="#link-icon"></use></svg>
|
|
380
|
+
</a>` : `
|
|
381
|
+
${button.emoji ? `<p class="buttonEmoji">${button.emoji}</p>` : ""}
|
|
382
|
+
${button.label ? `<p class="buttonLabel">${button.label}</p>` : ""}
|
|
383
|
+
`}
|
|
384
|
+
</div>
|
|
385
|
+
`;
|
|
386
|
+
}
|
|
387
|
+
selectorBuilder(selector) {
|
|
388
|
+
return `
|
|
389
|
+
<div class="selector">
|
|
390
|
+
<div class="selectorInput">
|
|
391
|
+
<p class="selectorInputText">${selector.placeholder}</p>
|
|
392
|
+
</div>
|
|
393
|
+
<div class="selectorOptionMenu">
|
|
394
|
+
${selector.type == JsonComponentType.StringSelect ? selector.options.map(option => {
|
|
395
|
+
return `
|
|
396
|
+
<div class="selectorOption">
|
|
397
|
+
${option.emoji ? `<p class="selectorOptionEmoji">${option.emoji}</p>` : ""}
|
|
398
|
+
<div class="selectorOptionRight">
|
|
399
|
+
<p class="selectorOptionTitle">${option.label}</p>
|
|
400
|
+
${option.description ? `<p class="selectorOptionDesc">${option.description}</p>` : ""}
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
`;
|
|
404
|
+
}).join("") : ""}
|
|
405
|
+
</div>
|
|
406
|
+
</div>
|
|
407
|
+
`;
|
|
408
|
+
}
|
|
409
|
+
reactionsBuilder(reactions) {
|
|
410
|
+
return `
|
|
411
|
+
<div class="reactionsDiv">
|
|
412
|
+
${reactions.map(reaction => `
|
|
413
|
+
<div class="reaction"><p>${reaction.count} ${reaction.emoji}</p></div>
|
|
414
|
+
`).join('')}
|
|
415
|
+
</div>
|
|
416
|
+
`;
|
|
417
|
+
}
|
|
418
|
+
spoilerAttachmentBuilder(spoiler, html) {
|
|
419
|
+
return spoiler ? `<div class="spoilerAttachment"><div class="spoilerAttachmentOverlay">SPOILER</div><div class="spoilerAttachmentContent">${html}</div></div>` : html;
|
|
420
|
+
}
|
|
421
|
+
svgBuilder() {
|
|
422
|
+
const { options } = this.data;
|
|
423
|
+
return `
|
|
424
|
+
<svg style="display: none;">
|
|
425
|
+
<defs>
|
|
426
|
+
<symbol id="reply-icon" viewBox="0 0 16 16" fill="none">
|
|
427
|
+
<g transform="rotate(90 8 8)">
|
|
428
|
+
<path d="M6 2V9C6 11.5 8.5 14 11 14H14" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
|
429
|
+
</g>
|
|
430
|
+
</symbol>
|
|
431
|
+
${options.includeAttachments ? `<symbol id="download-icon" viewBox="0 -960 960 960">
|
|
432
|
+
<path d="m720-120 160-160-56-56-64 64v-167h-80v167l-64-64-56 56 160 160ZM560 0v-80h320V0H560ZM240-160q-33 0-56.5-23.5T160-240v-560q0-33 23.5-56.5T240-880h280l240 240v121h-80v-81H480v-200H240v560h240v80H240Zm0-80v-560 560Z"/>
|
|
433
|
+
</symbol> ` : ""}
|
|
434
|
+
${options.includeButtons ? `<symbol id="link-icon" viewBox="0 -960 960 960" fill="#e3e3e3">
|
|
435
|
+
<path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h560v-280h80v280q0 33-23.5 56.5T760-120H200Zm188-212-56-56 372-372H560v-80h280v280h-80v-144L388-332Z"/>
|
|
436
|
+
</symbol>` : ""}
|
|
437
|
+
</defs>
|
|
438
|
+
</svg>
|
|
439
|
+
`;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function script(includeComponents: boolean, includePolls: boolean): string;
|
|
2
|
+
export declare const POLL_JS = "\nconst pollDiv = event.target.closest('.pollResultEmbedButton');\nif (pollDiv) {\n event.preventDefault();\n const messageId = pollDiv.dataset.id;\n if (!messageId || messageId == \"\") return;\n const message = document.getElementById(messageId);\n\n if (message) {\n message.scrollIntoView({ behavior: 'smooth', block: 'center' });\n message.classList.add('highlight');\n setTimeout(() => {\n message.classList.remove('highlight');\n }, 1500);\n }\n}\n";
|
|
3
|
+
export declare const SELECTOR_JS = "\nconst selectorInput = event.target.closest('.selectorInput');\ndocument.querySelectorAll('.selector').forEach(selector => {\n if (!selector.contains(event.target)) {\n selector.classList.remove('active');\n }\n});\n\nif (selectorInput) {\n const selector = selectorInput.closest('.selector');\n if (selector) {\n selector.classList.toggle('active');\n }\n}\n";
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
export function script(includeComponents, includePolls) {
|
|
2
|
+
return `
|
|
3
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
4
|
+
const transcriptDataElement = document.getElementById('authorData');
|
|
5
|
+
if (!transcriptDataElement) {
|
|
6
|
+
console.error('Missing author data element.');
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const data = JSON.parse(transcriptDataElement.textContent);
|
|
11
|
+
const authorMap = new Map((data.authors || []).map(author => [author.id, author]));
|
|
12
|
+
|
|
13
|
+
document.querySelectorAll('.messageDiv[data-author-id]').forEach(messageDiv => {
|
|
14
|
+
const authorId = messageDiv.dataset.authorId;
|
|
15
|
+
const author = authorMap.get(authorId);
|
|
16
|
+
|
|
17
|
+
if (!author) return;
|
|
18
|
+
|
|
19
|
+
const avatarImg = messageDiv.querySelector('.messageImg');
|
|
20
|
+
if (avatarImg) avatarImg.src = author.avatarURL;
|
|
21
|
+
|
|
22
|
+
const username = messageDiv.querySelector('.messageUsername');
|
|
23
|
+
if (username) {
|
|
24
|
+
username.textContent = author.member?.displayName ?? author.displayName;
|
|
25
|
+
username.style.color = author.member?.displayHexColor ?? '#dbdee1';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const badgesDiv = messageDiv.querySelector('.badges');
|
|
29
|
+
if (badgesDiv) {
|
|
30
|
+
badgesDiv.innerHTML = '';
|
|
31
|
+
if (author.bot) {
|
|
32
|
+
const badge = document.createElement('p');
|
|
33
|
+
badge.className = 'badge';
|
|
34
|
+
badge.textContent = 'APP';
|
|
35
|
+
badgesDiv.appendChild(badge);
|
|
36
|
+
}
|
|
37
|
+
if (author.system) {
|
|
38
|
+
const badge = document.createElement('p');
|
|
39
|
+
badge.className = 'badge';
|
|
40
|
+
badge.textContent = 'SYSTEM';
|
|
41
|
+
badgesDiv.appendChild(badge);
|
|
42
|
+
}
|
|
43
|
+
if (author.guildTag) {
|
|
44
|
+
const badge = document.createElement('p');
|
|
45
|
+
badge.className = 'badgeTag';
|
|
46
|
+
badge.textContent = author.guildTag;
|
|
47
|
+
badgesDiv.appendChild(badge);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
document.querySelectorAll('.messageReply[data-id]').forEach(replyDiv => {
|
|
53
|
+
const repliedToId = replyDiv.dataset.id;
|
|
54
|
+
if (!repliedToId) return;
|
|
55
|
+
|
|
56
|
+
const repliedToMessageDiv = document.getElementById(repliedToId);
|
|
57
|
+
if (!repliedToMessageDiv) return;
|
|
58
|
+
|
|
59
|
+
const repliedToAuthorId = repliedToMessageDiv.dataset.authorId;
|
|
60
|
+
const repliedToAuthor = authorMap.get(repliedToAuthorId);
|
|
61
|
+
|
|
62
|
+
if (repliedToAuthor) {
|
|
63
|
+
const replyImg = replyDiv.querySelector('.messageReplyImg');
|
|
64
|
+
if (replyImg) replyImg.src = repliedToAuthor.avatarURL;
|
|
65
|
+
|
|
66
|
+
const replyBadgesDiv = replyDiv.querySelector('.replyBadges');
|
|
67
|
+
if (replyBadgesDiv) {
|
|
68
|
+
replyBadgesDiv.innerHTML = '';
|
|
69
|
+
if (repliedToAuthor.bot) {
|
|
70
|
+
const badge = document.createElement('p');
|
|
71
|
+
badge.className = 'badge';
|
|
72
|
+
badge.textContent = 'APP';
|
|
73
|
+
replyBadgesDiv.appendChild(badge);
|
|
74
|
+
}
|
|
75
|
+
if (repliedToAuthor.system) {
|
|
76
|
+
const badge = document.createElement('p');
|
|
77
|
+
badge.className = 'badge';
|
|
78
|
+
badge.textContent = 'SYSTEM';
|
|
79
|
+
replyBadgesDiv.appendChild(badge);
|
|
80
|
+
}
|
|
81
|
+
if (repliedToAuthor.guildTag) {
|
|
82
|
+
const badge = document.createElement('p');
|
|
83
|
+
badge.className = 'badgeTag';
|
|
84
|
+
badge.textContent = repliedToAuthor.guildTag;
|
|
85
|
+
replyBadgesDiv.appendChild(badge);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const replyTextDiv = replyDiv.querySelector('.messageReplyText');
|
|
91
|
+
if (replyTextDiv) {
|
|
92
|
+
const originalContent = repliedToMessageDiv.querySelector('.messageContent');
|
|
93
|
+
if (originalContent) {
|
|
94
|
+
let content = originalContent.textContent || '';
|
|
95
|
+
if (content.length > 100) {
|
|
96
|
+
content = content.substring(0, 100).trim() + '...';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const authorName = repliedToAuthor?.member?.displayName ?? repliedToAuthor?.displayName ?? 'Unknown';
|
|
100
|
+
const authorColor = repliedToAuthor?.member?.displayHexColor ?? 'inherit';
|
|
101
|
+
|
|
102
|
+
const authorNameSpan = \`<span style="color: \${authorColor};">\${authorName}</span>\`;
|
|
103
|
+
replyTextDiv.innerHTML = authorNameSpan + " " + content;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
document.addEventListener('click', function (event) {
|
|
109
|
+
const spoiler = event.target.closest('.spoilerMsg, .spoilerAttachment');
|
|
110
|
+
if (spoiler && !spoiler.classList.contains('revealed')) {
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
event.stopPropagation();
|
|
113
|
+
spoiler.classList.add('revealed');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const replyDiv = event.target.closest('.messageReply');
|
|
117
|
+
if (replyDiv) {
|
|
118
|
+
event.preventDefault();
|
|
119
|
+
const messageId = replyDiv.dataset.id;
|
|
120
|
+
if (!messageId) return;
|
|
121
|
+
|
|
122
|
+
const message = document.getElementById(messageId);
|
|
123
|
+
if (message) {
|
|
124
|
+
message.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
125
|
+
message.classList.add('highlight');
|
|
126
|
+
setTimeout(() => {
|
|
127
|
+
message.classList.remove('highlight');
|
|
128
|
+
}, 1500);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
${includeComponents ? SELECTOR_JS : ""}
|
|
133
|
+
|
|
134
|
+
${includePolls ? POLL_JS : ""}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
if (window.hljs) {
|
|
138
|
+
hljs.highlightAll();
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
`;
|
|
142
|
+
}
|
|
143
|
+
export const POLL_JS = `
|
|
144
|
+
const pollDiv = event.target.closest('.pollResultEmbedButton');
|
|
145
|
+
if (pollDiv) {
|
|
146
|
+
event.preventDefault();
|
|
147
|
+
const messageId = pollDiv.dataset.id;
|
|
148
|
+
if (!messageId || messageId == "") return;
|
|
149
|
+
const message = document.getElementById(messageId);
|
|
150
|
+
|
|
151
|
+
if (message) {
|
|
152
|
+
message.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
153
|
+
message.classList.add('highlight');
|
|
154
|
+
setTimeout(() => {
|
|
155
|
+
message.classList.remove('highlight');
|
|
156
|
+
}, 1500);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
`;
|
|
160
|
+
export const SELECTOR_JS = `
|
|
161
|
+
const selectorInput = event.target.closest('.selectorInput');
|
|
162
|
+
document.querySelectorAll('.selector').forEach(selector => {
|
|
163
|
+
if (!selector.contains(event.target)) {
|
|
164
|
+
selector.classList.remove('active');
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
if (selectorInput) {
|
|
169
|
+
const selector = selectorInput.closest('.selector');
|
|
170
|
+
if (selector) {
|
|
171
|
+
selector.classList.toggle('active');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
`;
|