discord-html-transcripts-fix 1.4.0 → 1.6.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/dist/generator/index.js +51 -19
- package/dist/generator/renderers/components/Container.js +12 -4
- package/dist/generator/renderers/components/section/SectionContent.js +7 -3
- package/dist/generator/renderers/message.js +108 -32
- package/dist/generator/renderers/systemMessage.js +52 -24
- package/dist/generator/transcript.js +29 -9
- package/dist/static/client.js +372 -180
- package/dist/types.d.ts +14 -0
- package/dist/utils/buildProfiles.js +19 -10
- package/package.json +17 -29
package/dist/static/client.js
CHANGED
|
@@ -62,7 +62,8 @@ const defaultDicts = {
|
|
|
62
62
|
edited: 'edited',
|
|
63
63
|
editedAt: 'Edited at {time}',
|
|
64
64
|
joined: 'joined the server',
|
|
65
|
-
pinned: 'pinned
|
|
65
|
+
pinned: 'pinned {message} to this channel.',
|
|
66
|
+
pinnedLink: 'a message',
|
|
66
67
|
boosted: 'boosted the server!',
|
|
67
68
|
threadStarted: 'started a thread:',
|
|
68
69
|
changedChannelName: 'changed the channel name:',
|
|
@@ -105,16 +106,17 @@ const defaultDicts = {
|
|
|
105
106
|
filterHasImage: 'Has image',
|
|
106
107
|
filterHasEmbed: 'Has embed',
|
|
107
108
|
filterHasAttachment: 'Has attachment',
|
|
109
|
+
filterHasComponentV2: 'Has container',
|
|
108
110
|
filterApply: 'Apply',
|
|
109
111
|
filterReset: 'Reset',
|
|
110
|
-
filterShowing: 'Showing {visible} of {total}',
|
|
111
112
|
flags: 'Badges',
|
|
112
113
|
},
|
|
113
114
|
de: {
|
|
114
115
|
edited: 'bearbeitet',
|
|
115
116
|
editedAt: 'Bearbeitet am {time}',
|
|
116
117
|
joined: 'ist dem Server beigetreten',
|
|
117
|
-
pinned: 'hat
|
|
118
|
+
pinned: 'hat {message} in diesem Channel angepinnt.',
|
|
119
|
+
pinnedLink: 'eine Nachricht',
|
|
118
120
|
boosted: 'hat den Server geboostet!',
|
|
119
121
|
threadStarted: 'hat einen Thread gestartet:',
|
|
120
122
|
changedChannelName: 'hat den Channel-Namen geändert:',
|
|
@@ -157,9 +159,9 @@ const defaultDicts = {
|
|
|
157
159
|
filterHasImage: 'Mit Bild',
|
|
158
160
|
filterHasEmbed: 'Mit Embed',
|
|
159
161
|
filterHasAttachment: 'Mit Anhang',
|
|
162
|
+
filterHasComponentV2: 'Mit Container',
|
|
160
163
|
filterApply: 'Anwenden',
|
|
161
164
|
filterReset: 'Zurücksetzen',
|
|
162
|
-
filterShowing: 'Zeige {visible} von {total}',
|
|
163
165
|
flags: 'Abzeichen',
|
|
164
166
|
},
|
|
165
167
|
};
|
|
@@ -203,26 +205,173 @@ exports.mentionPopup = `(function(){
|
|
|
203
205
|
function safeColor(c,fb){fb=fb||'#5865F2';return typeof c==='string' && /^#[0-9a-fA-F]{3,8}$/.test(c) ? c : fb;}
|
|
204
206
|
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;}
|
|
205
207
|
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 '';}}
|
|
208
|
+
function copyBtn(text,label){if(text==null||text==='')return '';return '<button type="button" class="dht-popup-copy" data-copy="'+esc(text)+'" title="Copy '+esc(label||'value')+'" aria-label="Copy '+esc(label||'value')+'"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button>';}
|
|
206
209
|
var popup=null;
|
|
207
|
-
function
|
|
210
|
+
function isTriggerInPath(path){
|
|
211
|
+
for(var i=0;i<path.length;i++){
|
|
212
|
+
var x=path[i];if(!x)continue;
|
|
213
|
+
if(x.getAttribute && x.getAttribute('data-mention-id'))return true;
|
|
214
|
+
if(x.tagName && typeof x.tagName==='string'){var tn=x.tagName.toLowerCase();if(tn==='discord-command')return true;}
|
|
215
|
+
if(x.classList){
|
|
216
|
+
if(x.classList.contains('discord-author-info')||x.classList.contains('discord-author-username')||x.classList.contains('discord-author-avatar')||x.classList.contains('discord-application-tag'))return true;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
function ensure(){
|
|
222
|
+
if(popup)return popup;
|
|
223
|
+
popup=document.createElement('div');popup.className='dht-popup';popup.setAttribute('role','dialog');
|
|
224
|
+
popup.innerHTML='<div class="dht-popup-body"></div><button type="button" class="dht-popup-close" aria-label="Close">×</button>';
|
|
225
|
+
document.body.appendChild(popup);
|
|
226
|
+
popup.querySelector('.dht-popup-close').addEventListener('click',hide);
|
|
227
|
+
document.addEventListener('click',function(e){
|
|
228
|
+
if(!e||e.defaultPrevented)return;
|
|
229
|
+
if(!popup||popup.style.display!=='block')return;
|
|
230
|
+
if(popup.contains(e.target))return;
|
|
231
|
+
var path=(typeof e.composedPath==='function')?e.composedPath():[];
|
|
232
|
+
if(isTriggerInPath(path))return;
|
|
233
|
+
hide();
|
|
234
|
+
});
|
|
235
|
+
document.addEventListener('keydown',function(e){if(e.key==='Escape')hide();});
|
|
236
|
+
window.addEventListener('resize',hide);
|
|
237
|
+
return popup;
|
|
238
|
+
}
|
|
208
239
|
function hide(){if(popup)popup.style.display='none';}
|
|
209
240
|
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';}
|
|
210
241
|
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>';}
|
|
211
242
|
function flagBadgeHtml(flagName){try{var dh=globalThis.__DHT_FLAG_BADGES__||{};var b=dh[flagName];if(b)return '<span class="dht-flag" title="'+esc(b.label)+'" style="color:'+safeColor(b.color)+';">'+esc(b.emoji)+'</span>';}catch(_){};return '<span class="dht-flag" title="'+esc(flagName)+'">'+esc(flagName)+'</span>';}
|
|
212
|
-
function userHtml(id){
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
243
|
+
function userHtml(id){
|
|
244
|
+
var d=DATA();
|
|
245
|
+
var u=(d.users&&d.users[id])||null;
|
|
246
|
+
var p=(d.profiles&&d.profiles[id])||null;
|
|
247
|
+
if(!u&&!p)return '<i>?</i><div class="dht-popup-id">ID: <code>'+esc(id)+'</code>'+copyBtn(id,'user ID')+'</div>';
|
|
248
|
+
var name=(u&&(u.displayName||u.username))||(p&&p.author)||'Unknown';
|
|
249
|
+
var username=u&&u.username?'@'+u.username:'';
|
|
250
|
+
var avatar=(u&&u.avatar)||(p&&p.avatar)||'';
|
|
251
|
+
var color=safeColor((u&&u.bannerColor)||(p&&p.roleColor),'#dbdee1');
|
|
252
|
+
var bot=(u&&u.bot)||(p&&p.bot);
|
|
253
|
+
var verifiedBot=u&&u.verifiedBot;
|
|
254
|
+
var roles=u&&Array.isArray(u.roles)&&u.roles.length?u.roles.map(rolePill).join(''):'';
|
|
255
|
+
var flags=u&&Array.isArray(u.flags)&&u.flags.length?u.flags.filter(function(f){return f!=='VerifiedBot';}).map(flagBadgeHtml).join(''):'';
|
|
256
|
+
var joinedAt=u&&u.joinedAt?fmt(u.joinedAt):'';
|
|
257
|
+
var createdAt=u&&u.createdAt?fmt(u.createdAt):'';
|
|
258
|
+
var botBadge=bot?(' <span class="dht-popup-badge">'+esc(t('botBadge'))+(verifiedBot?' ✓':'')+'</span>'):'';
|
|
259
|
+
return ''
|
|
260
|
+
+'<div class="dht-popup-head">'
|
|
261
|
+
+(avatar?'<img class="dht-popup-avatar" src="'+esc(avatar)+'" alt="">':'<div class="dht-popup-avatar dht-popup-avatar--ph"></div>')
|
|
262
|
+
+'<div class="dht-popup-headtext">'
|
|
263
|
+
+'<div class="dht-popup-name" style="color:'+color+';">'+esc(name)+botBadge+copyBtn(name,'name')+'</div>'
|
|
264
|
+
+(username?'<div class="dht-popup-sub">'+esc(username)+copyBtn(username,'username')+'</div>':'')
|
|
265
|
+
+'</div>'
|
|
266
|
+
+'</div>'
|
|
267
|
+
+(flags?'<div class="dht-popup-section"><div class="dht-popup-label">'+esc(t('flags'))+'</div><div class="dht-popup-flags">'+flags+'</div></div>':'')
|
|
268
|
+
+(roles?'<div class="dht-popup-section"><div class="dht-popup-label">Roles</div><div class="dht-popup-roles">'+roles+'</div></div>':'')
|
|
269
|
+
+(joinedAt?'<div class="dht-popup-row"><span class="dht-popup-label">Server</span><span>'+esc(joinedAt)+'</span></div>':'')
|
|
270
|
+
+(createdAt?'<div class="dht-popup-row"><span class="dht-popup-label">Account</span><span>'+esc(createdAt)+'</span></div>':'')
|
|
271
|
+
+'<div class="dht-popup-id">ID: <code>'+esc(id)+'</code>'+copyBtn(id,'user ID')+'</div>';
|
|
272
|
+
}
|
|
273
|
+
function roleHtml(id){
|
|
274
|
+
var r=(DATA().roles||{})[id];
|
|
275
|
+
if(!r)return '<i>?</i><div class="dht-popup-id">ID: <code>'+esc(id)+'</code>'+copyBtn(id,'role ID')+'</div>';
|
|
276
|
+
var color=safeColor(r.color,'#dbdee1');
|
|
277
|
+
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)+copyBtn('@'+r.name,'role name')+'</div>'+(r.color?'<div class="dht-popup-sub"><code>'+esc(r.color)+'</code>'+copyBtn(r.color,'color')+'</div>':'')+'</div></div>'
|
|
278
|
+
+(r.memberCount!=null?'<div class="dht-popup-row"><span class="dht-popup-label">Members</span><span>'+esc(r.memberCount)+'</span></div>':'')
|
|
279
|
+
+(r.position!=null?'<div class="dht-popup-row"><span class="dht-popup-label">Position</span><span>'+esc(r.position)+'</span></div>':'')
|
|
280
|
+
+(r.hoist?'<div class="dht-popup-row"><span class="dht-popup-label">Hoisted</span><span>Yes</span></div>':'')
|
|
281
|
+
+(r.mentionable?'<div class="dht-popup-row"><span class="dht-popup-label">Mentionable</span><span>Yes</span></div>':'')
|
|
282
|
+
+(r.managed?'<div class="dht-popup-row"><span class="dht-popup-label">Managed</span><span>Bot/Integration</span></div>':'')
|
|
283
|
+
+'<div class="dht-popup-id">ID: <code>'+esc(id)+'</code>'+copyBtn(id,'role ID')+'</div>';
|
|
284
|
+
}
|
|
285
|
+
function channelHtml(id){
|
|
286
|
+
var c=(DATA().channels||{})[id];
|
|
287
|
+
if(!c)return '<i>Channel</i><div class="dht-popup-id">ID: <code>'+esc(id)+'</code>'+copyBtn(id,'channel ID')+'</div>';
|
|
288
|
+
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)+copyBtn('#'+c.name,'channel')+'</div>'+(c.parent?'<div class="dht-popup-sub">in '+esc(c.parent)+'</div>':'')+'</div></div>'
|
|
289
|
+
+(c.topic?'<div class="dht-popup-section"><div class="dht-popup-label">Topic</div><div>'+esc(c.topic)+'</div></div>':'')
|
|
290
|
+
+(c.nsfw?'<div class="dht-popup-row"><span class="dht-popup-label">NSFW</span><span>Yes</span></div>':'')
|
|
291
|
+
+'<div class="dht-popup-id">ID: <code>'+esc(id)+'</code>'+copyBtn(id,'channel ID')+'</div>';
|
|
292
|
+
}
|
|
293
|
+
function slashHtml(el){
|
|
294
|
+
var cmd=el.getAttribute('data-slash-cmd')||el.getAttribute('command')||'/?';
|
|
295
|
+
var by=el.getAttribute('data-slash-by')||'';
|
|
296
|
+
var byId=el.getAttribute('data-slash-by-id')||el.getAttribute('profile')||'';
|
|
297
|
+
var optsJson=el.getAttribute('data-slash-options')||'[]';
|
|
298
|
+
var opts;
|
|
299
|
+
try{opts=JSON.parse(optsJson);}catch(_){opts=[];}
|
|
300
|
+
if(!Array.isArray(opts))opts=[];
|
|
301
|
+
var paramsHtml=opts.length
|
|
302
|
+
? '<div class="dht-popup-section"><div class="dht-popup-label">Parameters</div><div class="dht-slash-params">'
|
|
303
|
+
+opts.map(function(o){return '<div class="dht-slash-param"><span class="dht-slash-param-name">'+esc(o.name)+'</span><span class="dht-slash-param-val">'+esc(o.value)+'</span>'+copyBtn(o.value,o.name)+'</div>';}).join('')
|
|
304
|
+
+'</div></div>'
|
|
305
|
+
: '<div class="dht-popup-sub" style="margin-top:8px">No parameters</div>';
|
|
306
|
+
return '<div class="dht-popup-head">'
|
|
307
|
+
+'<div class="dht-popup-rolemark" style="background:#5865F2;font-family:Consolas,Menlo,monospace;font-size:18px;">/</div>'
|
|
308
|
+
+'<div class="dht-popup-headtext">'
|
|
309
|
+
+'<div class="dht-popup-name" style="font-family:Consolas,Menlo,monospace;color:#5865F2">'+esc(cmd)+copyBtn(cmd,'command')+'</div>'
|
|
310
|
+
+(by?'<div class="dht-popup-sub">used by '+esc(by)+'</div>':'')
|
|
311
|
+
+'</div>'
|
|
312
|
+
+'</div>'
|
|
313
|
+
+paramsHtml
|
|
314
|
+
+(byId?'<div class="dht-popup-id">User ID: <code>'+esc(byId)+'</code>'+copyBtn(byId,'user ID')+'</div>':'');
|
|
315
|
+
}
|
|
316
|
+
function findAncestor(path,pred){for(var i=0;i<path.length;i++){if(pred(path[i]))return path[i];}return null;}
|
|
317
|
+
function isAuthorPath(path){
|
|
318
|
+
for(var i=0;i<path.length;i++){
|
|
319
|
+
var x=path[i];if(!x||!x.classList)continue;
|
|
320
|
+
if(x.classList.contains('discord-author-info')||x.classList.contains('discord-author-username')||x.classList.contains('discord-author-avatar')||x.classList.contains('discord-application-tag'))return true;
|
|
321
|
+
}
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
// Copy-button delegated handler (any .dht-popup-copy click — inside popup or anywhere else)
|
|
325
|
+
document.addEventListener('click',function(e){
|
|
326
|
+
var t=e.target;
|
|
327
|
+
if(!t)return;
|
|
328
|
+
var btn=null;
|
|
329
|
+
if(t.closest)btn=t.closest('.dht-popup-copy');
|
|
330
|
+
if(!btn)return;
|
|
331
|
+
var text=btn.getAttribute('data-copy')||'';
|
|
332
|
+
if(!text)return;
|
|
333
|
+
e.preventDefault();e.stopPropagation();
|
|
334
|
+
function done(){btn.classList.add('dht-popup-copy--ok');setTimeout(function(){btn.classList.remove('dht-popup-copy--ok');},900);}
|
|
335
|
+
try{
|
|
336
|
+
if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(text).then(done,function(){fallback();});}
|
|
337
|
+
else fallback();
|
|
338
|
+
}catch(_){fallback();}
|
|
339
|
+
function fallback(){try{var ta=document.createElement('textarea');ta.value=text;ta.style.position='fixed';ta.style.opacity='0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);done();}catch(_2){}}
|
|
340
|
+
},true);
|
|
341
|
+
// Main trigger handler
|
|
342
|
+
document.addEventListener('click',function(e){
|
|
343
|
+
if(!e||e.defaultPrevented)return;
|
|
216
344
|
var path=(typeof e.composedPath==='function')?e.composedPath():[];
|
|
217
345
|
if(!path.length){var n=e.target;while(n){path.push(n);n=n.parentNode||(n.host);}}
|
|
218
|
-
|
|
219
|
-
for(var
|
|
220
|
-
|
|
221
|
-
var
|
|
222
|
-
if(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
346
|
+
// 0) skip if click is on a copy button (handled in capture phase above)
|
|
347
|
+
for(var z=0;z<path.length;z++){var zz=path[z];if(zz&&zz.classList&&zz.classList.contains('dht-popup-copy'))return;}
|
|
348
|
+
// 1) explicit mention pills with data-mention-id (users/roles/channels via markdown)
|
|
349
|
+
var pill=findAncestor(path,function(x){return x&&x.getAttribute&&x.getAttribute('data-mention-id');});
|
|
350
|
+
if(pill){
|
|
351
|
+
var tp=pill.getAttribute('data-mention-type');var id=pill.getAttribute('data-mention-id');
|
|
352
|
+
if(!tp||!id)return;
|
|
353
|
+
e.preventDefault();e.stopPropagation();
|
|
354
|
+
var html='';
|
|
355
|
+
if(tp==='user')html=userHtml(id);
|
|
356
|
+
else if(tp==='role')html=roleHtml(id);
|
|
357
|
+
else if(tp==='channel')html=channelHtml(id);
|
|
358
|
+
else return;
|
|
359
|
+
showAt(pill,html);return;
|
|
360
|
+
}
|
|
361
|
+
// 2) slash command pill — discord-command web component
|
|
362
|
+
var cmdEl=findAncestor(path,function(x){return x&&x.tagName&&typeof x.tagName==='string'&&x.tagName.toLowerCase()==='discord-command';});
|
|
363
|
+
if(cmdEl){
|
|
364
|
+
e.preventDefault();e.stopPropagation();
|
|
365
|
+
showAt(cmdEl,slashHtml(cmdEl));return;
|
|
366
|
+
}
|
|
367
|
+
// 3) author area inside <discord-message> shadow DOM (avatar, name, BOT/APP tag)
|
|
368
|
+
if(isAuthorPath(path)){
|
|
369
|
+
var msgEl=findAncestor(path,function(x){return x&&x.tagName&&typeof x.tagName==='string'&&x.tagName.toLowerCase()==='discord-message';});
|
|
370
|
+
if(msgEl){
|
|
371
|
+
var uid=msgEl.getAttribute('profile')||msgEl.getAttribute('data-author-id');
|
|
372
|
+
if(uid){e.preventDefault();e.stopPropagation();showAt(msgEl,userHtml(uid));return;}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
226
375
|
});
|
|
227
376
|
})();`;
|
|
228
377
|
|
|
@@ -272,8 +421,35 @@ exports.mentionPopupStyles = `
|
|
|
272
421
|
.dht-popup-label{color:#949ba4;font-size:11px;text-transform:uppercase;letter-spacing:.04em;font-weight:700}
|
|
273
422
|
.dht-popup-roles{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
274
423
|
.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}
|
|
275
|
-
.dht-popup-id{margin-top:10px;padding-top:8px;border-top:1px solid #2b2d31;font-size:11px;color:#6e727a}
|
|
424
|
+
.dht-popup-id{margin-top:10px;padding-top:8px;border-top:1px solid #2b2d31;font-size:11px;color:#6e727a;display:flex;align-items:center;gap:6px}
|
|
276
425
|
.dht-popup-id code{background:rgba(255,255,255,.05);padding:1px 4px;border-radius:3px}
|
|
426
|
+
/* Copy buttons inside the popup */
|
|
427
|
+
.dht-popup-copy{display:inline-flex;align-items:center;justify-content:center;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.06);color:#b5bac1;border-radius:4px;width:22px;height:22px;padding:0;margin-left:6px;cursor:pointer;vertical-align:middle;transition:background .15s ease,color .15s ease,border-color .15s ease;flex:none}
|
|
428
|
+
.dht-popup-copy:hover{background:rgba(255,255,255,.1);color:#fff}
|
|
429
|
+
.dht-popup-copy:focus-visible{outline:2px solid #5865F2;outline-offset:2px}
|
|
430
|
+
.dht-popup-copy--ok{background:#3ba55d!important;color:#fff!important;border-color:#3ba55d!important}
|
|
431
|
+
.dht-popup-copy svg{display:block}
|
|
432
|
+
.dht-popup-name{display:flex;align-items:center;gap:0;flex-wrap:wrap}
|
|
433
|
+
.dht-popup-sub{display:flex;align-items:center;gap:0;flex-wrap:wrap}
|
|
434
|
+
/* Slash command popup — parameter list */
|
|
435
|
+
.dht-slash-params{display:flex;flex-direction:column;gap:4px;margin-top:4px}
|
|
436
|
+
.dht-slash-param{display:flex;align-items:center;gap:6px;background:rgba(255,255,255,.04);padding:4px 8px;border-radius:4px;font-size:12px}
|
|
437
|
+
.dht-slash-param-name{color:#949ba4;font-family:Consolas,Menlo,monospace}
|
|
438
|
+
.dht-slash-param-name::after{content:":"}
|
|
439
|
+
.dht-slash-param-val{color:#dbdee1;font-family:Consolas,Menlo,monospace;word-break:break-all;flex:1}
|
|
440
|
+
/* Make message author area look clickable (skyra shadow DOM elements bubble into the host) */
|
|
441
|
+
discord-message .discord-author-username,
|
|
442
|
+
discord-message .discord-author-info,
|
|
443
|
+
discord-message [slot="author-image"],
|
|
444
|
+
discord-message .discord-author-avatar,
|
|
445
|
+
discord-message .discord-application-tag{cursor:pointer}
|
|
446
|
+
discord-message .discord-author-username:hover,
|
|
447
|
+
discord-message .discord-author-info:hover{text-decoration:underline}
|
|
448
|
+
/* Slash command pill — clickable affordance */
|
|
449
|
+
discord-command.dht-slash-clickable,
|
|
450
|
+
discord-command{cursor:pointer;transition:filter .15s ease}
|
|
451
|
+
discord-command.dht-slash-clickable:hover,
|
|
452
|
+
discord-command:hover{filter:brightness(1.2)}
|
|
277
453
|
`;
|
|
278
454
|
|
|
279
455
|
// ===========================================================================
|
|
@@ -283,39 +459,13 @@ exports.backToTop = `(function(){var btn=document.createElement('button');btn.cl
|
|
|
283
459
|
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)}`;
|
|
284
460
|
|
|
285
461
|
// ===========================================================================
|
|
286
|
-
// Search
|
|
462
|
+
// Search — handled inside the unified TOC panel (see exports.toc).
|
|
463
|
+
// These exports stay for backwards compatibility with anyone wiring them
|
|
464
|
+
// individually; both are inert (no DOM injection). Search-hit styles still
|
|
465
|
+
// live here because the TOC IIFE creates <mark class="dht-hit"> nodes.
|
|
287
466
|
// ===========================================================================
|
|
288
|
-
exports.searchBar =
|
|
289
|
-
|
|
290
|
-
var dict=(DATA.i18n&&(DATA.i18n[DATA.lang]||DATA.i18n.en))||{};
|
|
291
|
-
var bar=document.createElement('div');
|
|
292
|
-
bar.className='dht-search';
|
|
293
|
-
function esc(s){return String(s==null?'':s).replace(/[&<>"']/g,function(c){return ({'&':'&','<':'<','>':'>','"':'"',"'":'''})[c];});}
|
|
294
|
-
bar.innerHTML='<input type="search" class="dht-search-input" placeholder="'+esc(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>';
|
|
295
|
-
document.body.appendChild(bar);
|
|
296
|
-
var input=bar.querySelector('.dht-search-input');
|
|
297
|
-
var counter=bar.querySelector('.dht-search-counter');
|
|
298
|
-
var matches=[],idx=-1;
|
|
299
|
-
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';}
|
|
300
|
-
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);}}
|
|
301
|
-
function search(q){clear();if(!q||q.length<2)return;var re=new RegExp(q.replace(/[.*+?^\${}()|[\\]\\\\]/g,function(c){return '\\\\'+c;}),'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||'no matches');}
|
|
302
|
-
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;}}
|
|
303
|
-
input.addEventListener('input',function(){search(input.value);});
|
|
304
|
-
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();}});
|
|
305
|
-
document.addEventListener('keydown',function(e){
|
|
306
|
-
if((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()==='f'){
|
|
307
|
-
// Skip if user is currently typing in the filter panel
|
|
308
|
-
var ae=document.activeElement;
|
|
309
|
-
if(ae && ae.closest && ae.closest('.dht-filter'))return;
|
|
310
|
-
e.preventDefault();bar.classList.add('dht-search--open');input.focus();input.select();
|
|
311
|
-
}else if(e.key==='Escape'&&bar.classList.contains('dht-search--open')){
|
|
312
|
-
bar.classList.remove('dht-search--open');input.value='';clear();
|
|
313
|
-
}else if(e.key==='Enter'&&document.activeElement===input){
|
|
314
|
-
if(matches.length){idx=(idx+(e.shiftKey?-1:1)+matches.length)%matches.length;goTo();}
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
})();`;
|
|
318
|
-
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}`;
|
|
467
|
+
exports.searchBar = '/* searchBar: merged into TOC */';
|
|
468
|
+
exports.searchBarStyles = `.dht-hit{background:rgba(255,228,0,.35);color:inherit;border-radius:2px}.dht-hit--active{background:rgba(255,140,0,.7);color:#000}`;
|
|
319
469
|
|
|
320
470
|
// ===========================================================================
|
|
321
471
|
// Image lightbox — click images to fullscreen, arrow keys to navigate
|
|
@@ -341,24 +491,166 @@ exports.toc = `(function(){
|
|
|
341
491
|
var DATA=globalThis.$discordMessage||{};
|
|
342
492
|
var dict=(DATA.i18n&&(DATA.i18n[DATA.lang]||DATA.i18n.en))||{};
|
|
343
493
|
var users=DATA.users||DATA.profiles||{};
|
|
344
|
-
var
|
|
345
|
-
|
|
494
|
+
var roles=DATA.roles||{};
|
|
495
|
+
var userIds=Object.keys(users).filter(function(x){return /^\\d+$/.test(x);}).sort(function(a,b){var na=(users[a].displayName||users[a].author||users[a].username||'').toLowerCase();var nb=(users[b].displayName||users[b].author||users[b].username||'').toLowerCase();return na.localeCompare(nb);});
|
|
496
|
+
var roleIds=Object.keys(roles).filter(function(x){return /^\\d+$/.test(x);});
|
|
497
|
+
|
|
346
498
|
function esc(s){return String(s==null?'':s).replace(/[&<>"']/g,function(c){return ({'&':'&','<':'<','>':'>','"':'"',"'":'''})[c];});}
|
|
347
499
|
function safeColor(c,fb){fb=fb||'#dbdee1';return typeof c==='string' && /^#[0-9a-fA-F]{3,8}$/.test(c) ? c : fb;}
|
|
348
500
|
function safeUrl(u){if(typeof u!=='string'||!u)return '';if(/^https?:\\/\\//i.test(u))return u;return '';}
|
|
349
501
|
function firstMessageOf(uid){var m=document.querySelector('discord-message[profile="'+uid+'"],[data-profile="'+uid+'"]');return m?m.id:null;}
|
|
502
|
+
function parseId(v){if(!v)return null;var t=v.trim();if(/^\\d{15,21}$/.test(t))return t;var m=t.match(/\\((\\d{15,21})\\)/);return m?m[1]:null;}
|
|
503
|
+
function authorHasRole(authorId,roleId){var u=users[authorId];if(!u||!Array.isArray(u.roles))return false;for(var i=0;i<u.roles.length;i++){if(u.roles[i].id===roleId)return true;}return false;}
|
|
504
|
+
|
|
350
505
|
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);
|
|
506
|
+
|
|
351
507
|
var panel=document.createElement('aside');panel.className='dht-toc';panel.setAttribute('aria-hidden','true');
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
508
|
+
|
|
509
|
+
// Header
|
|
510
|
+
var headerHtml='<header><h3>'+esc(dict.tocTitle||'Participants')+'</h3><button class="dht-toc-close" type="button" aria-label="Close">×</button></header>';
|
|
511
|
+
// Search field — keyword highlight + participant name filter
|
|
512
|
+
var searchHtml='<div class="dht-toc-search-wrap"><span class="dht-toc-search-icon" aria-hidden="true"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg></span><input type="search" class="dht-toc-search" placeholder="'+esc(dict.searchPlaceholder||'Search…')+'"><span class="dht-toc-counter" aria-live="polite"></span><button class="dht-toc-srch-btn" type="button" data-act="prev" title="Previous" aria-label="Previous match">▲</button><button class="dht-toc-srch-btn" type="button" data-act="next" title="Next" aria-label="Next match">▼</button></div>';
|
|
513
|
+
// Participants list — collapsible, open by default
|
|
514
|
+
var listHtml='<details class="dht-toc-section" open><summary>'+esc(dict.tocTitle||'Participants')+'</summary><ul class="dht-toc-list" role="list">';
|
|
515
|
+
if(userIds.length>0){
|
|
516
|
+
userIds.forEach(function(id){
|
|
517
|
+
var u=users[id];var name=u.displayName||u.author||u.username||'Unknown';var avatar=safeUrl(u.avatar||'');var color=safeColor(u.bannerColor||u.roleColor,'#dbdee1');
|
|
518
|
+
listHtml+='<li data-uid="'+esc(id)+'" data-name="'+esc(String(name).toLowerCase())+'" tabindex="0" role="button">'+(avatar?'<img src="'+esc(avatar)+'" alt="" loading="lazy">':'<span class="dht-toc-ph"></span>')+'<span class="dht-toc-name" style="color:'+color+'">'+esc(name)+'</span></li>';
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
listHtml+='</ul></details>';
|
|
522
|
+
// Filter form — replaces the standalone bottom-right magnifying glass. Open by default.
|
|
523
|
+
var filterHtml='<details class="dht-toc-section dht-toc-filter-details" open><summary>'+esc(dict.filterPanel||'Filter')+'</summary><div class="dht-toc-filter-body">';
|
|
524
|
+
filterHtml+='<label class="dht-f-field">'+esc(dict.filterAuthor||'Author')+'<input list="dht-f-authors" class="dht-f-author" placeholder="@user / ID / name"></label>';
|
|
525
|
+
filterHtml+='<datalist id="dht-f-authors">'+userIds.map(function(id){var u=users[id];return '<option value="'+esc(u.displayName||u.author||u.username||'')+' ('+esc(id)+')">';}).join('')+'</datalist>';
|
|
526
|
+
filterHtml+='<label class="dht-f-field">'+esc(dict.filterRole||'Role')+'<input list="dht-f-roles" class="dht-f-role" placeholder="@role / ID / name"></label>';
|
|
527
|
+
filterHtml+='<datalist id="dht-f-roles">'+roleIds.map(function(id){var r=roles[id];return '<option value="'+esc(r.name||'')+' ('+esc(id)+')">';}).join('')+'</datalist>';
|
|
528
|
+
filterHtml+='<div class="dht-f-grid"><label class="dht-f-field">'+esc(dict.filterFrom||'From')+'<input type="datetime-local" class="dht-f-from"></label><label class="dht-f-field">'+esc(dict.filterTo||'To')+'<input type="datetime-local" class="dht-f-to"></label></div>';
|
|
529
|
+
filterHtml+='<div class="dht-f-checks">';
|
|
530
|
+
filterHtml+='<label><input type="checkbox" class="dht-f-pinned"> '+esc(dict.filterPinned||'Pinned only')+'</label>';
|
|
531
|
+
filterHtml+='<label><input type="checkbox" class="dht-f-image"> '+esc(dict.filterHasImage||'Has image')+'</label>';
|
|
532
|
+
filterHtml+='<label><input type="checkbox" class="dht-f-embed"> '+esc(dict.filterHasEmbed||'Has embed')+'</label>';
|
|
533
|
+
filterHtml+='<label><input type="checkbox" class="dht-f-attach"> '+esc(dict.filterHasAttachment||'Has attachment')+'</label>';
|
|
534
|
+
filterHtml+='<label><input type="checkbox" class="dht-f-v2"> '+esc(dict.filterHasComponentV2||'Has container')+'</label>';
|
|
535
|
+
filterHtml+='</div>';
|
|
536
|
+
filterHtml+='<div class="dht-f-actions"><button type="button" class="dht-f-apply">'+esc(dict.filterApply||'Apply')+'</button><button type="button" class="dht-f-reset">'+esc(dict.filterReset||'Reset')+'</button></div>';
|
|
537
|
+
filterHtml+='</div></details>';
|
|
538
|
+
|
|
539
|
+
panel.innerHTML=headerHtml+searchHtml+listHtml+filterHtml;document.body.appendChild(panel);
|
|
540
|
+
|
|
355
541
|
function syncToggleVisibility(open){btn.style.opacity=open?'0':'1';btn.style.pointerEvents=open?'none':'auto';btn.setAttribute('aria-expanded',open?'true':'false');}
|
|
356
|
-
|
|
357
|
-
|
|
542
|
+
function openPanel(){panel.classList.add('dht-toc--open');panel.setAttribute('aria-hidden','false');syncToggleVisibility(true);}
|
|
543
|
+
function closePanel(){panel.classList.remove('dht-toc--open');panel.setAttribute('aria-hidden','true');syncToggleVisibility(false);}
|
|
544
|
+
btn.addEventListener('click',function(){if(panel.classList.contains('dht-toc--open'))closePanel();else openPanel();});
|
|
545
|
+
panel.querySelector('.dht-toc-close').addEventListener('click',closePanel);
|
|
546
|
+
|
|
358
547
|
function activate(li){var uid=li.getAttribute('data-uid');if(!uid||!/^\\d+$/.test(uid))return;var mid=firstMessageOf(uid);if(mid){var el=document.getElementById(mid);if(el){el.scrollIntoView({behavior:'smooth',block:'center'});var prev=el.style.backgroundColor;el.style.backgroundColor='rgba(148,156,247,0.18)';setTimeout(function(){el.style.backgroundColor=prev||'transparent';},1500);}}}
|
|
359
|
-
panel.querySelectorAll('li').forEach(function(li){li.addEventListener('click',function(){activate(li);});li.addEventListener('keydown',function(e){if(e.key==='Enter'||e.key===' '){e.preventDefault();activate(li);}});});
|
|
548
|
+
panel.querySelectorAll('.dht-toc-list li').forEach(function(li){li.addEventListener('click',function(){activate(li);});li.addEventListener('keydown',function(e){if(e.key==='Enter'||e.key===' '){e.preventDefault();activate(li);}});});
|
|
549
|
+
|
|
550
|
+
// Keyword highlight + participant filter (driven by the top search input)
|
|
551
|
+
var input=panel.querySelector('.dht-toc-search');
|
|
552
|
+
var counter=panel.querySelector('.dht-toc-counter');
|
|
553
|
+
var matches=[],idx=-1;
|
|
554
|
+
function clearMatches(){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='';}
|
|
555
|
+
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-toc')||node.classList.contains('dht-popup')||node.tagName==='SCRIPT'||node.tagName==='STYLE'))return;for(var i=node.childNodes.length-1;i>=0;i--)walk(node.childNodes[i],re,acc);}}
|
|
556
|
+
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;}}
|
|
557
|
+
function applySearch(q){
|
|
558
|
+
clearMatches();
|
|
559
|
+
var lowerQ=(q||'').trim().toLowerCase();
|
|
560
|
+
panel.querySelectorAll('.dht-toc-list li').forEach(function(li){var n=li.getAttribute('data-name')||'';li.style.display=(!lowerQ||n.indexOf(lowerQ)!==-1)?'':'none';});
|
|
561
|
+
if(!lowerQ||lowerQ.length<2){counter.textContent='';return;}
|
|
562
|
+
var re=new RegExp(lowerQ.replace(/[.*+?^\${}()|[\\]\\\\]/g,function(c){return '\\\\'+c;}),'gi');
|
|
563
|
+
walk(document.body,re,matches);
|
|
564
|
+
if(matches.length){idx=0;goTo();}else{counter.textContent=dict.noMatches||'no matches';}
|
|
565
|
+
}
|
|
566
|
+
input.addEventListener('input',function(){applySearch(input.value);});
|
|
567
|
+
panel.querySelectorAll('.dht-toc-srch-btn').forEach(function(b){b.addEventListener('click',function(){var act=b.getAttribute('data-act');if(!matches.length)return;if(act==='next')idx=(idx+1)%matches.length;else if(act==='prev')idx=(idx-1+matches.length)%matches.length;goTo();});});
|
|
568
|
+
input.addEventListener('keydown',function(e){if(e.key==='Enter'){if(matches.length){idx=(idx+(e.shiftKey?-1:1)+matches.length)%matches.length;goTo();}e.preventDefault();}});
|
|
569
|
+
|
|
570
|
+
// Filter form — author / role / date / has-flags. Replaces the old standalone .dht-filter aside.
|
|
571
|
+
function applyFilter(){
|
|
572
|
+
var authorIdRaw=parseId(panel.querySelector('.dht-f-author').value);
|
|
573
|
+
var authorTextRaw=(panel.querySelector('.dht-f-author').value||'').trim().toLowerCase();
|
|
574
|
+
var roleIdRaw=parseId(panel.querySelector('.dht-f-role').value);
|
|
575
|
+
var roleTextRaw=(panel.querySelector('.dht-f-role').value||'').trim().toLowerCase();
|
|
576
|
+
var fromVal=panel.querySelector('.dht-f-from').value;
|
|
577
|
+
var toVal=panel.querySelector('.dht-f-to').value;
|
|
578
|
+
var fromMs=fromVal?new Date(fromVal).getTime():null;
|
|
579
|
+
var toMs=toVal?new Date(toVal).getTime():null;
|
|
580
|
+
var needPinned=panel.querySelector('.dht-f-pinned').checked;
|
|
581
|
+
var needImage=panel.querySelector('.dht-f-image').checked;
|
|
582
|
+
var needEmbed=panel.querySelector('.dht-f-embed').checked;
|
|
583
|
+
var needAttach=panel.querySelector('.dht-f-attach').checked;
|
|
584
|
+
var needV2=panel.querySelector('.dht-f-v2').checked;
|
|
585
|
+
var matchedRoleId=null;
|
|
586
|
+
if(roleIdRaw){matchedRoleId=roleIdRaw;}
|
|
587
|
+
else if(roleTextRaw){var exact=null,sub=null;for(var rid in roles){if(Object.prototype.hasOwnProperty.call(roles,rid)){var rn=(roles[rid].name||'').toLowerCase();if(rn===roleTextRaw){exact=rid;break;}else if(!sub && rn.indexOf(roleTextRaw)!==-1){sub=rid;}}}matchedRoleId=exact||sub;}
|
|
588
|
+
var matchedAuthorId=authorIdRaw||null;
|
|
589
|
+
var msgs=document.querySelectorAll('discord-message, discord-system-message');
|
|
590
|
+
for(var i=0;i<msgs.length;i++){
|
|
591
|
+
var m=msgs[i];var ok=true;
|
|
592
|
+
var authorId=m.getAttribute('data-author-id')||'';
|
|
593
|
+
var authorName=(m.getAttribute('data-author-name')||'').toLowerCase();
|
|
594
|
+
var rolesAttr=m.getAttribute('data-roles')||'';
|
|
595
|
+
var tsStr=m.getAttribute('data-timestamp');
|
|
596
|
+
var ts=tsStr?parseInt(tsStr,10):0;
|
|
597
|
+
var pinned=m.getAttribute('data-pinned')==='true';
|
|
598
|
+
var hasImg=m.getAttribute('data-has-image')==='true';
|
|
599
|
+
var hasEmb=m.getAttribute('data-has-embed')==='true';
|
|
600
|
+
var hasAtt=m.getAttribute('data-has-attachment')==='true';
|
|
601
|
+
var hasV2=m.getAttribute('data-has-component-v2')==='true';
|
|
602
|
+
if(matchedAuthorId && authorId!==matchedAuthorId)ok=false;
|
|
603
|
+
if(ok && !matchedAuthorId && !authorIdRaw && authorTextRaw && authorName.indexOf(authorTextRaw)===-1)ok=false;
|
|
604
|
+
if(ok && matchedRoleId){var rIds=rolesAttr.split(',');if(rIds.indexOf(matchedRoleId)===-1 && !authorHasRole(authorId,matchedRoleId))ok=false;}
|
|
605
|
+
if(ok && fromMs){if(!ts || ts<fromMs)ok=false;}
|
|
606
|
+
if(ok && toMs){if(!ts || ts>toMs)ok=false;}
|
|
607
|
+
if(ok && needPinned && !pinned)ok=false;
|
|
608
|
+
if(ok && needImage && !hasImg)ok=false;
|
|
609
|
+
if(ok && needEmbed && !hasEmb)ok=false;
|
|
610
|
+
if(ok && needAttach && !hasAtt)ok=false;
|
|
611
|
+
if(ok && needV2 && !hasV2)ok=false;
|
|
612
|
+
m.style.display=ok?'':'none';
|
|
613
|
+
}
|
|
614
|
+
var seps=document.querySelectorAll('.dht-date-sep');
|
|
615
|
+
for(var s=0;s<seps.length;s++){var sep=seps[s];var next=sep.nextElementSibling;var hasVis=false;while(next && !next.classList.contains('dht-date-sep')){if(next.style.display!=='none' && (next.tagName==='DISCORD-MESSAGE' || next.tagName==='DISCORD-SYSTEM-MESSAGE')){hasVis=true;break;}next=next.nextElementSibling;}sep.style.display=hasVis?'':'none';}
|
|
616
|
+
}
|
|
617
|
+
function resetFilter(){panel.querySelectorAll('.dht-toc-filter-body input').forEach(function(i){if(i.type==='checkbox')i.checked=false;else i.value='';});document.querySelectorAll('discord-message, discord-system-message, .dht-date-sep').forEach(function(m){m.style.display='';});}
|
|
618
|
+
panel.querySelector('.dht-f-apply').addEventListener('click',applyFilter);
|
|
619
|
+
panel.querySelector('.dht-f-reset').addEventListener('click',resetFilter);
|
|
620
|
+
panel.querySelector('.dht-toc-filter-body').addEventListener('keydown',function(e){if(e.key==='Enter'){e.preventDefault();applyFilter();}});
|
|
621
|
+
try{globalThis.__DHT_FLAG_BADGES__=${JSON.stringify(FLAG_BADGES)};}catch(_){}
|
|
622
|
+
|
|
623
|
+
// Ctrl+F / Cmd+F opens the panel and focuses the search input
|
|
624
|
+
document.addEventListener('keydown',function(e){
|
|
625
|
+
if((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()==='f'){
|
|
626
|
+
e.preventDefault();openPanel();setTimeout(function(){input.focus();input.select();},20);
|
|
627
|
+
}else if(e.key==='Escape'&&panel.classList.contains('dht-toc--open')){
|
|
628
|
+
if(document.activeElement===input&&input.value){input.value='';applySearch('');}
|
|
629
|
+
else closePanel();
|
|
630
|
+
}
|
|
631
|
+
});
|
|
360
632
|
})();`;
|
|
361
|
-
exports.tocStyles = `.dht-toc-toggle{position:fixed;top:16px;
|
|
633
|
+
exports.tocStyles = `.dht-toc-toggle{position:fixed;top:16px;right: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}
|
|
634
|
+
.dht-toc{position:fixed;top:0;right:-340px;left:auto;width:320px;height:100vh;background:#1e1f22;border-left:1px solid #2b2d31;transition:right .25s ease;z-index:9997;overflow-y:auto;font-family:"gg sans",sans-serif;color:#dbdee1;padding:16px;box-sizing:border-box}
|
|
635
|
+
.dht-toc--open{right:0}
|
|
636
|
+
.dht-toc header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid #2b2d31}
|
|
637
|
+
.dht-toc h3{margin:0;font-size:14px;text-transform:uppercase;letter-spacing:.04em;color:#949ba4}
|
|
638
|
+
.dht-toc-close{background:none;border:none;color:#949ba4;cursor:pointer;font-size:22px;line-height:1}
|
|
639
|
+
.dht-toc-search-wrap{display:flex;align-items:center;gap:6px;margin-bottom:14px;background:#2b2d31;border:1px solid #2b2d31;border-radius:6px;padding:4px 8px;transition:border-color .15s ease}
|
|
640
|
+
.dht-toc-search-wrap:focus-within{border-color:#5865F2}
|
|
641
|
+
.dht-toc-search-icon{color:#949ba4;display:inline-flex;align-items:center;flex:none}
|
|
642
|
+
.dht-toc-search{flex:1;min-width:0;background:transparent;color:#dbdee1;border:none;font-size:13px;outline:none;font-family:inherit;padding:4px 0}
|
|
643
|
+
.dht-toc-counter{font-size:11px;color:#949ba4;min-width:46px;text-align:right;white-space:nowrap}
|
|
644
|
+
.dht-toc-srch-btn{background:none;border:none;color:#dbdee1;cursor:pointer;padding:2px 4px;border-radius:3px;font-size:11px;line-height:1;flex:none}
|
|
645
|
+
.dht-toc-srch-btn:hover{background:rgba(255,255,255,.06)}
|
|
646
|
+
.dht-toc-section-label{font-size:11px;color:#949ba4;text-transform:uppercase;letter-spacing:.04em;font-weight:700;margin:0 0 6px}
|
|
647
|
+
.dht-toc-list{list-style:none;padding:0;margin:0}
|
|
648
|
+
.dht-toc-list li{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:4px;cursor:pointer;font-size:14px}
|
|
649
|
+
.dht-toc-list li:hover{background:rgba(255,255,255,.04)}
|
|
650
|
+
.dht-toc-list li img,.dht-toc-ph{width:28px;height:28px;border-radius:50%;flex:none}
|
|
651
|
+
.dht-toc-ph{background:#313338}
|
|
652
|
+
.dht-toc-name{flex:1;font-weight:500;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
653
|
+
@media (max-width:640px){.dht-toc{width:85vw;right:-85vw}.dht-toc--open{right:0}.dht-toc-toggle{top:12px;right:12px}}`;
|
|
362
654
|
|
|
363
655
|
// ===========================================================================
|
|
364
656
|
// Language switcher
|
|
@@ -473,9 +765,14 @@ exports.markdownStyles = `
|
|
|
473
765
|
/* Body fallback when web components fail to load from CDN */
|
|
474
766
|
body{background:#313338;color:#dbdee1;font-family:"gg sans","Helvetica Neue",Helvetica,Arial,sans-serif}
|
|
475
767
|
discord-messages{background:#313338;display:block}
|
|
476
|
-
/* CRITICAL: ensure message hosts are block-level. Without this, two
|
|
477
|
-
messages collapse onto the same line in some browser states.
|
|
478
|
-
|
|
768
|
+
/* CRITICAL: ensure regular message hosts are block-level. Without this, two
|
|
769
|
+
consecutive messages collapse onto the same line in some browser states.
|
|
770
|
+
discord-system-message is intentionally NOT forced to block — skyra's
|
|
771
|
+
shadow DOM uses display:grid to lay out icon / content / timestamp; if we
|
|
772
|
+
override it, the pin icon ends up floating to the far right instead of
|
|
773
|
+
sitting to the left of the author. */
|
|
774
|
+
discord-message{display:block;position:relative}
|
|
775
|
+
discord-system-message{position:relative}
|
|
479
776
|
/* Fallback layout when @skyra Web Components fail to register (offline viewer). */
|
|
480
777
|
discord-message:not(:defined),discord-system-message:not(:defined){padding:6px 16px 6px 16px;min-height:32px;color:#dbdee1;font-size:14px;border-top:1px solid rgba(255,255,255,0.04);margin-top:0}
|
|
481
778
|
discord-message:not(:defined)::before{content:attr(profile);display:block;font-weight:600;color:#fff;font-size:13px;margin-bottom:2px;opacity:.7}
|
|
@@ -548,124 +845,21 @@ exports.markdownStyles = `
|
|
|
548
845
|
// Advanced filter panel — keyword + author + role + date range + has-image/embed/attachment + pinned-only
|
|
549
846
|
// Hides non-matching messages, respects date separators
|
|
550
847
|
// ===========================================================================
|
|
551
|
-
exports.filterPanel =
|
|
552
|
-
var DATA=globalThis.$discordMessage||{};
|
|
553
|
-
var dict=(DATA.i18n&&(DATA.i18n[DATA.lang]||DATA.i18n.en))||{};
|
|
554
|
-
var users=DATA.users||DATA.profiles||{};
|
|
555
|
-
var roles=DATA.roles||{};
|
|
556
|
-
function esc(s){return String(s==null?'':s).replace(/[&<>"']/g,function(c){return ({'&':'&','<':'<','>':'>','"':'"',"'":'''})[c];});}
|
|
557
|
-
function parseId(v){if(!v)return null;var t=v.trim();if(/^\\d{15,21}$/.test(t))return t;var m=t.match(/\\((\\d{15,21})\\)/);return m?m[1]:null;}
|
|
558
|
-
function authorHasRole(authorId,roleId){var u=users[authorId];if(!u||!Array.isArray(u.roles))return false;for(var i=0;i<u.roles.length;i++){if(u.roles[i].id===roleId)return true;}return false;}
|
|
559
|
-
var btn=document.createElement('button');btn.className='dht-filter-toggle';btn.type='button';btn.title=dict.filterPanel||'Filter';btn.setAttribute('aria-label',dict.filterPanel||'Filter');btn.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg>';document.body.appendChild(btn);
|
|
560
|
-
var panel=document.createElement('aside');panel.className='dht-filter';panel.setAttribute('aria-hidden','true');panel.setAttribute('role','region');
|
|
561
|
-
var userIds=Object.keys(users).filter(function(x){return /^\\d+$/.test(x);}).sort(function(a,b){var na=(users[a].displayName||users[a].author||'').toLowerCase();var nb=(users[b].displayName||users[b].author||'').toLowerCase();return na.localeCompare(nb);});
|
|
562
|
-
var roleIds=Object.keys(roles).filter(function(x){return /^\\d+$/.test(x);});
|
|
563
|
-
var html='<header><h3>'+esc(dict.filterPanel||'Filter')+'</h3><button class="dht-filter-close" type="button" aria-label="Close">×</button></header><div class="dht-filter-body">';
|
|
564
|
-
html+='<label class="dht-f-field">'+esc(dict.filterKeyword||'Keyword')+'<input type="search" class="dht-f-keyword" placeholder="'+esc(dict.searchPlaceholder||'Search…')+'"></label>';
|
|
565
|
-
html+='<label class="dht-f-field">'+esc(dict.filterAuthor||'Author')+'<input list="dht-f-authors" class="dht-f-author" placeholder="@user / ID / name"></label>';
|
|
566
|
-
html+='<datalist id="dht-f-authors">'+userIds.map(function(id){var u=users[id];return '<option value="'+esc(u.displayName||u.author||u.username||'')+' ('+esc(id)+')">';}).join('')+'</datalist>';
|
|
567
|
-
html+='<label class="dht-f-field">'+esc(dict.filterRole||'Role')+'<input list="dht-f-roles" class="dht-f-role" placeholder="@role / ID / name"></label>';
|
|
568
|
-
html+='<datalist id="dht-f-roles">'+roleIds.map(function(id){var r=roles[id];return '<option value="'+esc(r.name||'')+' ('+esc(id)+')">';}).join('')+'</datalist>';
|
|
569
|
-
html+='<div class="dht-f-grid"><label class="dht-f-field">'+esc(dict.filterFrom||'From')+'<input type="datetime-local" class="dht-f-from"></label><label class="dht-f-field">'+esc(dict.filterTo||'To')+'<input type="datetime-local" class="dht-f-to"></label></div>';
|
|
570
|
-
html+='<div class="dht-f-checks">';
|
|
571
|
-
html+='<label><input type="checkbox" class="dht-f-pinned"> '+esc(dict.filterPinned||'Pinned only')+'</label>';
|
|
572
|
-
html+='<label><input type="checkbox" class="dht-f-image"> '+esc(dict.filterHasImage||'Has image')+'</label>';
|
|
573
|
-
html+='<label><input type="checkbox" class="dht-f-embed"> '+esc(dict.filterHasEmbed||'Has embed')+'</label>';
|
|
574
|
-
html+='<label><input type="checkbox" class="dht-f-attach"> '+esc(dict.filterHasAttachment||'Has attachment')+'</label>';
|
|
575
|
-
html+='</div>';
|
|
576
|
-
html+='<div class="dht-f-actions"><button type="button" class="dht-f-apply">'+esc(dict.filterApply||'Apply')+'</button><button type="button" class="dht-f-reset">'+esc(dict.filterReset||'Reset')+'</button></div>';
|
|
577
|
-
html+='<div class="dht-f-counter" aria-live="polite"></div>';
|
|
578
|
-
html+='</div>';
|
|
579
|
-
panel.innerHTML=html;document.body.appendChild(panel);
|
|
580
|
-
function close(){panel.classList.remove('dht-filter--open');panel.setAttribute('aria-hidden','true');}
|
|
581
|
-
function open(){panel.classList.add('dht-filter--open');panel.setAttribute('aria-hidden','false');var k=panel.querySelector('.dht-f-keyword');if(k)k.focus();}
|
|
582
|
-
btn.addEventListener('click',open);
|
|
583
|
-
panel.querySelector('.dht-filter-close').addEventListener('click',close);
|
|
584
|
-
function apply(){
|
|
585
|
-
var keyword=(panel.querySelector('.dht-f-keyword').value||'').trim().toLowerCase();
|
|
586
|
-
var authorIdRaw=parseId(panel.querySelector('.dht-f-author').value);
|
|
587
|
-
var authorTextRaw=(panel.querySelector('.dht-f-author').value||'').trim().toLowerCase();
|
|
588
|
-
var roleIdRaw=parseId(panel.querySelector('.dht-f-role').value);
|
|
589
|
-
var roleTextRaw=(panel.querySelector('.dht-f-role').value||'').trim().toLowerCase();
|
|
590
|
-
var fromVal=panel.querySelector('.dht-f-from').value;
|
|
591
|
-
var toVal=panel.querySelector('.dht-f-to').value;
|
|
592
|
-
var fromMs=fromVal?new Date(fromVal).getTime():null;
|
|
593
|
-
var toMs=toVal?new Date(toVal).getTime():null;
|
|
594
|
-
var needPinned=panel.querySelector('.dht-f-pinned').checked;
|
|
595
|
-
var needImage=panel.querySelector('.dht-f-image').checked;
|
|
596
|
-
var needEmbed=panel.querySelector('.dht-f-embed').checked;
|
|
597
|
-
var needAttach=panel.querySelector('.dht-f-attach').checked;
|
|
598
|
-
var matchedRoleId=null;
|
|
599
|
-
if(roleIdRaw){matchedRoleId=roleIdRaw;}
|
|
600
|
-
else if(roleTextRaw){
|
|
601
|
-
// exact-match wins over substring
|
|
602
|
-
var exact=null,sub=null;
|
|
603
|
-
for(var rid in roles){if(Object.prototype.hasOwnProperty.call(roles,rid)){var rn=(roles[rid].name||'').toLowerCase();if(rn===roleTextRaw){exact=rid;break;}else if(!sub && rn.indexOf(roleTextRaw)!==-1){sub=rid;}}}
|
|
604
|
-
matchedRoleId=exact||sub;
|
|
605
|
-
}
|
|
606
|
-
var matchedAuthorId=null;
|
|
607
|
-
if(authorIdRaw){matchedAuthorId=authorIdRaw;}
|
|
608
|
-
var msgs=document.querySelectorAll('discord-message, discord-system-message');
|
|
609
|
-
var visible=0;
|
|
610
|
-
for(var i=0;i<msgs.length;i++){
|
|
611
|
-
var m=msgs[i];
|
|
612
|
-
var ok=true;
|
|
613
|
-
var text=(m.getAttribute('data-text')||'').toLowerCase();
|
|
614
|
-
var authorId=m.getAttribute('data-author-id')||'';
|
|
615
|
-
var authorName=(m.getAttribute('data-author-name')||'').toLowerCase();
|
|
616
|
-
var rolesAttr=m.getAttribute('data-roles')||'';
|
|
617
|
-
var tsStr=m.getAttribute('data-timestamp');
|
|
618
|
-
var ts=tsStr?parseInt(tsStr,10):0;
|
|
619
|
-
var pinned=m.getAttribute('data-pinned')==='true';
|
|
620
|
-
var hasImg=m.getAttribute('data-has-image')==='true';
|
|
621
|
-
var hasEmb=m.getAttribute('data-has-embed')==='true';
|
|
622
|
-
var hasAtt=m.getAttribute('data-has-attachment')==='true';
|
|
623
|
-
if(keyword && text.indexOf(keyword)===-1 && authorName.indexOf(keyword)===-1)ok=false;
|
|
624
|
-
if(ok && matchedAuthorId && authorId!==matchedAuthorId)ok=false;
|
|
625
|
-
if(ok && !matchedAuthorId && !authorIdRaw && authorTextRaw && authorName.indexOf(authorTextRaw)===-1)ok=false;
|
|
626
|
-
if(ok && matchedRoleId){var rIds=rolesAttr.split(',');if(rIds.indexOf(matchedRoleId)===-1 && !authorHasRole(authorId,matchedRoleId))ok=false;}
|
|
627
|
-
// If date filter active but message has no timestamp, exclude it (safer than always-passing).
|
|
628
|
-
if(ok && fromMs){if(!ts || ts<fromMs)ok=false;}
|
|
629
|
-
if(ok && toMs){if(!ts || ts>toMs)ok=false;}
|
|
630
|
-
if(ok && needPinned && !pinned)ok=false;
|
|
631
|
-
if(ok && needImage && !hasImg)ok=false;
|
|
632
|
-
if(ok && needEmbed && !hasEmb)ok=false;
|
|
633
|
-
if(ok && needAttach && !hasAtt)ok=false;
|
|
634
|
-
m.style.display=ok?'':'none';
|
|
635
|
-
if(ok)visible++;
|
|
636
|
-
}
|
|
637
|
-
var seps=document.querySelectorAll('.dht-date-sep');
|
|
638
|
-
for(var s=0;s<seps.length;s++){
|
|
639
|
-
var sep=seps[s];var next=sep.nextElementSibling;var hasVis=false;
|
|
640
|
-
while(next && !next.classList.contains('dht-date-sep')){
|
|
641
|
-
if(next.style.display!=='none' && (next.tagName==='DISCORD-MESSAGE' || next.tagName==='DISCORD-SYSTEM-MESSAGE')){hasVis=true;break;}
|
|
642
|
-
next=next.nextElementSibling;
|
|
643
|
-
}
|
|
644
|
-
sep.style.display=hasVis?'':'none';
|
|
645
|
-
}
|
|
646
|
-
panel.querySelector('.dht-f-counter').textContent=(dict.filterShowing||'Showing {visible} of {total}').replace('{visible}',visible).replace('{total}',msgs.length);
|
|
647
|
-
}
|
|
648
|
-
function reset(){
|
|
649
|
-
panel.querySelectorAll('input').forEach(function(i){if(i.type==='checkbox')i.checked=false;else i.value='';});
|
|
650
|
-
document.querySelectorAll('discord-message, discord-system-message, .dht-date-sep').forEach(function(m){m.style.display='';});
|
|
651
|
-
panel.querySelector('.dht-f-counter').textContent='';
|
|
652
|
-
}
|
|
653
|
-
panel.querySelector('.dht-f-apply').addEventListener('click',apply);
|
|
654
|
-
panel.querySelector('.dht-f-reset').addEventListener('click',reset);
|
|
655
|
-
panel.addEventListener('keydown',function(e){if(e.key==='Enter'){e.preventDefault();apply();}else if(e.key==='Escape'){close();}});
|
|
656
|
-
// Bind flag badges dict for popup access
|
|
657
|
-
try{globalThis.__DHT_FLAG_BADGES__=${JSON.stringify(FLAG_BADGES)};}catch(_){}
|
|
658
|
-
})();`;
|
|
848
|
+
exports.filterPanel = '/* filterPanel merged into TOC; see exports.toc */';
|
|
659
849
|
|
|
660
850
|
exports.filterPanelStyles = `
|
|
661
|
-
|
|
662
|
-
.dht-filter-toggle
|
|
663
|
-
.dht-filter
|
|
664
|
-
|
|
665
|
-
.dht-
|
|
666
|
-
.dht-
|
|
667
|
-
.dht-
|
|
668
|
-
.dht-
|
|
851
|
+
/* Filter form lives inside the TOC panel — only the form-field styles remain.
|
|
852
|
+
The old floating .dht-filter-toggle (magnifying-glass button) and standalone
|
|
853
|
+
.dht-filter aside are gone. */
|
|
854
|
+
/* Collapsible sections inside the TOC (participants + filter) */
|
|
855
|
+
.dht-toc-section{margin-top:12px;border-top:1px solid #2b2d31;padding-top:10px}
|
|
856
|
+
.dht-toc-section:first-of-type{margin-top:0;border-top:none;padding-top:0}
|
|
857
|
+
.dht-toc-section>summary{cursor:pointer;font-size:11px;color:#949ba4;text-transform:uppercase;letter-spacing:.04em;font-weight:700;padding:4px 0;list-style:none;display:flex;align-items:center;justify-content:space-between}
|
|
858
|
+
.dht-toc-section>summary::-webkit-details-marker{display:none}
|
|
859
|
+
.dht-toc-section>summary::after{content:'\\25BC';font-size:9px;color:#6e727a;transition:transform .15s ease}
|
|
860
|
+
.dht-toc-section[open]>summary::after{transform:rotate(180deg)}
|
|
861
|
+
.dht-toc-section>summary:hover{color:#dbdee1}
|
|
862
|
+
.dht-toc-filter-body{display:flex;flex-direction:column;gap:10px;margin-top:8px}
|
|
669
863
|
.dht-f-field{display:flex;flex-direction:column;gap:4px;font-size:11px;color:#b5bac1;text-transform:uppercase;letter-spacing:.04em;font-weight:600}
|
|
670
864
|
.dht-f-field input{background:#2b2d31;color:#dbdee1;border:1px solid #2b2d31;border-radius:4px;padding:6px 8px;font-size:13px;outline:none;font-family:inherit;text-transform:none;letter-spacing:0;font-weight:400}
|
|
671
865
|
.dht-f-field input:focus{border-color:#5865F2}
|
|
@@ -676,8 +870,6 @@ exports.filterPanelStyles = `
|
|
|
676
870
|
.dht-f-actions button{flex:1;padding:8px;border:none;border-radius:4px;cursor:pointer;font-weight:600;font-size:13px}
|
|
677
871
|
.dht-f-apply{background:#5865F2;color:#fff}.dht-f-apply:hover{background:#4752c4}
|
|
678
872
|
.dht-f-reset{background:#3f4248;color:#dbdee1}.dht-f-reset:hover{background:#4a4d54}
|
|
679
|
-
.dht-f-counter{margin-top:8px;font-size:12px;color:#b5bac1;text-align:center}
|
|
680
|
-
@media (max-width:640px){.dht-filter{width:85vw;right:-85vw}.dht-filter-toggle{bottom:70px;right:16px;width:40px;height:40px}}
|
|
681
873
|
.dht-flag{display:inline-flex;align-items:center;background:rgba(255,255,255,.06);border-radius:4px;padding:2px 6px;font-size:12px;margin:2px 2px 0 0}
|
|
682
874
|
.dht-popup-flags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
683
875
|
/* Pinned background — Discord-style amber tint */
|