Sleazy Fork is available in English.
Adds a "Hide UI" toggle button to the sidebar. When active, all UI is hidden except the button itself and the player progress bar.
// ==UserScript==
// @name RedGifs – Hide UI
// @namespace https://redgifs.com/
// @version 1.0.2
// @description Adds a "Hide UI" toggle button to the sidebar. When active, all UI is hidden except the button itself and the player progress bar.
// @author fusky
// @license MIT
// @match https://www.redgifs.com/*
// @match https://redgifs.com/*
// @grant GM_addStyle
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
/* ─── Styles ─────────────────────────────────────────────────────────── */
GM_addStyle(`
/* Button base */
#rgf-hide-ui-btn {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 10px;
margin: 8px 0;
border: none;
border-radius: 8px;
background: rgba(255,255,255,0.08);
color: #e0e0e0;
font-family: inherit;
font-size: 13px;
font-weight: 600;
letter-spacing: 0.03em;
cursor: pointer;
transition: background 0.2s, color 0.2s, transform 0.1s;
white-space: nowrap;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
z-index: 2147483647;
}
#rgf-hide-ui-btn:hover { background: rgba(255,255,255,0.15); }
#rgf-hide-ui-btn:active { transform: scale(0.96); }
/* Active / "UI hidden" state */
#rgf-hide-ui-btn.rgf-active {
background: rgba(255, 80, 80, 0.25);
color: #ff6b6b;
}
#rgf-hide-ui-btn.rgf-active:hover {
background: rgba(255, 80, 80, 0.35);
}
/* ── When UI is hidden ───────────────────────────────────────────── */
/* Only hide the meta info overlay — everything else stays untouched */
body.rgf-hidden .GifPreview-MetaInfo {
visibility: hidden !important;
}
`);
/* ─── Button creation ────────────────────────────────────────────────── */
function createButton () {
const btn = document.createElement('button');
btn.id = 'rgf-hide-ui-btn';
btn.setAttribute('aria-label', 'Toggle UI visibility');
btn.setAttribute('title', 'Hide / Show site UI');
btn.innerHTML = eyeIcon(false);
btn.addEventListener('click', toggle);
// Touch-friendly: also respond to touchend to feel snappy on mobile
btn.addEventListener('touchend', (e) => {
e.preventDefault();
toggle();
}, { passive: false });
return btn;
}
/* ─── Icons (inline SVG – no external deps) ─────────────────────────── */
function eyeIcon (crossed) {
return crossed
? `<svg width="16" height="16" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" aria-hidden="true">
<path d="M17.94 17.94A10.07 10.07 0 0112 20c-7 0-11-8-11-8
a18.45 18.45 0 015.06-5.94"/>
<path d="M9.9 4.24A9.12 9.12 0 0112 4c7 0 11 8 11 8
a18.5 18.5 0 01-2.16 3.19"/>
<line x1="1" y1="1" x2="23" y2="23"/>
</svg>`
: `<svg width="16" height="16" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" aria-hidden="true">
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
<circle cx="12" cy="12" r="3"/>
</svg>`;
}
/* ─── Filter sidebar items based on current hidden state ────────────── */
function filterSideBarItems () {
if (!hidden) return;
document.querySelectorAll('.sideBar .sideBarItem').forEach(item => {
const hasSoundBtn = !!item.querySelector('.SoundButton');
if (!hasSoundBtn) item.style.display = 'none';
});
}
/* ─── Toggle logic ───────────────────────────────────────────────────── */
let hidden = false;
function toggle () {
hidden = !hidden;
document.body.classList.toggle('rgf-hidden', hidden);
// Hide/show sidebar items based on state
if (hidden) {
filterSideBarItems();
} else {
document.querySelectorAll('.sideBar .sideBarItem').forEach(item => {
item.style.display = '';
});
}
// Sync all button instances
document.querySelectorAll('#rgf-hide-ui-btn').forEach(btn => {
btn.classList.toggle('rgf-active', hidden);
btn.innerHTML = eyeIcon(hidden);
});
}
/* ─── Inject into sidebar ────────────────────────────────────────────── */
function inject () {
document.querySelectorAll('.sideBar').forEach(sidebar => {
// Only inject once per sidebar instance
if (sidebar.querySelector('#rgf-hide-ui-btn')) return;
const btn = createButton();
if (sidebar.firstChild) {
sidebar.insertBefore(btn, sidebar.firstChild);
} else {
sidebar.appendChild(btn);
}
});
}
/* ─── Hide FeedModule ad elements in previewFeed (no DOM removal) ───── */
function purgeAdModules () {
document.querySelectorAll('.previewFeed .FeedModule').forEach(el => {
el.style.display = 'none';
});
}
/* ─── Sync all button instances to current state ────────────────────── */
function syncButtons () {
document.querySelectorAll('#rgf-hide-ui-btn').forEach(btn => {
btn.classList.toggle('rgf-active', hidden);
btn.innerHTML = eyeIcon(hidden);
if (!btn._rgfBound) {
btn._rgfBound = true;
btn.addEventListener('click', toggle);
btn.addEventListener('touchend', (e) => { e.preventDefault(); toggle(); }, { passive: false });
}
});
}
/* ─── Wait for the sidebar (SPA / lazy render) ───────────────────────── */
function waitForSidebar () {
inject();
purgeAdModules();
syncButtons();
let rafId = null;
const observer = new MutationObserver(() => {
if (rafId) return;
rafId = requestAnimationFrame(() => {
rafId = null;
inject();
purgeAdModules();
syncButtons();
filterSideBarItems();
});
});
observer.observe(document.body, { childList: true, subtree: true });
}
/* ─── Boot ───────────────────────────────────────────────────────────── */
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', waitForSidebar);
} else {
waitForSidebar();
}
})();