mode reminder for lazy peeps

This commit is contained in:
2026-07-15 22:04:20 +02:00
parent 8778dbf3da
commit afc776d948
10 changed files with 261 additions and 32 deletions

View File

@@ -6732,6 +6732,39 @@ span#favs {
font-size: 15px;
}
._error_filter_hint {
grid-column: 1 / -1;
margin-top: 12px;
padding: 8px 14px;
border: 1px dashed rgba(242, 239, 11, 0.35);
background: rgba(242, 239, 11, 0.06);
color: rgba(255, 255, 255, 0.75);
font-size: 0.82em;
line-height: 1.5;
text-align: center;
text-shadow: none;
}
._error_filter_hint i {
margin-right: 5px;
opacity: 0.7;
}
._error_filter_hint strong {
color: var(--accent, #f2ef0b);
font-weight: 700;
}
._error_filter_hint a {
color: var(--accent, #f2ef0b);
text-decoration: underline;
text-underline-offset: 2px;
}
._error_filter_hint a:hover {
opacity: 0.8;
}
/* Admin search css early test */
.admin-search {
margin-top: 15px;
@@ -15933,3 +15966,87 @@ body.scroller-active #gchat-reopen-bubble {
.archive-download-btn i {
font-size: 1em;
}
/* ── Filtered-upload ghost thumbnail ──────────────────────────────────────────
Shown when the current user's freshly-uploaded item is hidden by an active
content filter (SFW / NSFW / NSFL mode). Disappears on manual page reload.
──────────────────────────────────────────────────────────────────────────── */
a.thumb.filtered-upload-ghost,
a.lazy-thumb.filtered-upload-ghost {
position: relative;
overflow: hidden;
cursor: pointer;
border: 2px dashed rgba(255, 255, 255, 0.25) !important;
box-sizing: border-box;
}
/* Strongly blur the background thumbnail image */
a.thumb.filtered-upload-ghost::before,
a.lazy-thumb.filtered-upload-ghost::before {
content: '';
position: absolute;
inset: -6px; /* bleed out so blur edges don't show */
background: var(--thumb-bg) center / cover no-repeat;
filter: blur(14px) brightness(0.45);
z-index: 0;
}
/* Dark overlay to give the label good contrast */
a.thumb.filtered-upload-ghost::after,
a.lazy-thumb.filtered-upload-ghost::after {
content: '';
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 1;
}
/* Hover: slightly brighten to hint it's clickable */
a.thumb.filtered-upload-ghost:hover::before,
a.lazy-thumb.filtered-upload-ghost:hover::before {
filter: blur(14px) brightness(0.6);
}
a.thumb.filtered-upload-ghost:hover::after,
a.lazy-thumb.filtered-upload-ghost:hover::after {
background: rgba(0, 0, 0, 0.3);
}
/* Overlay label inside the ghost thumb */
.filtered-upload-ghost-label {
position: absolute;
inset: 0;
z-index: 2;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 5px;
padding: 8px;
text-align: center;
pointer-events: none;
color: rgba(255, 255, 255, 0.92);
user-select: none;
}
.filtered-upload-ghost-label .fug-icon {
font-size: 1.4em;
opacity: 0.85;
line-height: 1;
}
.filtered-upload-ghost-label .fug-title {
font-size: 0.65em;
font-weight: 700;
letter-spacing: 0.04em;
line-height: 1.25;
text-transform: uppercase;
opacity: 0.95;
}
.filtered-upload-ghost-label .fug-hint {
font-size: 0.58em;
opacity: 0.6;
line-height: 1.3;
font-weight: 400;
}

View File

@@ -676,11 +676,14 @@ window.cancelAnimFrame = (function () {
window.flashMessage('ALL MODE ACTIVATED');
gridCacheMap.clear();
const isGridView = document.querySelector('.posts, .tags-grid');
const isItemView = document.getElementById('prev') || document.getElementById('next') || /^\/\d+/.test(window.location.pathname);
let reloadPromise = null;
if (isGridView) {
const currentUrl = new URL(window.location.href);
currentUrl.searchParams.delete('mode');
reloadPromise = loadPageAjax(currentUrl.toString(), true, { skipCache: true });
reloadPromise = window.loadPageAjax ? window.loadPageAjax(currentUrl.toString(), true, { skipCache: true }) : null;
} else if (isItemView) {
reloadPromise = window.loadItemAjax ? window.loadItemAjax(window.location.href, true, { skipCache: true }) : null;
}
if (fromFilterModal) Promise.resolve(reloadPromise).finally(() => { window._keepFilterModal = false; });
}
@@ -731,14 +734,15 @@ window.cancelAnimFrame = (function () {
window.flashMessage(label);
gridCacheMap.clear();
const isGridView = document.querySelector('.posts, .tags-grid');
const isItemView = document.getElementById('prev') || document.getElementById('next');
const isItemView = document.getElementById('prev') || document.getElementById('next') || /^\/\d+/.test(window.location.pathname);
let reloadPromise = null;
if (isGridView) {
const currentUrl = new URL(window.location.href);
currentUrl.searchParams.delete('mode');
reloadPromise = loadPageAjax(currentUrl.toString(), true, { skipCache: true });
reloadPromise = window.loadPageAjax ? window.loadPageAjax(currentUrl.toString(), true, { skipCache: true }) : null;
} else if (isItemView) {
updateNavForMode(window.activeMode);
reloadPromise = window.loadItemAjax ? window.loadItemAjax(window.location.href, true, { skipCache: true }) : null;
}
if (fromFilterModal) Promise.resolve(reloadPromise).finally(() => { window._keepFilterModal = false; });
} else {
@@ -5495,6 +5499,14 @@ window.cancelAnimFrame = (function () {
});
}
// Delegated handler: [data-action="open-filter-modal"] links (e.g. error page hint)
document.addEventListener('click', (e) => {
const trigger = e.target.closest('[data-action="open-filter-modal"]');
if (!trigger) return;
e.preventDefault();
toggleModal(true);
});
close.addEventListener('click', () => toggleModal(false));
overlay.addEventListener('click', (e) => {
if (e.target === overlay) toggleModal(false);
@@ -7957,12 +7969,74 @@ class NotificationSystem {
window.location.pathname.includes('/h/') ||
window.location.pathname.includes('/user/')) return;
// Respect mode filter
// Respect mode filter — but if this is the current user's own upload,
// show a blurred "ghost" thumbnail so they know it was uploaded successfully
// even though the active filter hides it from the grid.
if (typeof window.activeMode !== 'undefined' && window.activeMode !== 3) { // 3 is ALL
if (window.activeMode === 0 && data.tag_id !== 1) return; // SFW mode, item is not SFW
if (window.activeMode === 1 && data.tag_id !== 2) return; // NSFW mode, item is not NSFW
if (window.activeMode === 4 && data.tag_id != window.f0ckSession?.nsfl_tag_id) return; // NSFL mode, item is not NSFL
if (window.activeMode === 2) return; // Untagged mode, new uploads are never untagged
let filtered = false;
let filterReason = '';
if (window.activeMode === 0 && data.tag_id !== 1) { filtered = true; filterReason = 'SFW'; } // SFW mode, item is not SFW
else if (window.activeMode === 1 && data.tag_id !== 2) { filtered = true; filterReason = 'NSFW'; } // NSFW mode, item is not NSFW
else if (window.activeMode === 4 && data.tag_id != window.f0ckSession?.nsfl_tag_id) { filtered = true; filterReason = 'NSFL'; } // NSFL mode
else if (window.activeMode === 2) { filtered = true; filterReason = 'untagged'; }
if (filtered) {
// Check if this is the current user's own upload
const sessionUser = (window.f0ckSession?.user || '').toLowerCase();
const itemUser = (data.username || '').toLowerCase();
const isOwnUpload = sessionUser && itemUser && sessionUser === itemUser;
if (!isOwnUpload) return; // Silently drop as before for other users' uploads
// Don't add duplicates
if (grid.querySelector(`a[href$="/${data.id}"]`)) return;
// Determine the link prefix from existing items
const firstThumb = grid.querySelector('a.thumb, a.lazy-thumb');
const linkBase = firstThumb ? firstThumb.getAttribute('href').replace(/\d+$/, '') : '/';
// Build filter-reason label
const i18n = window.f0ckI18n || {};
const filterLabel = filterReason === 'SFW' ? (i18n.filter_mode_sfw || 'SFW filter active')
: filterReason === 'NSFW' ? (i18n.filter_mode_nsfw || 'NSFW filter active')
: filterReason === 'NSFL' ? (i18n.filter_mode_nsfl || 'NSFL filter active')
: (i18n.filter_mode_other || 'Filter active');
const ghostTitle = i18n.filtered_upload_title || 'Your upload';
const ghostHint = i18n.filtered_upload_hint || 'Hidden by filter · click to view';
const nsflId = window.f0ckSession?.nsfl_tag_id;
const mode = data.tag_id ? (data.tag_id === 1 ? 'sfw' : (data.tag_id === 2 ? 'nsfw' : (data.tag_id == nsflId ? 'nsfl' : 'null'))) : 'null';
const ghost = document.createElement('a');
ghost.href = `${linkBase}${data.id}`;
ghost.className = 'thumb lazy-thumb filtered-upload-ghost loaded';
ghost.dataset.file = data.dest;
ghost.dataset.mime = data.mime;
ghost.dataset.user = data.display_name || data.username;
ghost.dataset.mode = mode;
ghost.style.setProperty('--thumb-bg', `url('/t/${data.id}.webp')`);
ghost.style.opacity = '0';
ghost.style.transform = 'scale(0.9)';
ghost.innerHTML = `
<div class="filtered-upload-ghost-label">
<i class="fa-solid fa-eye-slash"></i>
</div>`;
const pinnedItems = grid.querySelectorAll('.is-pinned');
if (pinnedItems.length > 0) {
pinnedItems[pinnedItems.length - 1].after(ghost);
} else {
grid.prepend(ghost);
}
requestAnimationFrame(() => {
ghost.style.transition = 'opacity 0.4s ease, transform 0.4s ease';
ghost.style.opacity = '1';
ghost.style.transform = 'scale(1)';
});
return; // Ghost injected — done
}
}
// Don't add duplicates