From 8b24668ee5fce2c6ca348664349301d2a77a1210 Mon Sep 17 00:00:00 2001 From: Vishwam Date: Fri, 19 Sep 2025 20:50:12 +0530 Subject: [PATCH 1/6] New Youtube Minimal Script --- Youtube_Minimal_Plus.user.js | 304 +++++++++++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 Youtube_Minimal_Plus.user.js diff --git a/Youtube_Minimal_Plus.user.js b/Youtube_Minimal_Plus.user.js new file mode 100644 index 0000000..d2fcdd7 --- /dev/null +++ b/Youtube_Minimal_Plus.user.js @@ -0,0 +1,304 @@ +// ==UserScript== +// @name Minimal YouTube +// @namespace http://tampermonkey.net/ +// @version 2.4 +// @description A minimal YouTube experience with a customizable interface. +// @author Your Name +// @match https://*.youtube.com/* +// @grant GM.getValue +// @grant GM.setValue +// @grant GM_addValueChangeListener +// @run-at document-start +// ==/UserScript== + +(function () { + "use strict"; + + const debug = true; + + const options = { + minimalHomepage: { + label: "Enable Minimal Homepage", + value: true, + onUpdate: applyStyles, + icon: `` + }, + hideComments: { + label: "Hide Comments", + value: true, + onUpdate: applyStyles, + icon: `` + }, + hideSecondary: { + label: "Hide Recommendations", + value: true, + onUpdate: applyStyles, + icon: `` + }, + hideRelated: { + label: "Hide Related Videos", + value: true, + onUpdate: applyStyles, + icon: `` + }, + hideSidebar: { + label: "Hide Sidebar", + value: true, + onUpdate: applyStyles, + icon: `` + }, + hideTopBarButtons: { + label: "Hide Top Bar Buttons", + value: true, + onUpdate: applyStyles, + icon: `` + }, + }; + + let popup; + let homeContainer; + let menuItems = {}; + + async function loadOptions() { + for (const key in options) { + const savedValue = await GM.getValue(key, options[key].value); + options[key].value = savedValue; + } + } + + function saveOption(key, value) { + options[key].value = value; + GM.setValue(key, value); + if (options[key].onUpdate) { + options[key].onUpdate(); + } + showToast(`${options[key].label} ${value ? 'enabled' : 'disabled'}`); + } + + function applyStyles() { + if (debug) console.log('Applying styles...'); + const html = document.documentElement; + const isHomepage = window.location.pathname === "/"; + try { + html.classList.toggle("minimal-youtube-homepage", options.minimalHomepage.value && isHomepage); + html.classList.toggle("minimal-youtube-hide-comments", options.hideComments.value); + html.classList.toggle("minimal-youtube-hide-secondary", options.hideSecondary.value); + html.classList.toggle("minimal-youtube-hide-related", options.hideRelated.value); + html.classList.toggle("minimal-youtube-hide-sidebar", options.hideSidebar.value); + html.classList.toggle("minimal-youtube-hide-top-bar-buttons", options.hideTopBarButtons.value); + + if (options.minimalHomepage.value && isHomepage) { + if (!homeContainer) createHomeContainer(); + homeContainer.style.display = 'flex'; + } else if (homeContainer) { + homeContainer.style.display = 'none'; + } + } catch (e) { + if (debug) console.error('Error applying styles:', e); + } + } + + function createMenuItem(key) { + const option = options[key]; + const item = document.createElement("div"); + item.className = "ytp-menuitem"; + + const icon = document.createElement("div"); + icon.className = "ytp-menuitem-icon"; + icon.innerHTML = option.icon; + + const label = document.createElement("div"); + label.className = "ytp-menuitem-label"; + label.textContent = option.label; + + const content = document.createElement("div"); + content.className = "ytp-menuitem-content"; + const toggleCheckbox = document.createElement("div"); + toggleCheckbox.className = "ytp-menuitem-toggle-checkbox"; + content.appendChild(toggleCheckbox); + + item.append(icon, label, content); + + item.setAttribute("aria-checked", option.value); + item.addEventListener("click", () => { + const newValue = !options[key].value; + item.setAttribute("aria-checked", newValue); + saveOption(key, newValue); + }); + + menuItems[key] = item; + return item; + } + + function createPopup() { + popup = document.createElement("div"); + popup.className = "yt-minimal-popup-container"; + popup.style.display = "none"; + popup.setAttribute('role', 'dialog'); + popup.setAttribute('aria-modal', 'true'); + popup.setAttribute('tabindex', '-1'); + + const menu = document.createElement("div"); + menu.className = "yt-minimal-menu ytp-panel-menu"; + popup.appendChild(menu); + + for (const key in options) { + menu.appendChild(createMenuItem(key)); + } + + document.body.appendChild(popup); + + popup.addEventListener('click', (e) => { + if (e.target === popup) togglePopup(); + }); + popup.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + e.preventDefault(); + togglePopup(); + } + }); + } + + function togglePopup() { + if (!popup) createPopup(); + const isHidden = popup.style.display === "none"; + popup.style.display = isHidden ? "flex" : "none"; + if (!isHidden) return; + popup.focus(); + } + + function createHomeContainer() { + const app = document.querySelector('ytd-app'); + if (!app) { + if (debug) console.error('ytd-app not found'); + return; + } + homeContainer = document.createElement('div'); + homeContainer.className = 'home-container'; + homeContainer.style.display = 'none'; + + homeContainer.innerHTML = ` +
+ +
+
+ + +
+ `; + app.appendChild(homeContainer); + + const input = homeContainer.querySelector(".search-input"); + const searchBtn = homeContainer.querySelector(".search-btn"); + + const search = () => { + const inputValue = input.value.trim(); + if (!inputValue) { + showToast("Enter a search term"); + return; + } + window.location.href = `https://www.youtube.com/results?search_query=${encodeURIComponent(inputValue)}`; + }; + + input.addEventListener("keypress", (e) => { + if (e.key === "Enter") search(); + }); + searchBtn.addEventListener("click", search); + } + + function showToast(message) { + const toast = document.createElement('div'); + toast.textContent = message; + toast.className = 'yt-minimal-toast'; + document.body.appendChild(toast); + setTimeout(() => toast.remove(), 2000); + } + + function init() { + loadOptions().then(() => { + const style = document.createElement("style"); + style.textContent = ` + /* Popup Styles */ + .yt-minimal-popup-container { display: flex; justify-content: center; align-items: center; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.6); z-index: 9999; } + .yt-minimal-menu.ytp-panel-menu { background: var(--yt-spec-base-background, #181818); width: 400px; padding: 10px; fill: var(--yt-spec-text-primary, #eee); font-family: "Roboto", "Arial", sans-serif; border-radius: 12px; } + .ytp-menuitem { display: flex; align-items: center; padding: 12px; cursor: pointer; } + .ytp-menuitem:hover { background-color: var(--yt-spec-10-percent-layer, #383838); } + .ytp-menuitem-icon { width: 24px; height: 24px; margin-right: 16px; } + .ytp-menuitem-label { color: var(--yt-spec-text-primary, #eee); font-size: 14px; flex-grow: 1; } + .ytp-menuitem-content { margin-left: auto; } + .ytp-menuitem-toggle-checkbox { background-color: var(--yt-spec-text-disabled, rgb(144, 144, 144)); border-radius: 12px; height: 16px; width: 32px; position: relative; } + .ytp-menuitem-toggle-checkbox::after { background-color: var(--yt-spec-base-background, #181818); border-radius: 50%; content: ""; height: 24px; width: 24px; position: absolute; top: -4px; left: -2px; transition: left 0.1s cubic-bezier(0.4, 0, 1, 1); } + .ytp-menuitem[aria-checked=true] .ytp-menuitem-toggle-checkbox { background-color: var(--yt-spec-call-to-action, #6ea8ff); } + .ytp-menuitem[aria-checked=true] .ytp-menuitem-toggle-checkbox::after { left: 10px; } + + /* Minimal YouTube Styles */ + html.minimal-youtube-homepage, html.minimal-youtube-homepage body { height: 100vh; background-color: var(--yt-spec-base-background, #0f0f0f); } + html.minimal-youtube-homepage ytd-app > :not(.home-container) { display: none !important; } + .home-container { display: none; flex-direction: column; gap: 24px; align-items: center; justify-content: center; height: 100%; position: absolute; top: 0; left: 0; width: 100%; background: var(--yt-spec-base-background, #0f0f0f); z-index: 1000; } + .logo-full { width: 200px; margin-bottom: 20px; } + .search-group { height: 40px; display: flex; position: relative; } + .search-input { font-size: 16px; padding: 8px 16px; max-width: 500px; width: calc(100vw - 100px); border-radius: 40px 0 0 40px; border: 1px solid var(--yt-spec-10-percent-layer, #303030); background: var(--ytd-searchbox-background, #121212); color: var(--ytd-searchbox-text-color, white); } + .search-input:focus { outline: none; border-color: var(--yt-spec-call-to-action, #1c62b9); } + .search-btn { border: 1px solid var(--yt-spec-10-percent-layer, #303030); border-left: none; height: 40px; cursor: pointer; border-radius: 0 40px 40px 0; padding: 0 24px; background: var(--ytd-searchbox-legacy-button-color, #222222); } + .search-icon-container { height: 24px; width: 24px; fill: var(--yt-spec-icon-active-other, #909090); } + + /* Hide element styles */ + html.minimal-youtube-hide-comments #comments { display: none !important; } + html.minimal-youtube-hide-secondary #secondary { display: none !important; } + html.minimal-youtube-hide-related #related { display: none !important; } + html.minimal-youtube-hide-sidebar #guide, html.minimal-youtube-hide-sidebar tp-yt-app-drawer, html.minimal-youtube-hide-sidebar ytd-mini-guide-renderer { display: none !important; } + html.minimal-youtube-hide-top-bar-buttons #guide-button, html.minimal-youtube-hide-top-bar-buttons #voice-search-button, html.minimal-youtube-hide-top-bar-buttons .ytd-masthead #end #buttons { display: none !important; } + /* FIX: Reclaim sidebar space */ + html.minimal-youtube-hide-sidebar ytd-page-manager.ytd-app { margin-left: 0 !important; } + + /* Toast */ + .yt-minimal-toast { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: var(--yt-spec-base-background, #181818); color: var(--yt-spec-text-primary, #eee); padding: 10px 20px; border-radius: 4px; z-index: 10000; opacity: 0.9; transition: opacity 0.3s; } + + /* Responsive */ + @media (max-width: 600px) { + .logo-full { width: 150px; } + .search-input { width: 100%; max-width: none; border-radius: 40px 40px 0 0; } + .search-btn { border-radius: 0 0 40px 40px; border-top: none; width: 100%; padding: 8px; } + .search-group { flex-direction: column; height: auto; } + } + `; + document.head.appendChild(style); + + window.addEventListener("keydown", (e) => { + if (e.key === "c" && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA') { + e.preventDefault(); + e.stopPropagation(); + togglePopup(); + } + }, true); + + window.addEventListener('yt-navigate-finish', applyStyles); + window.addEventListener('popstate', applyStyles); + window.addEventListener('hashchange', applyStyles); + + for (const key in options) { + GM_addValueChangeListener(key, (name, old_value, new_value, remote) => { + if (remote) { + options[key].value = new_value; + applyStyles(); + if (menuItems[key]) { + menuItems[key].setAttribute('aria-checked', new_value); + } + } + }); + } + + applyStyles(); + }); + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})(); From 24cf11a92faf849186e59bcf532e9fd300aeb7c9 Mon Sep 17 00:00:00 2001 From: fznhq <55099255+fznhq@users.noreply.github.com> Date: Sat, 20 Sep 2025 00:03:22 +0700 Subject: [PATCH 2/6] Fix playlist overlap --- Youtube_Minimal_Plus.user.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Youtube_Minimal_Plus.user.js b/Youtube_Minimal_Plus.user.js index d2fcdd7..01e5a8d 100644 --- a/Youtube_Minimal_Plus.user.js +++ b/Youtube_Minimal_Plus.user.js @@ -254,6 +254,9 @@ html.minimal-youtube-hide-top-bar-buttons #guide-button, html.minimal-youtube-hide-top-bar-buttons #voice-search-button, html.minimal-youtube-hide-top-bar-buttons .ytd-masthead #end #buttons { display: none !important; } /* FIX: Reclaim sidebar space */ html.minimal-youtube-hide-sidebar ytd-page-manager.ytd-app { margin-left: 0 !important; } + + /* FIX: Overlapping Playlist */ + html.minimal-youtube-hide-sidebar ytd-playlist-header-renderer { left: 0 !important; } /* Toast */ .yt-minimal-toast { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: var(--yt-spec-base-background, #181818); color: var(--yt-spec-text-primary, #eee); padding: 10px 20px; border-radius: 4px; z-index: 10000; opacity: 0.9; transition: opacity 0.3s; } From 8d241ee885318aeb71f70b09a3a1b462d58fae58 Mon Sep 17 00:00:00 2001 From: fznhq <55099255+fznhq@users.noreply.github.com> Date: Sat, 20 Sep 2025 02:02:24 +0700 Subject: [PATCH 3/6] More fix for playlist overlap --- Youtube_Minimal_Plus.user.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Youtube_Minimal_Plus.user.js b/Youtube_Minimal_Plus.user.js index 01e5a8d..c6ff4eb 100644 --- a/Youtube_Minimal_Plus.user.js +++ b/Youtube_Minimal_Plus.user.js @@ -256,7 +256,8 @@ html.minimal-youtube-hide-sidebar ytd-page-manager.ytd-app { margin-left: 0 !important; } /* FIX: Overlapping Playlist */ - html.minimal-youtube-hide-sidebar ytd-playlist-header-renderer { left: 0 !important; } + html.minimal-youtube-hide-sidebar ytd-browse[role=main] ytd-playlist-header-renderer:not([hidden]), + html.minimal-youtube-hide-sidebar ytd-browse[role=main] yt-page-header-renderer:not([hidden]) { left: 0 !important; } /* Toast */ .yt-minimal-toast { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: var(--yt-spec-base-background, #181818); color: var(--yt-spec-text-primary, #eee); padding: 10px 20px; border-radius: 4px; z-index: 10000; opacity: 0.9; transition: opacity 0.3s; } From d3db6ccfc0760352b85b08a319c7a6e9fcc6e238 Mon Sep 17 00:00:00 2001 From: Vishwam Date: Sat, 20 Sep 2025 12:25:06 +0530 Subject: [PATCH 4/6] Changed keybind and switched to attribute --- Youtube_Minimal_Plus.user.js | 54 +++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/Youtube_Minimal_Plus.user.js b/Youtube_Minimal_Plus.user.js index c6ff4eb..6043f8e 100644 --- a/Youtube_Minimal_Plus.user.js +++ b/Youtube_Minimal_Plus.user.js @@ -75,17 +75,32 @@ showToast(`${options[key].label} ${value ? 'enabled' : 'disabled'}`); } + const prefix = "ytmp-"; + const attrId = "-" + Date.now().toString(36).slice(-4); + const attr = { + minimalHomepage: "minimal-homepage", + hideComments: "hide-comments", + hideSecondary: "hide-secondary", + hideRelated: "hide-related", + hideSidebar: "hide-sidebar", + hideTopBarButtons: "hide-top-bar-buttons", + }; + + function setHtmlAttr(attrName, state) { + document.documentElement.toggleAttribute(prefix + attr[attrName] + attrId, state); + } + function applyStyles() { if (debug) console.log('Applying styles...'); const html = document.documentElement; const isHomepage = window.location.pathname === "/"; try { - html.classList.toggle("minimal-youtube-homepage", options.minimalHomepage.value && isHomepage); - html.classList.toggle("minimal-youtube-hide-comments", options.hideComments.value); - html.classList.toggle("minimal-youtube-hide-secondary", options.hideSecondary.value); - html.classList.toggle("minimal-youtube-hide-related", options.hideRelated.value); - html.classList.toggle("minimal-youtube-hide-sidebar", options.hideSidebar.value); - html.classList.toggle("minimal-youtube-hide-top-bar-buttons", options.hideTopBarButtons.value); + setHtmlAttr("minimalHomepage", options.minimalHomepage.value && isHomepage); + setHtmlAttr("hideComments", options.hideComments.value); + setHtmlAttr("hideSecondary", options.hideSecondary.value); + setHtmlAttr("hideRelated", options.hideRelated.value); + setHtmlAttr("hideSidebar", options.hideSidebar.value); + setHtmlAttr("hideTopBarButtons", options.hideTopBarButtons.value); if (options.minimalHomepage.value && isHomepage) { if (!homeContainer) createHomeContainer(); @@ -221,7 +236,7 @@ function init() { loadOptions().then(() => { const style = document.createElement("style"); - style.textContent = ` + let cssText = ` /* Popup Styles */ .yt-minimal-popup-container { display: flex; justify-content: center; align-items: center; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.6); z-index: 9999; } .yt-minimal-menu.ytp-panel-menu { background: var(--yt-spec-base-background, #181818); width: 400px; padding: 10px; fill: var(--yt-spec-text-primary, #eee); font-family: "Roboto", "Arial", sans-serif; border-radius: 12px; } @@ -236,8 +251,8 @@ .ytp-menuitem[aria-checked=true] .ytp-menuitem-toggle-checkbox::after { left: 10px; } /* Minimal YouTube Styles */ - html.minimal-youtube-homepage, html.minimal-youtube-homepage body { height: 100vh; background-color: var(--yt-spec-base-background, #0f0f0f); } - html.minimal-youtube-homepage ytd-app > :not(.home-container) { display: none !important; } + html[${prefix}minimal-homepage${attrId}], html[${prefix}minimal-homepage${attrId}] body { height: 100vh; background-color: var(--yt-spec-base-background, #0f0f0f); } + html[${prefix}minimal-homepage${attrId}] ytd-app > :not(.home-container) { display: none !important; } .home-container { display: none; flex-direction: column; gap: 24px; align-items: center; justify-content: center; height: 100%; position: absolute; top: 0; left: 0; width: 100%; background: var(--yt-spec-base-background, #0f0f0f); z-index: 1000; } .logo-full { width: 200px; margin-bottom: 20px; } .search-group { height: 40px; display: flex; position: relative; } @@ -247,17 +262,17 @@ .search-icon-container { height: 24px; width: 24px; fill: var(--yt-spec-icon-active-other, #909090); } /* Hide element styles */ - html.minimal-youtube-hide-comments #comments { display: none !important; } - html.minimal-youtube-hide-secondary #secondary { display: none !important; } - html.minimal-youtube-hide-related #related { display: none !important; } - html.minimal-youtube-hide-sidebar #guide, html.minimal-youtube-hide-sidebar tp-yt-app-drawer, html.minimal-youtube-hide-sidebar ytd-mini-guide-renderer { display: none !important; } - html.minimal-youtube-hide-top-bar-buttons #guide-button, html.minimal-youtube-hide-top-bar-buttons #voice-search-button, html.minimal-youtube-hide-top-bar-buttons .ytd-masthead #end #buttons { display: none !important; } + html[${prefix}hide-comments${attrId}] #comments { display: none !important; } + html[${prefix}hide-secondary${attrId}] #secondary { display: none !important; } + html[${prefix}hide-related${attrId}] #related { display: none !important; } + html[${prefix}hide-sidebar${attrId}] #guide, html[${prefix}hide-sidebar${attrId}] tp-yt-app-drawer, html[${prefix}hide-sidebar${attrId}] ytd-mini-guide-renderer { display: none !important; } + html[${prefix}hide-top-bar-buttons${attrId}] #guide-button, html[${prefix}hide-top-bar-buttons${attrId}] #voice-search-button, html[${prefix}hide-top-bar-buttons${attrId}] .ytd-masthead #end #buttons { display: none !important; } /* FIX: Reclaim sidebar space */ - html.minimal-youtube-hide-sidebar ytd-page-manager.ytd-app { margin-left: 0 !important; } - + html[${prefix}hide-sidebar${attrId}] ytd-page-manager.ytd-app { margin-left: 0 !important; } + /* FIX: Overlapping Playlist */ - html.minimal-youtube-hide-sidebar ytd-browse[role=main] ytd-playlist-header-renderer:not([hidden]), - html.minimal-youtube-hide-sidebar ytd-browse[role=main] yt-page-header-renderer:not([hidden]) { left: 0 !important; } + html[${prefix}hide-sidebar${attrId}] ytd-browse[role=main] ytd-playlist-header-renderer:not([hidden]), + html[${prefix}hide-sidebar${attrId}] ytd-browse[role=main] yt-page-header-renderer:not([hidden]) { left: 0 !important; } /* Toast */ .yt-minimal-toast { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: var(--yt-spec-base-background, #181818); color: var(--yt-spec-text-primary, #eee); padding: 10px 20px; border-radius: 4px; z-index: 10000; opacity: 0.9; transition: opacity 0.3s; } @@ -270,10 +285,11 @@ .search-group { flex-direction: column; height: auto; } } `; + style.textContent = cssText; document.head.appendChild(style); window.addEventListener("keydown", (e) => { - if (e.key === "c" && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA') { + if (e.key.toLowerCase() === "b" && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA') { e.preventDefault(); e.stopPropagation(); togglePopup(); From 93941f3d5acbe10569b8bde76525b10ff953e5a3 Mon Sep 17 00:00:00 2001 From: fznhq <55099255+fznhq@users.noreply.github.com> Date: Sat, 20 Sep 2025 23:13:39 +0700 Subject: [PATCH 5/6] Update Youtube_Minimal_Plus.user.js * Add proper metadata * Standardized object key naming * Add support for Chrome * Introduced utilities for creating templates * Made search box feel more like the native one * Improved homepage check implementation * Fix some bugs * Simplified and Cleaned up --- Youtube_Minimal_Plus.user.js | 473 +++++++++++++++++------------------ 1 file changed, 236 insertions(+), 237 deletions(-) diff --git a/Youtube_Minimal_Plus.user.js b/Youtube_Minimal_Plus.user.js index 6043f8e..b6e2c86 100644 --- a/Youtube_Minimal_Plus.user.js +++ b/Youtube_Minimal_Plus.user.js @@ -1,324 +1,323 @@ // ==UserScript== -// @name Minimal YouTube -// @namespace http://tampermonkey.net/ -// @version 2.4 -// @description A minimal YouTube experience with a customizable interface. -// @author Your Name -// @match https://*.youtube.com/* -// @grant GM.getValue -// @grant GM.setValue -// @grant GM_addValueChangeListener -// @run-at document-start +// @name Minimal YouTube +// @version 1.0.0 +// @description A minimal YouTube experience with a customizable interface. +// @run-at document-start +// @match https://www.youtube.com/* +// @exclude https://*.youtube.com/live_chat* +// @exclude https://*.youtube.com/embed* +// @exclude https://*.youtube.com/tv* +// @grant GM.getValue +// @grant GM.setValue +// @updateURL https://github.com/fznhq/userscript-collection/raw/main/Youtube_Minimal_Plus.user.js +// @downloadURL https://github.com/fznhq/userscript-collection/raw/main/Youtube_Minimal_Plus.user.js +// @author Vishwamz (https://github.com/Vishwamz) +// @collaborator Fznhq +// @namespace https://github.com/fznhq +// @homepageURL https://github.com/fznhq/userscript-collection +// @homepage https://github.com/fznhq/userscript-collection +// @license GNU GPLv3 // ==/UserScript== (function () { "use strict"; - const debug = true; - const options = { - minimalHomepage: { - label: "Enable Minimal Homepage", + minimal_homepage: { + label: "Minimal Homepage", value: true, - onUpdate: applyStyles, - icon: `` + icon: ``, }, - hideComments: { + hide_comments: { label: "Hide Comments", value: true, - onUpdate: applyStyles, - icon: `` + icon: ``, }, - hideSecondary: { + hide_secondary: { label: "Hide Recommendations", value: true, - onUpdate: applyStyles, - icon: `` + icon: ``, }, - hideRelated: { + hide_related: { label: "Hide Related Videos", value: true, - onUpdate: applyStyles, - icon: `` + icon: ``, }, - hideSidebar: { + hide_sidebar: { label: "Hide Sidebar", value: true, - onUpdate: applyStyles, - icon: `` + icon: ``, }, - hideTopBarButtons: { + hide_top_bar_buttons: { label: "Hide Top Bar Buttons", value: true, - onUpdate: applyStyles, - icon: `` + icon: ``, }, }; - let popup; - let homeContainer; - let menuItems = {}; + const policyOptions = { createHTML: (html) => html.trim() }; + const policy = window.trustedTypes + ? window.trustedTypes.createPolicy("ytmp-policy", policyOptions) + : policyOptions; + + function create(html) { + const container = document.createElement("div"); + container.innerHTML = policy.createHTML(html.replace(/>\s+<")); + return container.firstElementChild; + } + + const menuItems = {}; + const popup = createPopup(); + const homeContainer = createHomeContainer(); async function loadOptions() { for (const key in options) { - const savedValue = await GM.getValue(key, options[key].value); - options[key].value = savedValue; + options[key].value = await GM.getValue(key, options[key].value); } } function saveOption(key, value) { options[key].value = value; GM.setValue(key, value); - if (options[key].onUpdate) { - options[key].onUpdate(); - } - showToast(`${options[key].label} ${value ? 'enabled' : 'disabled'}`); } const prefix = "ytmp-"; const attrId = "-" + Date.now().toString(36).slice(-4); const attr = { - minimalHomepage: "minimal-homepage", - hideComments: "hide-comments", - hideSecondary: "hide-secondary", - hideRelated: "hide-related", - hideSidebar: "hide-sidebar", - hideTopBarButtons: "hide-top-bar-buttons", + is_homepage: "is-homepage", + minimal_homepage: "minimal-homepage", + hide_comments: "hide-comments", + hide_secondary: "hide-secondary", + hide_related: "hide-related", + hide_sidebar: "hide-sidebar", + hide_top_bar_buttons: "hide-top-bar-buttons", }; function setHtmlAttr(attrName, state) { - document.documentElement.toggleAttribute(prefix + attr[attrName] + attrId, state); + document.documentElement.toggleAttribute( + prefix + attrName + attrId, + state + ); } function applyStyles() { - if (debug) console.log('Applying styles...'); - const html = document.documentElement; - const isHomepage = window.location.pathname === "/"; - try { - setHtmlAttr("minimalHomepage", options.minimalHomepage.value && isHomepage); - setHtmlAttr("hideComments", options.hideComments.value); - setHtmlAttr("hideSecondary", options.hideSecondary.value); - setHtmlAttr("hideRelated", options.hideRelated.value); - setHtmlAttr("hideSidebar", options.hideSidebar.value); - setHtmlAttr("hideTopBarButtons", options.hideTopBarButtons.value); - - if (options.minimalHomepage.value && isHomepage) { - if (!homeContainer) createHomeContainer(); - homeContainer.style.display = 'flex'; - } else if (homeContainer) { - homeContainer.style.display = 'none'; - } - } catch (e) { - if (debug) console.error('Error applying styles:', e); - } + setHtmlAttr(attr.is_homepage, window.location.pathname === "/"); + setHtmlAttr(attr.minimal_homepage, options.minimal_homepage.value); + setHtmlAttr(attr.hide_comments, options.hide_comments.value); + setHtmlAttr(attr.hide_secondary, options.hide_secondary.value); + setHtmlAttr(attr.hide_related, options.hide_related.value); + setHtmlAttr(attr.hide_sidebar, options.hide_sidebar.value); + setHtmlAttr( + attr.hide_top_bar_buttons, + options.hide_top_bar_buttons.value + ); } function createMenuItem(key) { const option = options[key]; - const item = document.createElement("div"); - item.className = "ytp-menuitem"; - - const icon = document.createElement("div"); - icon.className = "ytp-menuitem-icon"; - icon.innerHTML = option.icon; - - const label = document.createElement("div"); - label.className = "ytp-menuitem-label"; - label.textContent = option.label; - - const content = document.createElement("div"); - content.className = "ytp-menuitem-content"; - const toggleCheckbox = document.createElement("div"); - toggleCheckbox.className = "ytp-menuitem-toggle-checkbox"; - content.appendChild(toggleCheckbox); - - item.append(icon, label, content); - - item.setAttribute("aria-checked", option.value); + const item = create(/*html*/ ` +
+
${option.icon}
+
${option.label}
+
+
+
+
+ `); item.addEventListener("click", () => { - const newValue = !options[key].value; - item.setAttribute("aria-checked", newValue); - saveOption(key, newValue); + const value = !option.value; + item.setAttribute("aria-checked", value); + saveOption(key, value); + applyStyles(); + showToast(`${option.label} ${value ? "enabled" : "disabled"}`); }); - - menuItems[key] = item; return item; } function createPopup() { - popup = document.createElement("div"); - popup.className = "yt-minimal-popup-container"; - popup.style.display = "none"; - popup.setAttribute('role', 'dialog'); - popup.setAttribute('aria-modal', 'true'); - popup.setAttribute('tabindex', '-1'); - - const menu = document.createElement("div"); - menu.className = "yt-minimal-menu ytp-panel-menu"; - popup.appendChild(menu); + const container = create(/*html*/ ` + + `); + const menu = container.querySelector(".yt-minimal-menu"); for (const key in options) { - menu.appendChild(createMenuItem(key)); + menuItems[key] = menu.appendChild(createMenuItem(key)); } - document.body.appendChild(popup); - - popup.addEventListener('click', (e) => { - if (e.target === popup) togglePopup(); + container.addEventListener("click", (e) => { + if (e.target.contains(container)) togglePopup(); }); - popup.addEventListener('keydown', (e) => { - if (e.key === 'Escape') { + + window.addEventListener("keydown", (e) => { + if (e.key === "Escape" && document.body.contains(container)) { e.preventDefault(); togglePopup(); } }); + + return container; } function togglePopup() { - if (!popup) createPopup(); - const isHidden = popup.style.display === "none"; - popup.style.display = isHidden ? "flex" : "none"; - if (!isHidden) return; - popup.focus(); + const body = document.body; + if (body.contains(popup)) popup.remove(); + else body.append(popup); } function createHomeContainer() { - const app = document.querySelector('ytd-app'); - if (!app) { - if (debug) console.error('ytd-app not found'); - return; + const container = create(/*html*/ ` +
+
+ +
+
+
+ + +
+
+
+ `); + + const input = container.querySelector("input"); + const form = container.querySelector("form"); + const submit = create(``); + + function search(e) { + e.preventDefault(); + const value = input.value.trim(); + if (!value) return showToast("Enter a search term"); + + const searchForm = document.querySelector("form[action*=result]"); + const searchInput = searchForm.querySelector("input"); + searchInput.value = value; + searchForm.appendChild(submit).click(); } - homeContainer = document.createElement('div'); - homeContainer.className = 'home-container'; - homeContainer.style.display = 'none'; - - homeContainer.innerHTML = ` -
- -
-
- - -
- `; - app.appendChild(homeContainer); - - const input = homeContainer.querySelector(".search-input"); - const searchBtn = homeContainer.querySelector(".search-btn"); - - const search = () => { - const inputValue = input.value.trim(); - if (!inputValue) { - showToast("Enter a search term"); - return; - } - window.location.href = `https://www.youtube.com/results?search_query=${encodeURIComponent(inputValue)}`; - }; - input.addEventListener("keypress", (e) => { - if (e.key === "Enter") search(); - }); - searchBtn.addEventListener("click", search); + form.addEventListener("submit", search); + return container; } + const toast = create(`
`); + function showToast(message) { - const toast = document.createElement('div'); toast.textContent = message; - toast.className = 'yt-minimal-toast'; - document.body.appendChild(toast); + document.body.append(toast); setTimeout(() => toast.remove(), 2000); } - function init() { - loadOptions().then(() => { - const style = document.createElement("style"); - let cssText = ` - /* Popup Styles */ - .yt-minimal-popup-container { display: flex; justify-content: center; align-items: center; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.6); z-index: 9999; } - .yt-minimal-menu.ytp-panel-menu { background: var(--yt-spec-base-background, #181818); width: 400px; padding: 10px; fill: var(--yt-spec-text-primary, #eee); font-family: "Roboto", "Arial", sans-serif; border-radius: 12px; } - .ytp-menuitem { display: flex; align-items: center; padding: 12px; cursor: pointer; } - .ytp-menuitem:hover { background-color: var(--yt-spec-10-percent-layer, #383838); } - .ytp-menuitem-icon { width: 24px; height: 24px; margin-right: 16px; } - .ytp-menuitem-label { color: var(--yt-spec-text-primary, #eee); font-size: 14px; flex-grow: 1; } - .ytp-menuitem-content { margin-left: auto; } - .ytp-menuitem-toggle-checkbox { background-color: var(--yt-spec-text-disabled, rgb(144, 144, 144)); border-radius: 12px; height: 16px; width: 32px; position: relative; } - .ytp-menuitem-toggle-checkbox::after { background-color: var(--yt-spec-base-background, #181818); border-radius: 50%; content: ""; height: 24px; width: 24px; position: absolute; top: -4px; left: -2px; transition: left 0.1s cubic-bezier(0.4, 0, 1, 1); } - .ytp-menuitem[aria-checked=true] .ytp-menuitem-toggle-checkbox { background-color: var(--yt-spec-call-to-action, #6ea8ff); } - .ytp-menuitem[aria-checked=true] .ytp-menuitem-toggle-checkbox::after { left: 10px; } - - /* Minimal YouTube Styles */ - html[${prefix}minimal-homepage${attrId}], html[${prefix}minimal-homepage${attrId}] body { height: 100vh; background-color: var(--yt-spec-base-background, #0f0f0f); } - html[${prefix}minimal-homepage${attrId}] ytd-app > :not(.home-container) { display: none !important; } - .home-container { display: none; flex-direction: column; gap: 24px; align-items: center; justify-content: center; height: 100%; position: absolute; top: 0; left: 0; width: 100%; background: var(--yt-spec-base-background, #0f0f0f); z-index: 1000; } - .logo-full { width: 200px; margin-bottom: 20px; } - .search-group { height: 40px; display: flex; position: relative; } - .search-input { font-size: 16px; padding: 8px 16px; max-width: 500px; width: calc(100vw - 100px); border-radius: 40px 0 0 40px; border: 1px solid var(--yt-spec-10-percent-layer, #303030); background: var(--ytd-searchbox-background, #121212); color: var(--ytd-searchbox-text-color, white); } - .search-input:focus { outline: none; border-color: var(--yt-spec-call-to-action, #1c62b9); } - .search-btn { border: 1px solid var(--yt-spec-10-percent-layer, #303030); border-left: none; height: 40px; cursor: pointer; border-radius: 0 40px 40px 0; padding: 0 24px; background: var(--ytd-searchbox-legacy-button-color, #222222); } - .search-icon-container { height: 24px; width: 24px; fill: var(--yt-spec-icon-active-other, #909090); } - - /* Hide element styles */ - html[${prefix}hide-comments${attrId}] #comments { display: none !important; } - html[${prefix}hide-secondary${attrId}] #secondary { display: none !important; } - html[${prefix}hide-related${attrId}] #related { display: none !important; } - html[${prefix}hide-sidebar${attrId}] #guide, html[${prefix}hide-sidebar${attrId}] tp-yt-app-drawer, html[${prefix}hide-sidebar${attrId}] ytd-mini-guide-renderer { display: none !important; } - html[${prefix}hide-top-bar-buttons${attrId}] #guide-button, html[${prefix}hide-top-bar-buttons${attrId}] #voice-search-button, html[${prefix}hide-top-bar-buttons${attrId}] .ytd-masthead #end #buttons { display: none !important; } - /* FIX: Reclaim sidebar space */ - html[${prefix}hide-sidebar${attrId}] ytd-page-manager.ytd-app { margin-left: 0 !important; } - - /* FIX: Overlapping Playlist */ - html[${prefix}hide-sidebar${attrId}] ytd-browse[role=main] ytd-playlist-header-renderer:not([hidden]), - html[${prefix}hide-sidebar${attrId}] ytd-browse[role=main] yt-page-header-renderer:not([hidden]) { left: 0 !important; } - - /* Toast */ - .yt-minimal-toast { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: var(--yt-spec-base-background, #181818); color: var(--yt-spec-text-primary, #eee); padding: 10px 20px; border-radius: 4px; z-index: 10000; opacity: 0.9; transition: opacity 0.3s; } - - /* Responsive */ - @media (max-width: 600px) { - .logo-full { width: 150px; } - .search-input { width: 100%; max-width: none; border-radius: 40px 40px 0 0; } - .search-btn { border-radius: 0 0 40px 40px; border-top: none; width: 100%; padding: 8px; } - .search-group { flex-direction: column; height: auto; } - } - `; - style.textContent = cssText; - document.head.appendChild(style); - - window.addEventListener("keydown", (e) => { - if (e.key.toLowerCase() === "b" && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA') { - e.preventDefault(); - e.stopPropagation(); - togglePopup(); - } - }, true); - - window.addEventListener('yt-navigate-finish', applyStyles); - window.addEventListener('popstate', applyStyles); - window.addEventListener('hashchange', applyStyles); + function isActiveEditable() { + const active = document.activeElement; + return ( + active.tagName === "TEXTAREA" || + active.tagName === "INPUT" || + active.isContentEditable + ); + } - for (const key in options) { - GM_addValueChangeListener(key, (name, old_value, new_value, remote) => { - if (remote) { - options[key].value = new_value; - applyStyles(); - if (menuItems[key]) { - menuItems[key].setAttribute('aria-checked', new_value); - } - } - }); + function initCSS() { + const css = document.head.appendChild(document.createElement("style")); + css.textContent = /* css */ ` + /* Popup Styles */ + .yt-minimal-popup-container { display: flex; justify-content: center; align-items: center; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.6); z-index: 9999; } + .yt-minimal-menu.ytp-panel-menu { background: var(--yt-spec-base-background, #181818); width: 400px; padding: 10px; fill: var(--yt-spec-text-primary, #eee); font-family: "Roboto", "Arial", sans-serif; border-radius: 12px; } + .ytp-menuitem { display: flex; align-items: center; padding: 12px; cursor: pointer; } + .ytp-menuitem:hover { background-color: var(--yt-spec-10-percent-layer, #383838); } + .ytp-menuitem-icon { width: 24px; height: 24px; margin-right: 16px; } + .ytp-menuitem-label { color: var(--yt-spec-text-primary, #eee); font-size: 14px; flex-grow: 1; } + .ytp-menuitem-content { margin-left: auto; } + .ytp-menuitem-toggle-checkbox { background-color: var(--yt-spec-text-disabled, rgb(144, 144, 144)); border-radius: 12px; height: 16px; width: 32px; position: relative; } + .ytp-menuitem-toggle-checkbox::after { background-color: var(--yt-spec-base-background, #181818); border-radius: 50%; content: ""; height: 24px; width: 24px; position: absolute; top: -4px; left: -2px; transition: left 0.1s cubic-bezier(0.4, 0, 1, 1); } + .ytp-menuitem[aria-checked=true] .ytp-menuitem-toggle-checkbox { background-color: var(--yt-spec-call-to-action, #6ea8ff); } + .ytp-menuitem[aria-checked=true] .ytp-menuitem-toggle-checkbox::after { left: 10px; } + + /* Minimal YouTube Styles */ + html[is-homepage][minimal-homepage], html[is-homepage][minimal-homepage] body { overflow: hidden !important; height: 100vh; background-color: var(--yt-spec-base-background, #0f0f0f); } + html[is-homepage][minimal-homepage] ytd-app > :not(.home-container):not(yt-page-navigation-progress) { display: none !important; } + html[is-homepage][minimal-homepage] .home-container { display: flex !important; } + .home-container { display: none; flex-direction: column; gap: 24px; align-items: center; justify-content: center; height: 100%; position: absolute; top: 0; left: 0; width: 100%; background: var(--yt-spec-base-background, #0f0f0f); z-index: 1000; } + .logo-full { width: 200px; margin-bottom: 20px; } + .search-group { height: 40px; display: flex; position: relative; } + .search-input { font-size: 16px; padding: 8px 16px; max-width: 500px; width: calc(100vw - 100px); border-radius: 40px 0 0 40px; border: 1px solid var(--yt-spec-10-percent-layer, #303030); background: var(--ytd-searchbox-background, #121212); color: var(--ytd-searchbox-text-color, white); } + .search-input:focus { outline: none; border-color: var(--yt-spec-call-to-action, #1c62b9); } + .search-btn { border: 1px solid var(--yt-spec-10-percent-layer, #303030); border-left: none; height: 40px; cursor: pointer; border-radius: 0 40px 40px 0; padding: 0 24px; background: var(--ytd-searchbox-legacy-button-color, #222222); } + .search-icon-container { height: 24px; width: 24px; fill: var(--yt-spec-icon-active-other, #909090); } + + /* Hide element styles */ + html[hide-comments] #comments { display: none !important; } + html[hide-secondary] #secondary { display: none !important; } + html[hide-related] #related { display: none !important; } + html[hide-sidebar] #guide, html[hide-sidebar] tp-yt-app-drawer, html[hide-sidebar] ytd-mini-guide-renderer { display: none !important; } + html[hide-top-bar-buttons] #guide-button, html[hide-top-bar-buttons] #voice-search-button, html[hide-top-bar-buttons] .ytd-masthead #end #buttons { display: none !important; } + /* FIX: Reclaim sidebar space */ + html[hide-sidebar] ytd-page-manager.ytd-app { margin-left: 0 !important; } + + /* FIX: Overlapping Playlist */ + html[hide-sidebar] ytd-browse[role=main] ytd-playlist-header-renderer:not([hidden]), + html[hide-sidebar] ytd-browse[role=main] yt-page-header-renderer:not([hidden]) { left: 0 !important; } + + /* Toast */ + .yt-minimal-toast { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: var(--yt-spec-base-background, #181818); color: var(--yt-spec-text-primary, #eee); padding: 10px 20px; border-radius: 4px; z-index: 10000; opacity: 0.9; transition: opacity 0.3s; } + + /* Responsive */ + @media (max-width: 600px) { + .logo-full { width: 150px; } + .search-input { width: 100%; max-width: none; border-radius: 40px 40px 0 0; } + .search-btn { border-radius: 0 0 40px 40px; border-top: none; width: 100%; padding: 8px; } + .search-group { flex-direction: column; height: auto; } } + `; - applyStyles(); - }); + for (const key in attr) { + css.textContent = css.textContent.replaceAll( + "[" + attr[key] + "]", + "[" + prefix + attr[key] + attrId + "]" + ); + } } - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', init); - } else { - init(); + async function init() { + initCSS(); + await loadOptions(); + applyStyles(); + + function keyTogglePopup(e) { + if ( + !e.ctrlKey && + e.key.toLowerCase() === "b" && + !isActiveEditable() + ) { + togglePopup(); + } + } + + async function syncOptions() { + await loadOptions(); + applyStyles(); + for (const key in options) { + menuItems[key].setAttribute("aria-checked", options[key].value); + } + } + + window.addEventListener("keydown", keyTogglePopup, true); + window.addEventListener("yt-navigate-finish", applyStyles); + window.addEventListener("popstate", applyStyles); + window.addEventListener("focus", syncOptions); } + + new MutationObserver((_, observe) => { + const app = document.querySelector("ytd-app"); + + if (app) { + observe.disconnect(); + document.body.append(homeContainer); + init(); + } + }).observe(document, { subtree: true, childList: true }); })(); From b9d2ba5eb718b9625ebf80e4f88f1c56502db9e7 Mon Sep 17 00:00:00 2001 From: fznhq <55099255+fznhq@users.noreply.github.com> Date: Sun, 21 Sep 2025 02:15:29 +0700 Subject: [PATCH 6/6] Fix YT logo in light mode and revet loadOptions back to callback --- Youtube_Minimal_Plus.user.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Youtube_Minimal_Plus.user.js b/Youtube_Minimal_Plus.user.js index b6e2c86..7bd6e32 100644 --- a/Youtube_Minimal_Plus.user.js +++ b/Youtube_Minimal_Plus.user.js @@ -170,7 +170,7 @@ const container = create(/*html*/ `
- +
@@ -242,7 +242,7 @@ html[is-homepage][minimal-homepage] ytd-app > :not(.home-container):not(yt-page-navigation-progress) { display: none !important; } html[is-homepage][minimal-homepage] .home-container { display: flex !important; } .home-container { display: none; flex-direction: column; gap: 24px; align-items: center; justify-content: center; height: 100%; position: absolute; top: 0; left: 0; width: 100%; background: var(--yt-spec-base-background, #0f0f0f); z-index: 1000; } - .logo-full { width: 200px; margin-bottom: 20px; } + .logo-full { width: 200px; margin-bottom: 20px; color: var(--yt-spec-wordmark-text); } .search-group { height: 40px; display: flex; position: relative; } .search-input { font-size: 16px; padding: 8px 16px; max-width: 500px; width: calc(100vw - 100px); border-radius: 40px 0 0 40px; border: 1px solid var(--yt-spec-10-percent-layer, #303030); background: var(--ytd-searchbox-background, #121212); color: var(--ytd-searchbox-text-color, white); } .search-input:focus { outline: none; border-color: var(--yt-spec-call-to-action, #1c62b9); } @@ -282,10 +282,8 @@ } } - async function init() { + function init() { initCSS(); - await loadOptions(); - applyStyles(); function keyTogglePopup(e) { if ( @@ -305,10 +303,13 @@ } } - window.addEventListener("keydown", keyTogglePopup, true); - window.addEventListener("yt-navigate-finish", applyStyles); - window.addEventListener("popstate", applyStyles); - window.addEventListener("focus", syncOptions); + loadOptions().then(() => { + applyStyles(); + window.addEventListener("keydown", keyTogglePopup, true); + window.addEventListener("yt-navigate-finish", applyStyles); + window.addEventListener("popstate", applyStyles); + window.addEventListener("focus", syncOptions); + }); } new MutationObserver((_, observe) => {