diff --git a/public/s/css/f0ckm.css b/public/s/css/f0ckm.css
index f428a9a..7520697 100644
--- a/public/s/css/f0ckm.css
+++ b/public/s/css/f0ckm.css
@@ -14410,10 +14410,10 @@ body.scroller-active #gchat-reopen-bubble {
/* Filter badge style on navbar */
.filter-badge {
position: absolute;
- bottom: -13px;
- font-size: 8px;
+ bottom: -14px;
+ font-size: 9px;
font-weight: 800;
- padding: 1px 4px;
+ padding: 2px 4px;
line-height: 1;
text-transform: uppercase;
color: #fff !important;
@@ -14705,4 +14705,10 @@ body.scroller-active #gchat-reopen-bubble {
padding: 0 !important;
font-size: 11px !important;
line-height: 1 !important;
+}
+
+/* Sidebar activity thumbnails blur support (SFW/Untagged only; NSFW/NSFL use pre-blurred static images directly) */
+.blur-sfw-active .sidebar-thumb-link[data-mode="sfw"] img,
+.blur-untagged-active .sidebar-thumb-link[data-mode="untagged"] img {
+ filter: blur(8px) contrast(0.85) brightness(0.85);
}
\ No newline at end of file
diff --git a/public/s/js/sidebar-activity.js b/public/s/js/sidebar-activity.js
index f775d7b..cdee132 100644
--- a/public/s/js/sidebar-activity.js
+++ b/public/s/js/sidebar-activity.js
@@ -397,13 +397,30 @@
let itemPreview = '';
if (c.item_id) {
let mediaHtml = '';
+ const rClass = c.item_rating_class || 'untagged';
+ const blurNsfw = localStorage.getItem('blurNsfw') === 'true';
+ const blurNsfl = localStorage.getItem('blurNsfl') === 'true';
+ const blurSfw = localStorage.getItem('blurSfw') === 'true';
+ const blurUntagged = localStorage.getItem('blurUntagged') === 'true';
+
+ let isBlurred = false;
+ if (rClass === 'nsfw' && blurNsfw) isBlurred = true;
+ else if (rClass === 'nsfl' && blurNsfl) isBlurred = true;
+ else if (rClass === 'sfw' && blurSfw) isBlurred = true;
+ else if (rClass === 'untagged' && blurUntagged) isBlurred = true;
+
let thumbUrl = `/t/${c.item_id}.webp`;
+ if (isBlurred && (rClass === 'nsfw' || rClass === 'nsfl')) {
+ thumbUrl = `/t/${c.item_id}_blur.webp`;
+ }
+
if (window.applyThumbCacheBust) thumbUrl = window.applyThumbCacheBust(thumbUrl);
+
mediaHtml = `
`;
itemPreview = `
`;
}
diff --git a/src/inc/locales/de.json b/src/inc/locales/de.json
index 84da1bd..f311407 100644
--- a/src/inc/locales/de.json
+++ b/src/inc/locales/de.json
@@ -156,7 +156,7 @@
"blur_sfw": "SFW weichzeichnen",
"blur_sfw_hint": "Zeichnet SFW-Vorschaubilder weich.",
"blur_untagged": "Unmarkierte weichzeichnen",
- "blur_untagged_hint": "Zeichnet unmarkierte Vorschaubilder weich. Klicken zum Aufdecken, Klick auf das durchgestrichene Auge zum erneuten Falten.",
+ "blur_untagged_hint": "Zeichnet unmarkierte Vorschaubilder weich.",
"render_emojis": "Emojis in Zitatantworten anzeigen",
"render_emojis_hint": ":emoji:-Bilder in >zitierten Zeilen anzeigen",
"embed_yt": "YouTube-Videos in Kommentaren einbetten",
diff --git a/src/inc/locales/zange.json b/src/inc/locales/zange.json
index 086a453..e92fbe9 100644
--- a/src/inc/locales/zange.json
+++ b/src/inc/locales/zange.json
@@ -149,14 +149,14 @@
"image_expand_on_click_hint": "Anstatt dat Scroll-Zoom-Moped aufzumache, wird n Bild beim Klickle uff volle Größ im Bereich uffgepumpt.",
"enable_bg_blur": "Hintergrundunschärfe aktivieren",
"enable_bg_blur_hint": "Gefalteten Hintergrund auf Elementen anzeigen",
- "blur_nsfw": "NSFW falten",
- "blur_nsfw_hint": "Faltet NSFW-Vorschaubilder.",
- "blur_nsfl": "NSFL falten",
- "blur_nsfl_hint": "Faltet NSFL-Vorschaubilder.",
- "blur_sfw": "SFW falten",
- "blur_sfw_hint": "Faltet SFW-Vorschaubilder.",
- "blur_untagged": "Unmarkierte falten",
- "blur_untagged_hint": "Faltet unmarkierte Vorschaubilder.",
+ "blur_nsfw": "NSFW verwischen",
+ "blur_nsfw_hint": "Verwischt NSFW-Vorschaubilder.",
+ "blur_nsfl": "NSFL verwischen",
+ "blur_nsfl_hint": "Verwischt NSFL-Vorschaubilder.",
+ "blur_sfw": "SFW verwischen",
+ "blur_sfw_hint": "Verwischt SFW-Vorschaubilder.",
+ "blur_untagged": "Unmarkierte verwischen",
+ "blur_untagged_hint": "Verwischt unmarkierte Vorschaubilder.",
"render_emojis": "Emojis in Zitatantworten darstellen",
"render_emojis_hint": ":emoji:-Bilder innerhalb von >zitierten Zeilen anzeigen",
"embed_yt": "Röhrenelfen in Kommentaren einbetten",
diff --git a/src/inc/routes/comments.mjs b/src/inc/routes/comments.mjs
index feccaec..8a2b4da 100644
--- a/src/inc/routes/comments.mjs
+++ b/src/inc/routes/comments.mjs
@@ -418,8 +418,23 @@ export default (router, tpl) => {
}
// Notify for live updates
- // Fetch the trigger-updated xd_score from the DB (trigger runs synchronously before we get here)
- const [xdRow] = await db`SELECT xd_score FROM items WHERE id = ${item_id}`;
+ // Fetch the trigger-updated xd_score and the item rating tag from the DB (trigger runs synchronously before we get here)
+ const itemQuery = await db`
+ SELECT
+ i.xd_score,
+ (SELECT ta.tag_id FROM tags_assign ta
+ WHERE ta.item_id = i.id AND ta.tag_id = ANY(${[1, 2, cfg.nsfl_tag_id || 3]}::int[])
+ ORDER BY ta.tag_id LIMIT 1) AS rating_tag_id
+ FROM items i WHERE i.id = ${item_id}
+ `;
+ const xdRow = itemQuery[0];
+ const ratingTagId = itemQuery[0]?.rating_tag_id;
+ let ratingLabel = '?';
+ let ratingClass = 'untagged';
+ if (ratingTagId == 1) { ratingLabel = 'SFW'; ratingClass = 'sfw'; }
+ else if (ratingTagId == 2) { ratingLabel = 'NSFW'; ratingClass = 'nsfw'; }
+ else if (ratingTagId == (cfg.nsfl_tag_id || 3)) { ratingLabel = 'NSFL'; ratingClass = 'nsfl'; }
+
// Truncate body to 500 chars: PostgreSQL NOTIFY has an 8000-byte hard limit.
// Large comments would silently drop the notification. The client fetches
// the full content via _silentSync; the NOTIFY only needs to trigger the update.
@@ -450,7 +465,14 @@ export default (router, tpl) => {
item_id: item_id,
type: 'comment',
body: notifyBody,
- id: commentId
+ id: commentId,
+ item_rating_class: ratingClass,
+ item_rating_label: ratingLabel,
+ avatar: req.session.avatar,
+ avatar_file: req.session.avatar_file,
+ username: req.session.user,
+ username_color: req.session.username_color,
+ display_name: req.session.display_name || null
}));
// Automatically subscribe user to the thread
@@ -806,6 +828,9 @@ export default (router, tpl) => {
i.mime,
i.id as item_id,
i.dest as item_dest,
+ (SELECT ta.tag_id FROM tags_assign ta
+ WHERE ta.item_id = i.id AND ta.tag_id = ANY(${[1, 2, cfg.nsfl_tag_id || 3]}::int[])
+ ORDER BY ta.tag_id LIMIT 1) AS rating_tag_id,
u.user as username,
uo.avatar,
uo.avatar_file,
@@ -827,10 +852,18 @@ export default (router, tpl) => {
`;
const processedComments = comments.map(c => {
+ let ratingLabel = '?';
+ let ratingClass = 'untagged';
+ if (c.rating_tag_id == 1) { ratingLabel = 'SFW'; ratingClass = 'sfw'; }
+ else if (c.rating_tag_id == 2) { ratingLabel = 'NSFW'; ratingClass = 'nsfw'; }
+ else if (c.rating_tag_id == (cfg.nsfl_tag_id || 3)) { ratingLabel = 'NSFL'; ratingClass = 'nsfl'; }
+
return {
...c,
content: (c.content || '').trim(),
- username_color: c.username_color
+ username_color: c.username_color,
+ item_rating_class: ratingClass,
+ item_rating_label: ratingLabel
// created_at stays as the raw ISO timestamp so the frontend f0ckTimeAgo can localize it
};
});