discord-message-transcript-base 1.1.4 → 1.1.6-dev.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.
@@ -222,7 +222,7 @@ blockquote {
222
222
  flex-direction: column;
223
223
  gap: 0.5rem;
224
224
  max-width: 40rem;
225
- min-width: 30rem;
225
+ width: fit-content;
226
226
  }
227
227
  .embed a {
228
228
  color: #00aff4;
@@ -278,13 +278,18 @@ blockquote {
278
278
  color: #dcddde;
279
279
  }
280
280
  .embedFields {
281
- display: flex;
282
- flex-wrap: wrap;
281
+ display: grid;
282
+ grid-template-columns: repeat(3, 1fr);
283
283
  gap: 0.5rem;
284
+ row-gap: 1rem;
285
+ width: 100%;
284
286
  }
285
287
  .embedFieldsField {
286
- flex: 1;
287
- min-width: 150px;
288
+ grid-column: 1 / -1;
289
+ min-width: 0;
290
+ }
291
+ .embedFieldsFieldInline {
292
+ min-width: 0;
288
293
  }
289
294
  .embedFieldsFieldTitle {
290
295
  font-size: 0.75rem;
@@ -20,13 +20,24 @@ export function markdownToHTML(text, mentions, everyone, dateFormat) {
20
20
  return `${LINE_TOKEN}${codeLine.length}${LINE_TOKEN}`;
21
21
  });
22
22
  text = sanitize(text);
23
- // Citation (>)
24
- text = text.replace(/(^[ \t]*> ?.*(?:\n[ \t]*> ?.*)*)/gm, (match) => {
25
- const cleanContent = match.split('\n').map(line => {
26
- return line.replace(/^[ \t]*>+ ?/, '');
27
- }).join('\n');
28
- return `<blockquote class="quote-multi">${cleanContent}</blockquote>`;
29
- });
23
+ // Citation (> | >>>)
24
+ const tripleCitationIndex = text.search(/^[ \t]*&gt;&gt;&gt;/m);
25
+ if (tripleCitationIndex !== -1) {
26
+ const lineStartIndex = text.lastIndexOf('\n', tripleCitationIndex) + 1;
27
+ let beforePart = text.substring(0, lineStartIndex);
28
+ let afterPart = text.substring(lineStartIndex);
29
+ beforePart = beforePart.replace(/(^[ \t]*&gt; ?.*(?:\n[ \t]*&gt; ?.*)*)/gm, (match) => {
30
+ return singleCitation(match);
31
+ });
32
+ afterPart = afterPart.replace(/^[ \t]*&gt;&gt;&gt; ?/, '');
33
+ const afterHtml = `<blockquote class="quote-multi">${afterPart}</blockquote>`;
34
+ text = beforePart + afterHtml;
35
+ }
36
+ else {
37
+ text = text.replace(/(^[ \t]*&gt; ?.*(?:\n[ \t]*&gt; ?.*)*)/gm, (match) => {
38
+ return singleCitation(match);
39
+ });
40
+ }
30
41
  // Headers (#)
31
42
  text = text.replace(/^### (.*)(?=\n|$)/gm, `<h3>$1</h3>`);
32
43
  text = text.replace(/^## (.*)(?=\n|$)/gm, `<h2>$1</h2>`);
@@ -135,6 +146,29 @@ export function markdownToHTML(text, mentions, everyone, dateFormat) {
135
146
  });
136
147
  return text;
137
148
  }
149
+ function singleCitation(match) {
150
+ const lines = match.split('\n');
151
+ const result = [];
152
+ let currentBlock = [];
153
+ for (const line of lines) {
154
+ const prefixMatch = line.match(/^[ \t]*((?:&gt;)+)/);
155
+ const len = prefixMatch ? prefixMatch[1].length : 0;
156
+ if (len === 4) { // Is a single '>'
157
+ currentBlock.push(line.replace(/^[ \t]*&gt; ?/, ''));
158
+ }
159
+ else { // Is '>>' or something else
160
+ if (currentBlock.length > 0) {
161
+ result.push(`<blockquote class="quote-multi">${currentBlock.join('\n')}</blockquote>`);
162
+ currentBlock = [];
163
+ }
164
+ result.push(line);
165
+ }
166
+ }
167
+ if (currentBlock.length > 0) {
168
+ result.push(`<blockquote class="quote-multi">${currentBlock.join('\n')}</blockquote>`);
169
+ }
170
+ return result.join('\n');
171
+ }
138
172
  // Check if styleKey is valid
139
173
  const styleOptions = {
140
174
  't': { timeStyle: 'short' },
@@ -1,6 +1,6 @@
1
1
  export declare const DEFAULT_CSS = "\nhtml, body {\n margin: 0;\n width: 100%;\n height: 100%;\n}\nbody {\n background-color: #3a3c43;\n color: #dbdee1;\n font-family: \"Whitney\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n display: flex;\n flex-direction: column;\n padding: 0;\n}\nheader {\n height: fit-content;\n border-bottom: 2px solid black;\n margin-top: 2rem;\n padding-left: 2rem;\n padding-bottom: 1rem;\n display: flex;\n flex-direction: column;\n display: flex;\n flex-direction: row;\n}\na {\n text-decoration: none;\n color: #1E90FF;\n}\np {\n margin: 0;\n}\nh1 {\n margin: 0.5rem 0;\n}\nh2 {\n margin: 0.3rem 0;\n}\nh3 {\n margin: 0.15rem\n}\nh4 {\n margin: 0;\n}\ncode {\n border: 1px solid #202225;\n border-radius: 0.25rem;\n}\nblockquote {\n margin: 0.5rem 0;\n border-left: 0.25rem solid #4f545c;\n padding: 0.4rem 0.6rem;\n border-radius: 0.25rem;\n color: #9f9fa6;\n}\n.line {\n display: flex;\n align-items: baseline;\n gap: 0.5rem\n}\n.badge {\n background-color: #5865f2;\n color: white;\n font-weight: 600;\n font-size: 80%;\n padding: 0.1rem 0.35rem;\n border-radius: 0.25rem;\n letter-spacing: 0.03rem;\n height: fit-content;\n width: fit-content;\n align-self: flex-start;\n}\n.badgeTag {\n background-color: #747F8D50;\n color: white;\n font-weight: 600;\n font-size: 70%;\n padding: 0.1rem 0.35rem;\n border-radius: 0.25rem;\n letter-spacing: 0.03rem;\n height: fit-content;\n width: fit-content;\n align-self: center;\n}\n.mention {\n background-color: #5664fa41;\n padding: 0.2rem;\n border-radius: 0.25rem;\n transition: background-color 0.2s ease;\n}\n.mention:hover {\n background-color: #5664fa7e;\n}\n.guildInitialsIcon {\n width: 7rem;\n height: 7rem;\n border-radius: 50%;\n background-color: #4f545c;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 3rem;\n font-weight: 600;\n}\n";
2
2
  export declare const MESSAGE_CSS = "\n.messageDiv {\n display: flex;\n flex-direction: column;\n gap: 0.2rem;\n padding: 0.5rem;\n border-radius: 1rem;\n}\n.messageDiv.highlight, .messageDiv:hover {\n background-color: #40434b;\n transition: background-color 0.3s ease-in-out;\n}\n.messageBotton {\n display: flex;\n flex-direction: row;\n gap: 1rem;\n padding: 0.5rem;\n border-radius: 0.25rem;\n}\n.messageImg {\n width: 3.5rem; \n height: 3.5rem; \n border-radius: 50%;\n}\n.messageDivRight {\n display: flex;\n flex-direction: column;\n gap: 0.25rem\n}\n.messageUser {\n display: flex;\n flex-direction: row;\n gap: 0.75rem;\n}\n.messageUsername {\n margin: 0;\n}\n.messageTimeStamp {\n color: #999999;\n font-size: 77.5%;\n align-self: center;\n}\n.messageContent {\n line-height: 1.5;\n}\n.pList {\n white-space: pre-wrap;\n}\n.subtext {\n font-size: 85%;\n color: #808080;\n}\n.spoilerMsg {\n display: inline-block;\n background-color: #202225;\n color: #202225;\n padding: 0 0.2rem;\n border-radius: 0.2rem;\n cursor: pointer;\n transition: background-color 0.1s ease-in-out, color 0.1s ease-in-out;\n}\n.spoilerMsg.revealed {\n background-color: transparent;\n color: inherit;\n}\n.messageReply {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.8rem;\n color: #b5bac1;\n cursor: pointer;\n margin-left: 2rem;\n}\n.messageReplySvg {\n flex-shrink: 0;\n width: 2.25rem;\n height: 2.25rem;\n color: #b5bac1;\n}\n.messageReplyImg {\n width: 1.75rem;\n height: 1.75rem;\n border-radius: 50%;\n flex-shrink: 0;\n}\n.messageReplyAuthor {\n font-weight: 600;\n color: #dbdee1;\n margin-right: 0.3rem;\n}\n.badgeReply {\n background-color: #5865f2;\n color: white;\n font-weight: 600;\n font-size: 70%;\n padding: 0.1rem 0.3rem;\n border-radius: 0.25rem;\n letter-spacing: 0.03rem;\n height: fit-content;\n align-self: center;\n flex-shrink: 0;\n}\n.messageReplyText {\n flex-grow: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: #b5bac1;\n font-size: 0.75rem;\n}\n";
3
- export declare const EMBED_CSS = "\n.embed {\n background-color: #2b2d31;\n border: 0.15rem solid #2b2d31;\n border-left: 0.25rem solid;\n border-radius: 0.25rem;\n padding: 0.5rem 0.75rem;\n margin-top: 0.5rem;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n max-width: 40rem;\n min-width: 30rem;\n}\n.embed a {\n color: #00aff4;\n text-decoration: none;\n}\n.embed a:hover {\n text-decoration: underline;\n}\n.embedHeader {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 0.5rem;\n}\n.embedHeaderLeft {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n.embedHeaderLeftAuthor {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.875rem;\n font-weight: 500;\n color: #ffffff;\n margin-bottom: 0.5rem;\n}\n.embedHeaderLeftAuthorImg {\n width: 1.5rem;\n height: 1.5rem;\n border-radius: 50%;\n}\n.embedHeaderLeftAuthorName {\n color: #ffffff;\n font-weight: 500;\n}\n.embedHeaderLeftTitle {\n font-size: 1rem;\n font-weight: bold;\n color: #ffffff;\n margin-bottom: 0.75rem;\n}\n.embedHeaderThumbnail {\n max-width: 80px;\n max-height: 80px;\n object-fit: contain;\n border-radius: 0.25rem;\n flex-shrink: 0;\n}\n.embedDescription {\n font-size: 0.875rem;\n color: #dcddde;\n}\n.embedFields {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n}\n.embedFieldsField {\n flex: 1;\n min-width: 150px;\n}\n.embedFieldsFieldTitle {\n font-size: 0.75rem;\n font-weight: bold;\n color: #ffffff;\n margin-bottom: 0.25rem;\n}\n.embedFieldsFieldValue {\n font-size: 0.875rem;\n color: #dcddde;\n}\n.embedImage {\n margin-top: 0.5rem;\n max-width: 100%;\n height: auto;\n}\n.embedImage img {\n max-width: 100%;\n max-height: 300px;\n object-fit: contain;\n border-radius: 0.25rem;\n}\n.embedFooter {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.75rem;\n color: #999999;\n margin-top: 0.5rem;\n}\n.embedFooterImg {\n width: 1.25rem;\n height: 1.25rem;\n border-radius: 50%;\n}\n.embedFooterText {\n color: #999999;\n}\n";
3
+ export declare const EMBED_CSS = "\n.embed {\n background-color: #2b2d31;\n border: 0.15rem solid #2b2d31;\n border-left: 0.25rem solid;\n border-radius: 0.25rem;\n padding: 0.5rem 0.75rem;\n margin-top: 0.5rem;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n max-width: 40rem;\n width: fit-content;\n}\n.embed a {\n color: #00aff4;\n text-decoration: none;\n}\n.embed a:hover {\n text-decoration: underline;\n}\n.embedHeader {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 0.5rem;\n}\n.embedHeaderLeft {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n.embedHeaderLeftAuthor {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.875rem;\n font-weight: 500;\n color: #ffffff;\n margin-bottom: 0.5rem;\n}\n.embedHeaderLeftAuthorImg {\n width: 1.5rem;\n height: 1.5rem;\n border-radius: 50%;\n}\n.embedHeaderLeftAuthorName {\n color: #ffffff;\n font-weight: 500;\n}\n.embedHeaderLeftTitle {\n font-size: 1rem;\n font-weight: bold;\n color: #ffffff;\n margin-bottom: 0.75rem;\n}\n.embedHeaderThumbnail {\n max-width: 80px;\n max-height: 80px;\n object-fit: contain;\n border-radius: 0.25rem;\n flex-shrink: 0;\n}\n.embedDescription {\n font-size: 0.875rem;\n color: #dcddde;\n}\n.embedFields {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 0.5rem;\n row-gap: 1rem;\n width: 100%;\n}\n.embedFieldsField {\n grid-column: 1 / -1;\n min-width: 0;\n}\n.embedFieldsFieldInline {\n min-width: 0;\n}\n.embedFieldsFieldTitle {\n font-size: 0.75rem;\n font-weight: bold;\n color: #ffffff;\n margin-bottom: 0.25rem;\n}\n.embedFieldsFieldValue {\n font-size: 0.875rem;\n color: #dcddde;\n}\n.embedImage {\n margin-top: 0.5rem;\n max-width: 100%;\n height: auto;\n}\n.embedImage img {\n max-width: 100%;\n max-height: 300px;\n object-fit: contain;\n border-radius: 0.25rem;\n}\n.embedFooter {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.75rem;\n color: #999999;\n margin-top: 0.5rem;\n}\n.embedFooterImg {\n width: 1.25rem;\n height: 1.25rem;\n border-radius: 50%;\n}\n.embedFooterText {\n color: #999999;\n}\n";
4
4
  export declare const ATTACHMENT_CSS = "\n.attachmentImage, .attachmentVideo {\n max-width: 400px;\n height: auto;\n border-radius: 0.25rem;\n margin-top: 0.5rem;\n}\n.attachmentAudio {\n width: 300px;\n margin-top: 0.5rem;\n}\n.attachmentFile {\n background-color: #2b2d31;\n border: 1px solid #202225;\n border-radius: 0.75rem;\n padding: 0.75rem;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n max-width: 400px;\n margin-top: 0.5rem;\n width: fit-content;\n}\n.attachmentFileIcon {\n width: 2.5rem;\n height: 2.5rem;\n fill: #b9bbbe;\n flex-shrink: 0;\n}\n.attachmentFileInfo {\n display: flex;\n flex-direction: column;\n gap: 0.1rem;\n overflow: hidden;\n flex-grow: 1;\n}\n.attachmentFileName {\n color: #ffffff;\n text-decoration: none;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.attachmentFileSize {\n font-size: 0.75rem;\n color: #72767d;\n}\n.attachmentDownload {\n display: block;\n flex-shrink: 0;\n}\n.attachmentDownloadIcon {\n width: 1.5rem;\n height: 1.5rem;\n fill: #b9bbbe;\n transition: fill 0.2s ease;\n}\n.attachmentDownload:hover .attachmentDownloadIcon {\n fill: #ffffff;\n}\n.spoilerAttachment {\n position: relative;\n display: inline-block;\n border-radius: 0.5rem;\n overflow: hidden;\n cursor: pointer;\n}\n.spoilerAttachment .spoilerAttachmentContent {\n filter: blur(64px);\n pointer-events: none;\n transition: filter 0.2s ease;\n width: 100%;\n height: 100%;\n}\n.spoilerAttachment .spoilerAttachmentOverlay {\n position: absolute;\n inset: 0;\n background: rgba(32, 34, 37, 0.85);\n color: #fff;\n font-weight: 600;\n letter-spacing: 0.05em;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 2;\n user-select: none;\n}\n.spoilerAttachment.revealed .spoilerAttachmentContent {\n filter: none;\n pointer-events: auto;\n}\n.spoilerAttachment.revealed .spoilerAttachmentOverlay {\n display: none;\n}\n";
5
5
  export declare const ACTIONROW_CSS = "\n.actionRow {\n display: flex;\n gap: 0.5rem;\n margin-top: 0.5rem;\n}\n";
6
6
  export declare const BUTTON_CSS = "\n.button {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0rem 0.8rem;\n height: 2.5rem;\n border-radius: 0.6rem;\n color: white;\n font-weight: 600;\n cursor: pointer;\n transition: filter 0.2s ease;\n}\n.button:hover {\n filter: brightness(1.1);\n}\n.buttonEmoji {\n font-size: 1.25rem;\n}\n.buttonLabel {\n font-size: 0.875rem;\n}\n.buttonLink {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n color: white;\n font-weight: 600;\n}\n.buttonLinkIcon {\n width: 1.25rem;\n height: 1.25rem;\n}\n";
@@ -227,7 +227,7 @@ export const EMBED_CSS = `
227
227
  flex-direction: column;
228
228
  gap: 0.5rem;
229
229
  max-width: 40rem;
230
- min-width: 30rem;
230
+ width: fit-content;
231
231
  }
232
232
  .embed a {
233
233
  color: #00aff4;
@@ -283,13 +283,18 @@ export const EMBED_CSS = `
283
283
  color: #dcddde;
284
284
  }
285
285
  .embedFields {
286
- display: flex;
287
- flex-wrap: wrap;
286
+ display: grid;
287
+ grid-template-columns: repeat(3, 1fr);
288
288
  gap: 0.5rem;
289
+ row-gap: 1rem;
290
+ width: 100%;
289
291
  }
290
292
  .embedFieldsField {
291
- flex: 1;
292
- min-width: 150px;
293
+ grid-column: 1 / -1;
294
+ min-width: 0;
295
+ }
296
+ .embedFieldsFieldInline {
297
+ min-width: 0;
293
298
  }
294
299
  .embedFieldsFieldTitle {
295
300
  font-size: 0.75rem;
@@ -193,14 +193,12 @@ export class Html {
193
193
  const winnerVotes = parseInt(getField("victor_answer_votes") ?? "0");
194
194
  const totalVotes = parseInt(getField("total_votes") ?? "0");
195
195
  const winnerPercentage = totalVotes > 0 ? (winnerVotes / totalVotes) * 100 : 0;
196
- if (!winnerText && winnerVotes != 0)
197
- return '';
198
196
  return `
199
197
  <div class="pollResultEmbed">
200
198
  <div>
201
199
  <div class="pollResultEmbedWinner">
202
200
  ${emojiText ? sanitize(emojiText) : ""}
203
- ${winnerText ? sanitize(winnerText) : "There was no winner"}
201
+ ${winnerText ? sanitize(winnerText) : winnerVotes > 0 ? "The result was a draw" : "There was no winner"}
204
202
  ${winnerVotes != 0 ? `<span class="pollResultEmbedCheckmark">✔</span>` : ""}
205
203
  </div>
206
204
  <div class="pollResultEmbedSubtitle">${totalVotes} votes (${winnerPercentage.toFixed(1)}%)</div>
@@ -220,7 +218,7 @@ export class Html {
220
218
  const embedAuthor = embed.author ? (embed.author.url ? `<a class="embedHeaderLefttAuthorName" href="${sanitize(embed.author.url)}" target="_blank">${sanitize(embed.author.name)}</a>` : `<p class="embedHeaderLeftAuthorName">${sanitize(embed.author.name)}</p>`) : "";
221
219
  const embedTitle = embed.title ? (embed.url ? `<a class="embedHeaderLeftTitle" href="${sanitize(embed.url)}" target="_blank">${sanitize(embed.title)}</a>` : `<p class="embedHeaderLeftTitle">${sanitize(embed.title)}</p>`) : "";
222
220
  return `
223
- <div class="embed" style="${embed.hexColor ? `border-left-color: ${embed.hexColor}` : ''}">
221
+ <div class="embed" style="border-left-color:${embed.hexColor ? `${embed.hexColor}` : '#4f545c'}">
224
222
  ${embed.author || embed.title || embed.thumbnail || embed.description ? `
225
223
  <div class="embedHeader">
226
224
  <div class="embedHeaderLeft">
@@ -237,7 +235,7 @@ export class Html {
237
235
  ${embed.fields && embed.fields.length > 0 ? `
238
236
  <div class="embedFields">
239
237
  ${embed.fields.map(field => `
240
- <div class="embedFieldsField" style="${field.inline ? 'display: inline-block;' : ''}">
238
+ <div class="${field.inline ? "embedFieldsFieldInline" : "embedFieldsField"}">
241
239
  <p class="embedFieldsFieldTitle">${sanitize(field.name)}</p>
242
240
  <p class="embedFieldsFieldValue">${markdownToHTML(field.value, this.data.mentions, message.mentions, this.dateFormat)}</p>
243
241
  </div>`).join("")}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discord-message-transcript-base",
3
- "version": "1.1.4",
3
+ "version": "1.1.6-dev.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",