This commit is contained in:
2026-09-11 23:07:03 +02:00
parent 802a59d090
commit 4b615428de
14 changed files with 243 additions and 174 deletions
+28 -17
View File
@@ -100,27 +100,27 @@
// ── Grid / Thumbnail size ─────────────────────────────────────────────────
const THUMB_SIZES = ['s', 'm', 'l', 'xl'];
let thumbSize = localStorage.getItem(THUMB_SIZE_KEY) || 'm';
if (!THUMB_SIZES.includes(thumbSize)) thumbSize = 'm';
let thumbSize = localStorage.getItem(THUMB_SIZE_KEY) || window.f0ckDefaultThumbSize || 'm';
if (!THUMB_SIZES.includes(thumbSize)) thumbSize = window.f0ckDefaultThumbSize || 'm';
function applyThumbSize(size) {
function applyThumbSize(size, persist = true) {
thumbSize = size;
document.documentElement.dataset.thumbSize = size;
localStorage.setItem(THUMB_SIZE_KEY, size);
if (persist) localStorage.setItem(THUMB_SIZE_KEY, size);
// Sync pill active state whenever called outside the click handler
document.querySelectorAll('#thumb-size-pills .filter-pill').forEach(p =>
p.classList.toggle('active', p.dataset.thumbSize === size)
);
}
// Apply persisted size on load
applyThumbSize(thumbSize);
// Apply on init — do NOT persist so config default stays effective until user chooses
applyThumbSize(thumbSize, false);
// Wire pill click events
const thumbSizePillsEl = document.getElementById('thumb-size-pills');
if (thumbSizePillsEl) {
thumbSizePillsEl.querySelectorAll('.filter-pill').forEach(pill => {
pill.addEventListener('click', () => {
applyThumbSize(pill.dataset.thumbSize);
applyThumbSize(pill.dataset.thumbSize, true);
});
});
}
@@ -1373,7 +1373,8 @@
const meta = document.createElement('div'); meta.className = 'scroll-meta';
// esc() the color value: a raw '"' in username_color would break out of the
// style attribute and allow arbitrary HTML injection (XSS).
const colorStyle = item.username_color ? `color:${esc(item.username_color)}` : '';
const isAnonGuest = window.f0ckSession?.guest_anonymize && !window.f0ckSession?.logged_in;
const colorStyle = (!isAnonGuest && item.username_color) ? `color:${esc(item.username_color)}` : '';
const ratingHtml = `<span class="scroll-rating ${esc(item.rating_class)}" data-item-id="${item.id}" data-rating="${esc(item.rating_class)}">${esc(item.rating_label)}</span>`;
const ocHtml = item.is_oc ? `<span class="scroll-oc"><i class="fa-solid fa-star" style="font-size:.6rem"></i> OC</span>` : '';
const badgesHtml = `<div class="scroll-badges">${ratingHtml}${ocHtml}</div>`;
@@ -1383,10 +1384,15 @@
item.tags.split(', ').map(t => `<span class="scroll-tag-pill" data-tag="${esc(t.trim())}">${esc(t.trim())}</span>`).join('')
}</div>`
: '';
meta.innerHTML = `
<div class="scroll-meta-inner">
${badgesHtml}
<div class="scroll-meta-top">
const userMetaHtml = isAnonGuest
? `<div class="scroll-meta-top">
<img class="scroll-avatar" src="/a/default.png" alt="" loading="lazy">
<div>
<div class="scroll-username">anonymous</div>
<div class="scroll-timeago">${esc(item.stamp ? timeAgo(item.stamp * 1000) : (item.timeago || ''))}</div>
</div>
</div>`
: `<div class="scroll-meta-top">
<a href="/user/${esc(item.username)}" class="scroll-user-link">
<img class="scroll-avatar" src="${esc(item.avatar)}" alt="" loading="lazy" onerror="this.src='/a/default.png'">
</a>
@@ -1396,7 +1402,11 @@
</a>
<div class="scroll-timeago">${esc(item.stamp ? timeAgo(item.stamp * 1000) : (item.timeago || ''))}</div>
</div>
</div>
</div>`;
meta.innerHTML = `
<div class="scroll-meta-inner">
${badgesHtml}
${userMetaHtml}
${tagsHtml}
${item.is_external && item.external_board && item.external_tid
? `<a class="scroll-id-link" href="https://boards.4chan.org/${item.external_board}/thread/${item.external_tid}#p${item.external_id}" target="_blank">/${item.external_board}/thread/${item.external_tid}</a>`
@@ -2187,10 +2197,11 @@
function renderCommentEl(c, canReply) {
const el = document.createElement('div'); el.className = 'comment-item';
el.dataset.commentId = c.id || '';
const av = c.avatar_file ? `/a/${c.avatar_file}` : (c.avatar ? `/t/${c.avatar}.webp` : '/a/default.png');
const nc = c.username_color ? `color:${esc(c.username_color)}` : '';
const isAnonGuest = window.f0ckSession?.guest_anonymize && !window.f0ckSession?.logged_in;
const av = isAnonGuest ? '/a/default.png' : (c.avatar_file ? `/a/${c.avatar_file}` : (c.avatar ? `/t/${c.avatar}.webp` : '/a/default.png'));
const nc = (!isAnonGuest && c.username_color) ? `color:${esc(c.username_color)}` : '';
const _i = window.f0ckI18n || {};
const uname = c.display_name || c.username || 'anon';
const uname = isAnonGuest ? 'anonymous' : (c.display_name || c.username || 'anon');
el.innerHTML = `
<img class="comment-avatar" src="${esc(av)}" alt="" loading="lazy" onerror="this.src='/a/default.png'">
<div class="comment-body">
@@ -2198,7 +2209,7 @@
<div class="comment-content" data-raw="${esc(c.content || '')}">${renderCommentContent(c.content || '')}</div>
<div class="comment-meta">
<span class="comment-time">${c.created_at ? timeAgo(c.created_at) : (_i.ta_just_now || _i.just_now || 'just now')}</span>
${canReply ? `
${(!isAnonGuest && canReply) ? `
<button class="comment-reply-btn" data-id="${c.id}" data-user="${esc(c.username || uname)}">${_i.reply || 'Reply'}</button>
<button class="comment-quote-btn" data-id="${c.id}" data-user="${esc(c.username || uname)}">${_i.quote || 'Quote'}</button>
` : ''}