discord-html-transcripts-fix 1.0.0 → 1.2.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/README.md +87 -66
- package/dist/downloader/images.js +60 -85
- package/dist/generator/index.js +197 -36
- package/dist/generator/renderers/attachment.js +27 -36
- package/dist/generator/renderers/components/Container.js +36 -14
- package/dist/generator/renderers/components/Media Gallery.js +24 -18
- package/dist/generator/renderers/components.js +7 -2
- package/dist/generator/renderers/content.js +68 -39
- package/dist/generator/renderers/embed.js +55 -34
- package/dist/generator/renderers/message.js +201 -12
- package/dist/generator/renderers/reply.js +47 -39
- package/dist/generator/renderers/systemMessage.js +138 -43
- package/dist/generator/transcript.js +42 -56
- package/dist/index.js +59 -86
- package/dist/static/client.js +229 -28
- package/dist/types.js +1 -0
- package/dist/utils/buildProfiles.js +141 -29
- package/dist/utils/utils.js +74 -19
- package/package.json +5 -5
|
@@ -1,51 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
18
5
|
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
6
|
+
var ownKeys = function(o){ownKeys = Object.getOwnPropertyNames || function (o){var ar=[];for (var k in o) if (Object.prototype.hasOwnProperty.call(o,k)) ar[ar.length]=k;return ar;};return ownKeys(o);};
|
|
7
|
+
return function (mod){if (mod && mod.__esModule) return mod;var result={};if (mod != null) for (var k=ownKeys(mod), i=0; i<k.length; i++) if (k[i] !== "default") Object.defineProperty(result,k[i],{get:function(){return mod[k[i]];}});Object.defineProperty(result,"default",{value:mod,enumerable:true});return result;};
|
|
34
8
|
})();
|
|
35
9
|
var __rest = (this && this.__rest) || function (s, e) {
|
|
36
10
|
var t = {};
|
|
37
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
38
|
-
t[p] = s[p];
|
|
11
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
|
|
39
12
|
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
40
13
|
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
41
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
42
|
-
t[p[i]] = s[p[i]];
|
|
14
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
|
|
43
15
|
}
|
|
44
16
|
return t;
|
|
45
17
|
};
|
|
46
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
47
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
48
|
-
};
|
|
49
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
19
|
exports.default = DiscordMessages;
|
|
51
20
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
@@ -53,24 +22,41 @@ const discord_js_1 = require("discord.js");
|
|
|
53
22
|
const content_1 = __importStar(require("./renderers/content"));
|
|
54
23
|
const message_1 = __importDefault(require("./renderers/message"));
|
|
55
24
|
const TranscriptHeader_1 = require("./renderers/components/TranscriptHeader");
|
|
56
|
-
|
|
57
|
-
* The core transcript component.
|
|
58
|
-
* Expects window.$discordMessage.profiles to be set for profile information.
|
|
59
|
-
*
|
|
60
|
-
* @param props Messages, channel details, callbacks, etc.
|
|
61
|
-
* @returns
|
|
62
|
-
*/
|
|
25
|
+
|
|
63
26
|
async function DiscordMessages(_a) {
|
|
64
|
-
var _b, _c, _d, _e, _f;
|
|
65
27
|
var { messages, channel, callbacks } = _a, options = __rest(_a, ["messages", "channel", "callbacks"]);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
28
|
+
const dateSeps = options.dateSeps || [];
|
|
29
|
+
|
|
30
|
+
return ((0, jsx_runtime_1.jsxs)("discord-messages", { style: { minHeight: '100vh' }, children: [
|
|
31
|
+
(0, jsx_runtime_1.jsx)(TranscriptHeader_1.TranscriptHeader, {
|
|
32
|
+
guildName: channel.isDMBased() ? 'Direct Messages' : channel.guild.name,
|
|
33
|
+
guildIcon: channel.isDMBased() ? undefined : (channel.guild.iconURL({ size: 128 }) ?? undefined),
|
|
34
|
+
channelName: channel.isDMBased()
|
|
35
|
+
? channel.type === discord_js_1.ChannelType.DM
|
|
36
|
+
? (channel.recipient?.tag ?? 'Unknown Recipient')
|
|
37
|
+
: 'Unknown Recipient'
|
|
38
|
+
: channel.name,
|
|
39
|
+
children: channel.isThread() ? (`Thread channel in ${channel.parent?.name ?? 'Unknown Channel'}`)
|
|
40
|
+
: channel.isDMBased() ? (`Direct Messages`)
|
|
41
|
+
: channel.isVoiceBased() ? (`Voice Text Channel for ${channel.name}`)
|
|
42
|
+
: channel.type === discord_js_1.ChannelType.GuildCategory ? (`Category Channel`)
|
|
43
|
+
: 'topic' in channel && channel.topic
|
|
44
|
+
? (0, jsx_runtime_1.jsx)(content_1.default, { content: channel.topic, context: Object.assign({ messages, channel, callbacks, type: content_1.RenderType.REPLY }, options) })
|
|
45
|
+
: (`This is the start of #${channel.name} channel.`)
|
|
46
|
+
}),
|
|
47
|
+
messages.map((message, idx) => [
|
|
48
|
+
dateSeps[idx] && (0, jsx_runtime_1.jsx)("div", { className: "dht-date-sep", children: dateSeps[idx] }, `sep-${idx}`),
|
|
49
|
+
(0, jsx_runtime_1.jsx)(message_1.default, { message: message, context: Object.assign({ messages, channel, callbacks }, options) }, message.id)
|
|
50
|
+
]),
|
|
51
|
+
(0, jsx_runtime_1.jsxs)("div", { style: { textAlign: 'center', width: '100%' }, children: [
|
|
52
|
+
options.footerText
|
|
53
|
+
? options.footerText.replaceAll('{number}', messages.length.toString()).replaceAll('{s}', messages.length > 1 ? 's' : '')
|
|
54
|
+
: `Exported ${messages.length} message${messages.length > 1 ? 's' : ''}.`,
|
|
55
|
+
' ',
|
|
56
|
+
options.poweredBy
|
|
57
|
+
? (0, jsx_runtime_1.jsxs)("span", { style: { textAlign: 'center' }, children: ["Powered by ", (0, jsx_runtime_1.jsx)("a", { href: "https://github.com/ItzDerock/discord-html-transcripts", style: { color: 'lightblue' }, children: "discord-html-transcripts" }), "."] })
|
|
58
|
+
: null
|
|
59
|
+
] })
|
|
60
|
+
] }));
|
|
75
61
|
}
|
|
76
|
-
//# sourceMappingURL=transcript.js.map
|
|
62
|
+
//# sourceMappingURL=transcript.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,138 +1,111 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/// <reference path="./discord-components.d.ts" />
|
|
3
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
-
if (k2 === undefined) k2 = k;
|
|
5
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
-
}
|
|
9
|
-
Object.defineProperty(o, k2, desc);
|
|
10
|
-
}) : (function(o, m, k, k2) {
|
|
11
|
-
if (k2 === undefined) k2 = k;
|
|
12
|
-
o[k2] = m[k];
|
|
13
|
-
}));
|
|
14
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
15
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
16
|
-
};
|
|
17
3
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
5
|
};
|
|
6
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
7
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p))
|
|
8
|
+
Object.defineProperty(exports, p, { enumerable: true, get: function() { return m[p]; } });
|
|
9
|
+
};
|
|
20
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
11
|
exports.TranscriptImageDownloader = exports.DiscordMessages = void 0;
|
|
22
12
|
exports.generateFromMessages = generateFromMessages;
|
|
23
13
|
exports.createTranscript = createTranscript;
|
|
14
|
+
const debug_1 = __importDefault(require("debug"));
|
|
24
15
|
const discord_js_1 = require("discord.js");
|
|
25
16
|
const generator_1 = __importDefault(require("./generator"));
|
|
26
17
|
const types_1 = require("./types");
|
|
27
18
|
const images_1 = require("./downloader/images");
|
|
28
|
-
|
|
19
|
+
|
|
20
|
+
const log = (0, debug_1.default)('discord-html-transcripts-fix');
|
|
21
|
+
|
|
29
22
|
var transcript_1 = require("./generator/transcript");
|
|
30
23
|
Object.defineProperty(exports, "DiscordMessages", { enumerable: true, get: function () { return __importDefault(transcript_1).default; } });
|
|
31
24
|
var images_2 = require("./downloader/images");
|
|
32
25
|
Object.defineProperty(exports, "TranscriptImageDownloader", { enumerable: true, get: function () { return images_2.TranscriptImageDownloader; } });
|
|
33
|
-
|
|
26
|
+
|
|
27
|
+
// Version check — warn only. NEVER kill host process.
|
|
34
28
|
const versionPrefix = discord_js_1.version.split('.')[0];
|
|
35
29
|
if (versionPrefix !== '14' && versionPrefix !== '15') {
|
|
36
|
-
console.
|
|
37
|
-
` For v13.x.x support, please install discord-html-transcripts v2.x.x using "npm install discord-html-transcripts@^2".`);
|
|
38
|
-
process.exit(1);
|
|
30
|
+
console.warn(`[discord-html-transcripts-fix] Compatible with discord.js v14/v15, you are using v${discord_js_1.version}. Continuing anyway.`);
|
|
39
31
|
}
|
|
40
|
-
|
|
41
|
-
*
|
|
42
|
-
* @param messages The messages to generate a transcript from
|
|
43
|
-
* @param channel The channel the messages are from (used for header and guild name)
|
|
44
|
-
* @param options The options to use when generating the transcript
|
|
45
|
-
* @returns The generated transcript
|
|
46
|
-
*/
|
|
32
|
+
|
|
47
33
|
async function generateFromMessages(messages, channel, options = {}) {
|
|
48
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
49
|
-
// turn messages into an array
|
|
50
34
|
const transformedMessages = messages instanceof discord_js_1.Collection ? Array.from(messages.values()) : messages;
|
|
51
|
-
|
|
52
|
-
|
|
35
|
+
|
|
36
|
+
// Image-src resolution
|
|
37
|
+
let resolveImageSrc = options.callbacks?.resolveImageSrc ?? ((attachment) => attachment.url);
|
|
53
38
|
if (options.saveImages) {
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
39
|
+
if (options.callbacks?.resolveImageSrc) {
|
|
40
|
+
log('saveImages + resolveImageSrc both set — resolveImageSrc wins');
|
|
41
|
+
} else {
|
|
58
42
|
resolveImageSrc = new images_1.TranscriptImageDownloader().build();
|
|
59
|
-
|
|
43
|
+
log('using default image downloader');
|
|
60
44
|
}
|
|
61
45
|
}
|
|
62
|
-
|
|
63
|
-
const
|
|
46
|
+
|
|
47
|
+
const callbacks = Object.assign({
|
|
48
|
+
resolveImageSrc,
|
|
49
|
+
resolveChannel: async (id) => channel.client.channels.fetch(id).catch(() => null),
|
|
50
|
+
resolveUser: async (id) => channel.client.users.fetch(id).catch(() => null),
|
|
51
|
+
resolveRole: channel.isDMBased() ? () => null : async (id) => channel.guild?.roles.fetch(id).catch(() => null),
|
|
52
|
+
}, options.callbacks ?? {});
|
|
53
|
+
|
|
54
|
+
const rendered = await (0, generator_1.default)({
|
|
64
55
|
messages: transformedMessages,
|
|
65
56
|
channel,
|
|
66
|
-
saveImages:
|
|
67
|
-
callbacks
|
|
68
|
-
poweredBy:
|
|
69
|
-
footerText:
|
|
70
|
-
favicon:
|
|
71
|
-
hydrate:
|
|
57
|
+
saveImages: options.saveImages ?? false,
|
|
58
|
+
callbacks,
|
|
59
|
+
poweredBy: options.poweredBy ?? true,
|
|
60
|
+
footerText: options.footerText ?? 'Exported {number} message{s}.',
|
|
61
|
+
favicon: options.favicon ?? 'guild',
|
|
62
|
+
hydrate: options.hydrate ?? false,
|
|
63
|
+
language: options.language ?? 'en',
|
|
64
|
+
i18n: options.i18n ?? undefined,
|
|
65
|
+
stream: options.returnType === 'stream' || options.stream === true,
|
|
66
|
+
returnType: options.returnType,
|
|
72
67
|
});
|
|
73
|
-
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// );
|
|
80
|
-
// return the html in the specified format
|
|
68
|
+
|
|
69
|
+
// Stream pass-through
|
|
70
|
+
if (options.returnType === 'stream' || options.stream === true) {
|
|
71
|
+
return rendered; // Node readable stream
|
|
72
|
+
}
|
|
73
|
+
|
|
81
74
|
if (options.returnType === types_1.ExportReturnType.Buffer) {
|
|
82
|
-
return Buffer.from(
|
|
75
|
+
return Buffer.from(rendered);
|
|
83
76
|
}
|
|
84
77
|
if (options.returnType === types_1.ExportReturnType.String) {
|
|
85
|
-
return
|
|
78
|
+
return rendered;
|
|
86
79
|
}
|
|
87
|
-
return new discord_js_1.AttachmentBuilder(Buffer.from(
|
|
88
|
-
name:
|
|
80
|
+
return new discord_js_1.AttachmentBuilder(Buffer.from(rendered), {
|
|
81
|
+
name: options.filename ?? `transcript-${channel.id}.html`,
|
|
89
82
|
});
|
|
90
83
|
}
|
|
91
|
-
|
|
92
|
-
*
|
|
93
|
-
* @param channel The channel to create a transcript from
|
|
94
|
-
* @param options The options to use when creating the transcript
|
|
95
|
-
* @returns The generated transcript
|
|
96
|
-
*/
|
|
84
|
+
|
|
97
85
|
async function createTranscript(channel, options = {}) {
|
|
98
|
-
// validate type
|
|
99
86
|
if (!channel.isTextBased()) {
|
|
100
|
-
// @ts-expect-error(2339): run-time check
|
|
101
87
|
throw new TypeError(`Provided channel must be text-based, received ${channel.type}`);
|
|
102
88
|
}
|
|
103
|
-
// fetch messages
|
|
104
89
|
let allMessages = [];
|
|
105
90
|
let lastMessageId;
|
|
106
91
|
const { limit, filter } = options;
|
|
107
92
|
const resolvedLimit = typeof limit === 'undefined' || limit === -1 ? Infinity : limit;
|
|
108
|
-
// until there are no more messages, keep fetching
|
|
109
93
|
while (true) {
|
|
110
|
-
// create fetch options
|
|
111
94
|
const fetchLimitOptions = { limit: 100, before: lastMessageId };
|
|
112
|
-
if (!lastMessageId)
|
|
113
|
-
delete fetchLimitOptions.before;
|
|
114
|
-
// fetch messages
|
|
95
|
+
if (!lastMessageId) delete fetchLimitOptions.before;
|
|
115
96
|
const messages = await channel.messages.fetch(fetchLimitOptions);
|
|
116
97
|
const filteredMessages = typeof filter === 'function' ? messages.filter(filter) : messages;
|
|
117
|
-
|
|
118
|
-
allMessages.push(...filteredMessages.values());
|
|
119
|
-
// Get the last key of 'messages', not 'filteredMessages' because you will be refetching the same messages
|
|
98
|
+
for (const m of filteredMessages.values()) allMessages.push(m);
|
|
120
99
|
lastMessageId = messages.lastKey();
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
break;
|
|
100
|
+
if (messages.size < 100) break;
|
|
101
|
+
if (allMessages.length >= resolvedLimit) break;
|
|
102
|
+
}
|
|
103
|
+
if (resolvedLimit < allMessages.length) {
|
|
104
|
+
allMessages = allMessages.slice(0, resolvedLimit);
|
|
127
105
|
}
|
|
128
|
-
if (resolvedLimit < allMessages.length)
|
|
129
|
-
allMessages = allMessages.slice(0, limit);
|
|
130
|
-
// generate the transcript
|
|
131
106
|
return generateFromMessages(allMessages.reverse(), channel, options);
|
|
132
107
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
generateFromMessages,
|
|
136
|
-
};
|
|
108
|
+
|
|
109
|
+
exports.default = { createTranscript, generateFromMessages };
|
|
137
110
|
__exportStar(require("./types"), exports);
|
|
138
|
-
//# sourceMappingURL=index.js.map
|
|
111
|
+
//# sourceMappingURL=index.js.map
|
package/dist/static/client.js
CHANGED
|
@@ -1,31 +1,232 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// TODO: create some sort of build system to compile this file
|
|
3
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.ggSansFont = exports.revealSpoiler = exports.scrollToMessage = void 0;
|
|
5
|
-
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
3
|
+
exports.ggSansFont = exports.revealSpoiler = exports.scrollToMessage = exports.mentionPopup = exports.mentionPopupStyles = exports.backToTop = exports.transcriptUtils = exports.searchBar = exports.searchBarStyles = exports.lightbox = exports.lightboxStyles = exports.toc = exports.tocStyles = exports.i18nSwitcher = exports.i18nStyles = exports.dateSeparatorStyles = void 0;
|
|
4
|
+
|
|
5
|
+
// ===========================================================================
|
|
6
|
+
// scrollToMessage — fixed stale ${goto} template
|
|
7
|
+
// ===========================================================================
|
|
8
|
+
exports.scrollToMessage = `document.addEventListener('click',function(e){var t=e.target;if(!t)return;var g=t.getAttribute&&t.getAttribute('data-goto');if(!g)return;var r=document.getElementById('m-'+g);if(r){r.scrollIntoView({behavior:'smooth',block:'center'});r.style.backgroundColor='rgba(148,156,247,0.15)';r.style.transition='background-color 0.5s ease';setTimeout(function(){r.style.backgroundColor='transparent'},1200);}else{console.warn('Message '+g+' not found.');}});`;
|
|
9
|
+
|
|
10
|
+
exports.revealSpoiler = `var s=document.querySelectorAll('.discord-spoiler');s.forEach(function(s){s.addEventListener('click',function(){if(s.classList.contains('discord-spoiler')){s.classList.remove('discord-spoiler');s.classList.add('discord-spoiler--revealed');}});});`;
|
|
11
|
+
|
|
12
|
+
// ===========================================================================
|
|
13
|
+
// i18n — default dictionaries, used by both server-side renderers and client-side scripts
|
|
14
|
+
// ===========================================================================
|
|
15
|
+
const defaultDicts = {
|
|
16
|
+
en: {
|
|
17
|
+
edited: 'edited',
|
|
18
|
+
editedAt: 'Edited at {time}',
|
|
19
|
+
joined: 'joined the server',
|
|
20
|
+
pinned: 'pinned a message to this channel.',
|
|
21
|
+
boosted: 'boosted the server!',
|
|
22
|
+
threadStarted: 'started a thread:',
|
|
23
|
+
changedChannelName: 'changed the channel name:',
|
|
24
|
+
changedChannelIcon: 'changed the channel icon.',
|
|
25
|
+
usedCommand: 'used',
|
|
26
|
+
startedCall: 'started a call.',
|
|
27
|
+
addedFollow: 'added {target} to follow this channel.',
|
|
28
|
+
left: 'left.',
|
|
29
|
+
autoModBlocked: 'AutoMod blocked a message.',
|
|
30
|
+
serverAlert: 'Server safety alert.',
|
|
31
|
+
pollEnded: 'A poll ended.',
|
|
32
|
+
roleSubPurchased: 'subscribed to {role}!',
|
|
33
|
+
forwardedFrom: 'Forwarded from',
|
|
34
|
+
searchPlaceholder: 'Search transcript…',
|
|
35
|
+
ofMatches: 'of',
|
|
36
|
+
noMatches: 'no matches',
|
|
37
|
+
backToTop: 'Back to top',
|
|
38
|
+
tocTitle: 'Participants',
|
|
39
|
+
statsMessages: '{n} messages',
|
|
40
|
+
statsParticipants: '{n} participants',
|
|
41
|
+
statsImages: '{n} images',
|
|
42
|
+
crossServerReply: 'Message from another server',
|
|
43
|
+
appBadge: 'APP',
|
|
44
|
+
botBadge: 'BOT',
|
|
45
|
+
editHistoryTitle: 'Edit history',
|
|
46
|
+
editHistoryAt: 'at',
|
|
47
|
+
voiceMessage: 'Voice message',
|
|
48
|
+
forwardedMessage: 'Forwarded',
|
|
49
|
+
languageLabel: 'Language',
|
|
50
|
+
threadArchived: 'Archived',
|
|
51
|
+
threadLocked: 'Locked',
|
|
52
|
+
suppressedEmbeds: '(embeds hidden)',
|
|
53
|
+
},
|
|
54
|
+
de: {
|
|
55
|
+
edited: 'bearbeitet',
|
|
56
|
+
editedAt: 'Bearbeitet am {time}',
|
|
57
|
+
joined: 'ist dem Server beigetreten',
|
|
58
|
+
pinned: 'hat eine Nachricht angepinnt.',
|
|
59
|
+
boosted: 'hat den Server geboostet!',
|
|
60
|
+
threadStarted: 'hat einen Thread gestartet:',
|
|
61
|
+
changedChannelName: 'hat den Channel-Namen geändert:',
|
|
62
|
+
changedChannelIcon: 'hat das Channel-Icon geändert.',
|
|
63
|
+
usedCommand: 'hat',
|
|
64
|
+
startedCall: 'hat einen Anruf gestartet.',
|
|
65
|
+
addedFollow: 'hat {target} hinzugefügt, um diesem Channel zu folgen.',
|
|
66
|
+
left: 'hat den Channel verlassen.',
|
|
67
|
+
autoModBlocked: 'AutoMod hat eine Nachricht blockiert.',
|
|
68
|
+
serverAlert: 'Sicherheitswarnung.',
|
|
69
|
+
pollEnded: 'Eine Umfrage wurde beendet.',
|
|
70
|
+
roleSubPurchased: 'hat {role} abonniert!',
|
|
71
|
+
forwardedFrom: 'Weitergeleitet von',
|
|
72
|
+
searchPlaceholder: 'Im Transcript suchen…',
|
|
73
|
+
ofMatches: 'von',
|
|
74
|
+
noMatches: 'keine Treffer',
|
|
75
|
+
backToTop: 'Nach oben',
|
|
76
|
+
tocTitle: 'Teilnehmer',
|
|
77
|
+
statsMessages: '{n} Nachrichten',
|
|
78
|
+
statsParticipants: '{n} Teilnehmer',
|
|
79
|
+
statsImages: '{n} Bilder',
|
|
80
|
+
crossServerReply: 'Nachricht von einem anderen Server',
|
|
81
|
+
appBadge: 'APP',
|
|
82
|
+
botBadge: 'BOT',
|
|
83
|
+
editHistoryTitle: 'Bearbeitungs-Verlauf',
|
|
84
|
+
editHistoryAt: 'am',
|
|
85
|
+
voiceMessage: 'Sprachnachricht',
|
|
86
|
+
forwardedMessage: 'Weitergeleitet',
|
|
87
|
+
languageLabel: 'Sprache',
|
|
88
|
+
threadArchived: 'Archiviert',
|
|
89
|
+
threadLocked: 'Gesperrt',
|
|
90
|
+
suppressedEmbeds: '(Embeds versteckt)',
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
function getDict(lang) {
|
|
95
|
+
if (lang && defaultDicts[lang]) return defaultDicts[lang];
|
|
96
|
+
return defaultDicts.en;
|
|
97
|
+
}
|
|
98
|
+
exports.getDict = getDict;
|
|
99
|
+
exports.defaultDicts = defaultDicts;
|
|
100
|
+
|
|
101
|
+
// ===========================================================================
|
|
102
|
+
// mentionPopup — clickable user/role/channel pills
|
|
103
|
+
// Reads from window.$discordMessage.{users,roles,channels,profiles}.
|
|
104
|
+
// Uses safe color validation to block CSS injection.
|
|
105
|
+
// ===========================================================================
|
|
106
|
+
exports.mentionPopup = `(function(){
|
|
107
|
+
function DATA(){return (typeof globalThis!=='undefined' && globalThis.$discordMessage)||{};}
|
|
108
|
+
function esc(s){return String(s==null?'':s).replace(/[&<>"']/g,function(c){return ({'&':'&','<':'<','>':'>','"':'"',"'":'''})[c];});}
|
|
109
|
+
function safeColor(c,fb){fb=fb||'#5865F2';return typeof c==='string' && /^#[0-9a-fA-F]{3,8}$/.test(c) ? c : fb;}
|
|
110
|
+
function t(key){var d=DATA();var lang=d.lang||'en';var dict=(d.i18n&&d.i18n[lang])||(d.i18n&&d.i18n.en)||{};return dict[key]||key;}
|
|
111
|
+
function fmt(iso){if(!iso)return '';try{var d=new Date(iso);return isNaN(d.getTime())?'':d.toLocaleString(DATA().lang==='de'?'de-DE':'en-US',{dateStyle:'medium',timeStyle:'short'});}catch(_){return '';}}
|
|
112
|
+
var popup=null;
|
|
113
|
+
function ensure(){if(popup)return popup;popup=document.createElement('div');popup.className='dht-popup';popup.innerHTML='<div class="dht-popup-body"></div><button type="button" class="dht-popup-close" aria-label="Close">×</button>';document.body.appendChild(popup);popup.querySelector('.dht-popup-close').addEventListener('click',hide);document.addEventListener('click',function(e){if(!popup||popup.style.display!=='block')return;if(popup.contains(e.target))return;if(e.target.closest&&e.target.closest('[data-mention-id]'))return;hide();});document.addEventListener('keydown',function(e){if(e.key==='Escape')hide();});window.addEventListener('resize',hide);return popup;}
|
|
114
|
+
function hide(){if(popup)popup.style.display='none';}
|
|
115
|
+
function showAt(el,html){var p=ensure();p.querySelector('.dht-popup-body').innerHTML=html;p.style.display='block';var r=el.getBoundingClientRect();var pr=p.getBoundingClientRect();var pad=8;var top=r.bottom+6;var left=r.left;if(top+pr.height>window.innerHeight-pad)top=Math.max(pad,r.top-pr.height-6);if(left+pr.width>window.innerWidth-pad)left=Math.max(pad,window.innerWidth-pr.width-pad);if(left<pad)left=pad;p.style.top=top+'px';p.style.left=left+'px';}
|
|
116
|
+
function rolePill(role){var c=safeColor(role&&role.color);return '<span class="dht-role-pill" style="--dht-role:'+c+';">'+esc(role&&role.name?role.name:'@role')+'</span>';}
|
|
117
|
+
function userHtml(id){var d=DATA();var u=(d.users&&d.users[id])||null;var p=(d.profiles&&d.profiles[id])||null;if(!u&&!p)return '<i>?</i><div class="dht-popup-id">ID: <code>'+esc(id)+'</code></div>';var name=(u&&(u.displayName||u.username))||(p&&p.author)||'Unknown';var username=u&&u.username?'@'+u.username:'';var avatar=(u&&u.avatar)||(p&&p.avatar)||'';var color=safeColor((u&&u.bannerColor)||(p&&p.roleColor),'#dbdee1');var bot=(u&&u.bot)||(p&&p.bot);var roles=u&&Array.isArray(u.roles)&&u.roles.length?u.roles.map(rolePill).join(''):'';var joinedAt=u&&u.joinedAt?fmt(u.joinedAt):'';var createdAt=u&&u.createdAt?fmt(u.createdAt):'';var labels=DATA().i18n&&(DATA().i18n[DATA().lang]||DATA().i18n.en)||{};return ''+'<div class="dht-popup-head">'+(avatar?'<img class="dht-popup-avatar" src="'+esc(avatar)+'" alt="">':'<div class="dht-popup-avatar dht-popup-avatar--ph"></div>')+'<div class="dht-popup-headtext"><div class="dht-popup-name" style="color:'+color+';">'+esc(name)+(bot?'<span class="dht-popup-badge">'+esc(t('botBadge'))+'</span>':'')+'</div>'+(username?'<div class="dht-popup-sub">'+esc(username)+'</div>':'')+'</div></div>'+(roles?'<div class="dht-popup-section"><div class="dht-popup-label">Roles</div><div class="dht-popup-roles">'+roles+'</div></div>':'')+(joinedAt?'<div class="dht-popup-row"><span class="dht-popup-label">Server</span><span>'+esc(joinedAt)+'</span></div>':'')+(createdAt?'<div class="dht-popup-row"><span class="dht-popup-label">Account</span><span>'+esc(createdAt)+'</span></div>':'')+'<div class="dht-popup-id">ID: <code>'+esc(id)+'</code></div>';}
|
|
118
|
+
function roleHtml(id){var r=(DATA().roles||{})[id];if(!r)return '<i>?</i><div class="dht-popup-id">ID: <code>'+esc(id)+'</code></div>';var color=safeColor(r.color,'#dbdee1');return '<div class="dht-popup-head"><div class="dht-popup-rolemark" style="background:'+color+';"></div><div class="dht-popup-headtext"><div class="dht-popup-name" style="color:'+color+';">@'+esc(r.name)+'</div>'+(r.color?'<div class="dht-popup-sub"><code>'+esc(r.color)+'</code></div>':'')+'</div></div>'+(r.memberCount!=null?'<div class="dht-popup-row"><span class="dht-popup-label">Members</span><span>'+esc(r.memberCount)+'</span></div>':'')+(r.position!=null?'<div class="dht-popup-row"><span class="dht-popup-label">Position</span><span>'+esc(r.position)+'</span></div>':'')+(r.hoist?'<div class="dht-popup-row"><span class="dht-popup-label">Hoisted</span><span>Yes</span></div>':'')+(r.mentionable?'<div class="dht-popup-row"><span class="dht-popup-label">Mentionable</span><span>Yes</span></div>':'')+(r.managed?'<div class="dht-popup-row"><span class="dht-popup-label">Managed</span><span>Bot/Integration</span></div>':'')+'<div class="dht-popup-id">ID: <code>'+esc(id)+'</code></div>';}
|
|
119
|
+
function channelHtml(id){var c=(DATA().channels||{})[id];if(!c)return '<i>Channel</i><div class="dht-popup-id">ID: <code>'+esc(id)+'</code></div>';return '<div class="dht-popup-head"><div class="dht-popup-rolemark" style="background:#5865F2;">#</div><div class="dht-popup-headtext"><div class="dht-popup-name">#'+esc(c.name)+'</div>'+(c.parent?'<div class="dht-popup-sub">in '+esc(c.parent)+'</div>':'')+'</div></div>'+(c.topic?'<div class="dht-popup-section"><div class="dht-popup-label">Topic</div><div>'+esc(c.topic)+'</div></div>':'')+(c.nsfw?'<div class="dht-popup-row"><span class="dht-popup-label">NSFW</span><span>Yes</span></div>':'')+'<div class="dht-popup-id">ID: <code>'+esc(id)+'</code></div>';}
|
|
120
|
+
document.addEventListener('click',function(e){var el=e.target&&e.target.closest?e.target.closest('[data-mention-id]'):null;if(!el)return;var tp=el.getAttribute('data-mention-type');var id=el.getAttribute('data-mention-id');if(!tp||!id)return;e.preventDefault();e.stopPropagation();var html='';if(tp==='user')html=userHtml(id);else if(tp==='role')html=roleHtml(id);else if(tp==='channel')html=channelHtml(id);else return;showAt(el,html);});
|
|
121
|
+
})();`;
|
|
122
|
+
|
|
123
|
+
exports.mentionPopupStyles = `
|
|
124
|
+
.dht-mention{cursor:pointer;transition:filter .15s ease}
|
|
125
|
+
.dht-mention:hover{filter:brightness(1.15)}
|
|
126
|
+
.dht-popup{position:fixed;display:none;max-width:340px;min-width:240px;background:#1e1f22;color:#dbdee1;border:1px solid #2b2d31;border-radius:10px;padding:14px 16px 12px;box-shadow:0 12px 32px rgba(0,0,0,.55),0 2px 6px rgba(0,0,0,.35);font-family:"gg sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.4;z-index:99999}
|
|
127
|
+
.dht-popup-close{position:absolute;top:6px;right:8px;background:none;border:none;color:#949ba4;cursor:pointer;font-size:20px;line-height:1;padding:4px 8px;border-radius:4px}
|
|
128
|
+
.dht-popup-close:hover{background:rgba(255,255,255,.06);color:#dbdee1}
|
|
129
|
+
.dht-popup-head{display:flex;align-items:center;gap:10px;margin-right:18px}
|
|
130
|
+
.dht-popup-avatar{width:48px;height:48px;border-radius:50%;object-fit:cover;flex:none}
|
|
131
|
+
.dht-popup-avatar--ph{background:#313338}
|
|
132
|
+
.dht-popup-rolemark{width:32px;height:32px;border-radius:8px;flex:none;display:flex;align-items:center;justify-content:center;font-weight:700;color:#fff}
|
|
133
|
+
.dht-popup-headtext{min-width:0}
|
|
134
|
+
.dht-popup-name{font-weight:600;font-size:16px;word-break:break-word}
|
|
135
|
+
.dht-popup-sub{font-size:12px;color:#949ba4;word-break:break-all}
|
|
136
|
+
.dht-popup-badge{background:#5865F2;color:#fff;font-size:10px;padding:1px 6px;border-radius:4px;margin-left:6px;vertical-align:middle}
|
|
137
|
+
.dht-popup-section{margin-top:10px}
|
|
138
|
+
.dht-popup-row{display:flex;justify-content:space-between;gap:12px;margin-top:6px;font-size:13px}
|
|
139
|
+
.dht-popup-label{color:#949ba4;font-size:11px;text-transform:uppercase;letter-spacing:.04em;font-weight:700}
|
|
140
|
+
.dht-popup-roles{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
141
|
+
.dht-role-pill{display:inline-flex;align-items:center;background:color-mix(in srgb,var(--dht-role) 18%,transparent);color:var(--dht-role);border:1px solid color-mix(in srgb,var(--dht-role) 40%,transparent);padding:1px 8px;border-radius:999px;font-size:11px;line-height:1.5}
|
|
142
|
+
.dht-popup-id{margin-top:10px;padding-top:8px;border-top:1px solid #2b2d31;font-size:11px;color:#6e727a}
|
|
143
|
+
.dht-popup-id code{background:rgba(255,255,255,.05);padding:1px 4px;border-radius:3px}
|
|
144
|
+
`;
|
|
145
|
+
|
|
146
|
+
// ===========================================================================
|
|
147
|
+
// Back-to-top
|
|
148
|
+
// ===========================================================================
|
|
149
|
+
exports.backToTop = `(function(){var btn=document.createElement('button');btn.className='dht-back-top';btn.type='button';var DATA=globalThis.$discordMessage||{};var dict=(DATA.i18n&&(DATA.i18n[DATA.lang]||DATA.i18n.en))||{};btn.title=dict.backToTop||'Back to top';btn.setAttribute('aria-label',dict.backToTop||'Back to top');btn.innerHTML='▲';document.body.appendChild(btn);btn.addEventListener('click',function(){window.scrollTo({top:0,behavior:'smooth'});});function toggle(){btn.style.opacity=window.scrollY>400?'1':'0';btn.style.pointerEvents=window.scrollY>400?'auto':'none';}window.addEventListener('scroll',toggle,{passive:true});toggle();})();`;
|
|
150
|
+
exports.transcriptUtils = `.dht-back-top{position:fixed;bottom:24px;right:24px;width:44px;height:44px;border-radius:50%;border:none;background:#5865F2;color:#fff;font-size:16px;cursor:pointer;box-shadow:0 6px 18px rgba(0,0,0,.45);opacity:0;pointer-events:none;transition:opacity .2s ease,transform .2s ease;z-index:9999}.dht-back-top:hover{transform:translateY(-2px)}`;
|
|
151
|
+
|
|
152
|
+
// ===========================================================================
|
|
153
|
+
// Search bar — Ctrl+F replacement: live highlight, x of n matches, prev/next nav
|
|
154
|
+
// ===========================================================================
|
|
155
|
+
exports.searchBar = `(function(){
|
|
156
|
+
var DATA=globalThis.$discordMessage||{};
|
|
157
|
+
var dict=(DATA.i18n&&(DATA.i18n[DATA.lang]||DATA.i18n.en))||{};
|
|
158
|
+
var bar=document.createElement('div');
|
|
159
|
+
bar.className='dht-search';
|
|
160
|
+
bar.innerHTML='<input type="search" class="dht-search-input" placeholder="'+(dict.searchPlaceholder||'Search…')+'"><span class="dht-search-counter">0</span><button class="dht-search-btn" data-act="prev" title="Previous">▲</button><button class="dht-search-btn" data-act="next" title="Next">▼</button><button class="dht-search-btn" data-act="close" title="Close">×</button>';
|
|
161
|
+
document.body.appendChild(bar);
|
|
162
|
+
var input=bar.querySelector('.dht-search-input');
|
|
163
|
+
var counter=bar.querySelector('.dht-search-counter');
|
|
164
|
+
var matches=[],idx=-1;
|
|
165
|
+
function clear(){matches.forEach(function(m){var p=m.parentNode;if(!p)return;var tn=document.createTextNode(m.textContent);p.replaceChild(tn,m);p.normalize();});matches=[];idx=-1;counter.textContent='0';}
|
|
166
|
+
function walk(node,re,acc){if(node.nodeType===3){var text=node.nodeValue;if(!re.test(text))return;re.lastIndex=0;var frag=document.createDocumentFragment();var last=0;var m;while((m=re.exec(text))!==null){if(m.index>last)frag.appendChild(document.createTextNode(text.slice(last,m.index)));var span=document.createElement('mark');span.className='dht-hit';span.textContent=m[0];frag.appendChild(span);acc.push(span);last=re.lastIndex;}if(last<text.length)frag.appendChild(document.createTextNode(text.slice(last)));node.parentNode.replaceChild(frag,node);}else if(node.nodeType===1){if(node.classList&&(node.classList.contains('dht-search')||node.tagName==='SCRIPT'||node.tagName==='STYLE'))return;for(var i=node.childNodes.length-1;i>=0;i--)walk(node.childNodes[i],re,acc);}}
|
|
167
|
+
function search(q){clear();if(!q||q.length<2)return;var re=new RegExp(q.replace(/[.*+?^\${}()|[\\]\\\\]/g,'\\\\$&'),'gi');walk(document.body,re,matches);if(matches.length){idx=0;goTo();}counter.textContent=matches.length?(idx+1)+' '+(dict.ofMatches||'of')+' '+matches.length:(dict.noMatches||'none');}
|
|
168
|
+
function goTo(){matches.forEach(function(m,i){m.classList.toggle('dht-hit--active',i===idx);});if(idx>=0&&matches[idx]){matches[idx].scrollIntoView({behavior:'smooth',block:'center'});counter.textContent=(idx+1)+' '+(dict.ofMatches||'of')+' '+matches.length;}}
|
|
169
|
+
input.addEventListener('input',function(){search(input.value);});
|
|
170
|
+
bar.addEventListener('click',function(e){var t=e.target;var act=t.getAttribute&&t.getAttribute('data-act');if(act==='next'){if(matches.length){idx=(idx+1)%matches.length;goTo();}}else if(act==='prev'){if(matches.length){idx=(idx-1+matches.length)%matches.length;goTo();}}else if(act==='close'){bar.classList.remove('dht-search--open');input.value='';clear();}});
|
|
171
|
+
document.addEventListener('keydown',function(e){if((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()==='f'){e.preventDefault();bar.classList.add('dht-search--open');input.focus();input.select();}else if(e.key==='Escape'&&bar.classList.contains('dht-search--open')){bar.classList.remove('dht-search--open');input.value='';clear();}else if(e.key==='Enter'&&document.activeElement===input){if(matches.length){idx=(idx+(e.shiftKey?-1:1)+matches.length)%matches.length;goTo();}}});
|
|
172
|
+
})();`;
|
|
173
|
+
exports.searchBarStyles = `.dht-search{position:fixed;top:16px;right:16px;background:#1e1f22;border:1px solid #2b2d31;border-radius:8px;padding:6px 8px;display:none;align-items:center;gap:6px;z-index:99998;box-shadow:0 6px 18px rgba(0,0,0,.5);font-family:"gg sans",sans-serif;color:#dbdee1}.dht-search--open{display:flex}.dht-search-input{background:#2b2d31;color:#dbdee1;border:1px solid #2b2d31;border-radius:4px;padding:4px 8px;font-size:13px;width:220px;outline:none}.dht-search-input:focus{border-color:#5865F2}.dht-search-counter{color:#949ba4;font-size:12px;min-width:60px}.dht-search-btn{background:none;border:none;color:#dbdee1;cursor:pointer;padding:4px 6px;border-radius:4px;font-size:12px}.dht-search-btn:hover{background:rgba(255,255,255,.06)}.dht-hit{background:rgba(255,228,0,.35);color:inherit;border-radius:2px}.dht-hit--active{background:rgba(255,140,0,.7);color:#000}`;
|
|
174
|
+
|
|
175
|
+
// ===========================================================================
|
|
176
|
+
// Image lightbox — click images to fullscreen, arrow keys to navigate
|
|
177
|
+
// ===========================================================================
|
|
178
|
+
exports.lightbox = `(function(){
|
|
179
|
+
var overlay=null,images=[],idx=0;
|
|
180
|
+
function collect(){images=Array.from(document.querySelectorAll('img')).filter(function(i){return !i.closest('.dht-popup')&&!i.classList.contains('dht-popup-avatar')&&i.naturalWidth>40;});}
|
|
181
|
+
function build(){overlay=document.createElement('div');overlay.className='dht-lightbox';overlay.innerHTML='<button class="dht-lb-close" aria-label="Close">×</button><button class="dht-lb-prev" aria-label="Previous">‹</button><img class="dht-lb-img" alt=""><button class="dht-lb-next" aria-label="Next">›</button><div class="dht-lb-caption"></div>';document.body.appendChild(overlay);overlay.addEventListener('click',function(e){if(e.target===overlay||e.target.classList.contains('dht-lb-close'))close();else if(e.target.classList.contains('dht-lb-prev'))nav(-1);else if(e.target.classList.contains('dht-lb-next'))nav(1);});}
|
|
182
|
+
function open(src,alt){if(!overlay)build();collect();idx=images.findIndex(function(i){return i.src===src;});if(idx<0)idx=0;render();overlay.style.display='flex';}
|
|
183
|
+
function nav(d){if(!images.length)return;idx=(idx+d+images.length)%images.length;render();}
|
|
184
|
+
function render(){var img=images[idx];if(!img)return;overlay.querySelector('.dht-lb-img').src=img.src;overlay.querySelector('.dht-lb-caption').textContent=img.alt||'';}
|
|
185
|
+
function close(){if(overlay)overlay.style.display='none';}
|
|
186
|
+
document.addEventListener('click',function(e){var img=e.target;if(img&&img.tagName==='IMG'&&img.naturalWidth>40&&!img.closest('.dht-popup')&&!img.classList.contains('dht-popup-avatar')&&!img.closest('.dht-toc')&&!img.closest('.dht-search')){e.preventDefault();open(img.src,img.alt);}});
|
|
187
|
+
document.addEventListener('keydown',function(e){if(!overlay||overlay.style.display!=='flex')return;if(e.key==='Escape')close();else if(e.key==='ArrowLeft')nav(-1);else if(e.key==='ArrowRight')nav(1);});
|
|
188
|
+
})();`;
|
|
189
|
+
exports.lightboxStyles = `.dht-lightbox{position:fixed;inset:0;background:rgba(0,0,0,.92);display:none;align-items:center;justify-content:center;z-index:100000;flex-direction:column}.dht-lb-img{max-width:90vw;max-height:80vh;object-fit:contain;box-shadow:0 4px 20px rgba(0,0,0,.6);border-radius:6px}.dht-lb-close,.dht-lb-prev,.dht-lb-next{position:absolute;background:rgba(0,0,0,.4);color:#fff;border:none;cursor:pointer;font-size:28px;width:48px;height:48px;border-radius:50%;display:flex;align-items:center;justify-content:center}.dht-lb-close:hover,.dht-lb-prev:hover,.dht-lb-next:hover{background:rgba(255,255,255,.15)}.dht-lb-close{top:20px;right:20px}.dht-lb-prev{left:20px;top:50%;transform:translateY(-50%)}.dht-lb-next{right:20px;top:50%;transform:translateY(-50%)}.dht-lb-caption{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);color:#dbdee1;font-family:"gg sans",sans-serif;font-size:14px;padding:6px 14px;background:rgba(0,0,0,.5);border-radius:4px;max-width:80%}`;
|
|
190
|
+
|
|
191
|
+
// ===========================================================================
|
|
192
|
+
// TOC / Sidebar — list participants, click jumps to their first message
|
|
193
|
+
// ===========================================================================
|
|
194
|
+
exports.toc = `(function(){
|
|
195
|
+
var DATA=globalThis.$discordMessage||{};
|
|
196
|
+
var dict=(DATA.i18n&&(DATA.i18n[DATA.lang]||DATA.i18n.en))||{};
|
|
197
|
+
var users=DATA.users||DATA.profiles||{};
|
|
198
|
+
var ids=Object.keys(users);
|
|
199
|
+
if(ids.length===0)return;
|
|
200
|
+
function firstMessageOf(uid){var m=document.querySelector('discord-message[profile="'+uid+'"]');return m?m.id:null;}
|
|
201
|
+
var btn=document.createElement('button');btn.className='dht-toc-toggle';btn.type='button';btn.title=dict.tocTitle||'Participants';btn.setAttribute('aria-label',dict.tocTitle||'Participants');btn.innerHTML='☰';document.body.appendChild(btn);
|
|
202
|
+
var panel=document.createElement('aside');panel.className='dht-toc';
|
|
203
|
+
var html='<header><h3>'+(dict.tocTitle||'Participants')+'</h3><button class="dht-toc-close" aria-label="Close">×</button></header><ul>';
|
|
204
|
+
ids.sort(function(a,b){var ua=users[a],ub=users[b];var na=(ua.displayName||ua.author||ua.username||'').toLowerCase();var nb=(ub.displayName||ub.author||ub.username||'').toLowerCase();return na.localeCompare(nb);}).forEach(function(id){var u=users[id];var name=u.displayName||u.author||u.username||'Unknown';var avatar=u.avatar||'';var color=(typeof u.bannerColor==='string'&&/^#[0-9a-f]{3,8}$/i.test(u.bannerColor))?u.bannerColor:(typeof u.roleColor==='string'&&/^#[0-9a-f]{3,8}$/i.test(u.roleColor)?u.roleColor:'#dbdee1');html+='<li data-uid="'+id+'">'+(avatar?'<img src="'+avatar+'" alt="">':'<span class="dht-toc-ph"></span>')+'<span class="dht-toc-name" style="color:'+color+'">'+name.replace(/[&<>]/g,function(c){return ({'&':'&','<':'<','>':'>'})[c];})+'</span></li>';});
|
|
205
|
+
html+='</ul>';panel.innerHTML=html;document.body.appendChild(panel);
|
|
206
|
+
btn.addEventListener('click',function(){panel.classList.toggle('dht-toc--open');});
|
|
207
|
+
panel.querySelector('.dht-toc-close').addEventListener('click',function(){panel.classList.remove('dht-toc--open');});
|
|
208
|
+
panel.querySelectorAll('li').forEach(function(li){li.addEventListener('click',function(){var uid=li.getAttribute('data-uid');var mid=firstMessageOf(uid);if(mid){var el=document.getElementById(mid);if(el){el.scrollIntoView({behavior:'smooth',block:'center'});el.style.backgroundColor='rgba(148,156,247,0.18)';setTimeout(function(){el.style.backgroundColor='transparent';},1500);}}});});
|
|
209
|
+
})();`;
|
|
210
|
+
exports.tocStyles = `.dht-toc-toggle{position:fixed;top:16px;left:16px;width:40px;height:40px;border-radius:50%;border:none;background:#2b2d31;color:#fff;font-size:16px;cursor:pointer;box-shadow:0 4px 12px rgba(0,0,0,.4);z-index:9998}.dht-toc-toggle:hover{background:#5865F2}.dht-toc{position:fixed;top:0;left:-320px;width:300px;height:100vh;background:#1e1f22;border-right:1px solid #2b2d31;transition:left .25s ease;z-index:9997;overflow-y:auto;font-family:"gg sans",sans-serif;color:#dbdee1;padding:16px}.dht-toc--open{left:0}.dht-toc header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid #2b2d31}.dht-toc h3{margin:0;font-size:14px;text-transform:uppercase;letter-spacing:.04em;color:#949ba4}.dht-toc-close{background:none;border:none;color:#949ba4;cursor:pointer;font-size:22px;line-height:1}.dht-toc ul{list-style:none;padding:0;margin:0}.dht-toc li{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:4px;cursor:pointer;font-size:14px}.dht-toc li:hover{background:rgba(255,255,255,.04)}.dht-toc li img,.dht-toc-ph{width:28px;height:28px;border-radius:50%;flex:none}.dht-toc-ph{background:#313338}.dht-toc-name{flex:1;font-weight:500}`;
|
|
211
|
+
|
|
212
|
+
// ===========================================================================
|
|
213
|
+
// Language switcher
|
|
214
|
+
// ===========================================================================
|
|
215
|
+
exports.i18nSwitcher = `(function(){
|
|
216
|
+
var DATA=globalThis.$discordMessage||{};
|
|
217
|
+
if(!DATA.i18n)return;
|
|
218
|
+
var langs=Object.keys(DATA.i18n);
|
|
219
|
+
if(langs.length<2)return;
|
|
220
|
+
var current=DATA.lang||'en';
|
|
221
|
+
function apply(lang){DATA.lang=lang;var dict=DATA.i18n[lang]||DATA.i18n.en||{};document.querySelectorAll('[data-i18n]').forEach(function(el){var key=el.getAttribute('data-i18n');var raw=dict[key];if(typeof raw!=='string')return;var params=el.getAttribute('data-i18n-params');if(params){try{var obj=JSON.parse(params);Object.keys(obj).forEach(function(k){raw=raw.replace('{'+k+'}',obj[k]);});}catch(_){}}el.textContent=raw;});}
|
|
222
|
+
var wrap=document.createElement('div');wrap.className='dht-langs';langs.forEach(function(l){var b=document.createElement('button');b.type='button';b.textContent=l.toUpperCase();b.className='dht-lang'+(l===current?' dht-lang--active':'');b.addEventListener('click',function(){wrap.querySelectorAll('.dht-lang').forEach(function(x){x.classList.remove('dht-lang--active');});b.classList.add('dht-lang--active');apply(l);});wrap.appendChild(b);});document.body.appendChild(wrap);
|
|
223
|
+
})();`;
|
|
224
|
+
exports.i18nStyles = `.dht-langs{position:fixed;bottom:24px;left:24px;display:flex;gap:4px;background:#1e1f22;border:1px solid #2b2d31;border-radius:6px;padding:4px;z-index:9998;font-family:"gg sans",sans-serif}.dht-lang{background:none;border:none;color:#949ba4;cursor:pointer;padding:4px 10px;border-radius:4px;font-size:12px;font-weight:600}.dht-lang:hover{color:#dbdee1}.dht-lang--active{background:#5865F2;color:#fff}`;
|
|
225
|
+
|
|
226
|
+
// ===========================================================================
|
|
227
|
+
// Date separators (server renders <div class="dht-date-sep">…</div>)
|
|
228
|
+
// ===========================================================================
|
|
229
|
+
exports.dateSeparatorStyles = `.dht-date-sep{display:flex;align-items:center;gap:12px;margin:24px 16px 8px;color:#b5bac1;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.04em}.dht-date-sep::before,.dht-date-sep::after{content:"";flex:1;height:1px;background:#3f4248}`;
|
|
230
|
+
|
|
30
231
|
exports.ggSansFont = '@font-face{src:url(https://cdn.jsdelivr.net/gh/Tyrrrz/DiscordFonts@master/ggsans-normal-400.woff2);font-family:"gg sans";font-weight:400;font-style:normal}@font-face{src:url(https://cdn.jsdelivr.net/gh/Tyrrrz/DiscordFonts@master/ggsans-normal-500.woff2);font-family:"gg sans";font-weight:500;font-style:normal}@font-face{src:url(https://cdn.jsdelivr.net/gh/Tyrrrz/DiscordFonts@master/ggsans-normal-600.woff2);font-family:"gg sans";font-weight:600;font-style:normal}@font-face{src:url(https://cdn.jsdelivr.net/gh/Tyrrrz/DiscordFonts@master/ggsans-normal-700.woff2);font-family:"gg sans";font-weight:700;font-style:normal}@font-face{src:url(https://cdn.jsdelivr.net/gh/Tyrrrz/DiscordFonts@master/ggsans-normal-800.woff2);font-family:"gg sans";font-weight:800;font-style:normal}@font-face{src:url(https://cdn.jsdelivr.net/gh/Tyrrrz/DiscordFonts@master/ggsans-italic-400.woff2);font-family:"gg sans";font-weight:400;font-style:italic}@font-face{src:url(https://cdn.jsdelivr.net/gh/Tyrrrz/DiscordFonts@master/ggsans-italic-500.woff2);font-family:"gg sans";font-weight:500;font-style:italic}@font-face{src:url(https://cdn.jsdelivr.net/gh/Tyrrrz/DiscordFonts@master/ggsans-italic-600.woff2);font-family:"gg sans";font-weight:600;font-style:italic}@font-face{src:url(https://cdn.jsdelivr.net/gh/Tyrrrz/DiscordFonts@master/ggsans-italic-700.woff2);font-family:"gg sans";font-weight:700;font-style:italic}@font-face{src:url(https://cdn.jsdelivr.net/gh/Tyrrrz/DiscordFonts@master/ggsans-italic-800.woff2);font-family:"gg sans";font-weight:800;font-style:italic}';
|
|
31
|
-
//# sourceMappingURL=client.js.map
|
|
232
|
+
//# sourceMappingURL=client.js.map
|