mirror of
https://github.com/lawrencehook/remove-youtube-suggestions.git
synced 2026-07-25 06:54:31 +00:00
feat: add announcement banner to YouTube homepage and revamp reveal boxes
- Add shared banner system (src/shared/banners.js) for extensible banner config - Display RYS-branded announcement banner on YouTube homepage and options page - Banner pushes down YouTube page content with CSS variable for height - Revamp reveal suggestion boxes with polished two-row layout and RYS branding - Add per-surface reveal settings (homepage/sidebar/end-of-video) with migration - Consolidate colors and dimensions into CSS variables - Cache reveal box config at module level for performance Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
"/shared/main.js",
|
||||
"/shared/https.js",
|
||||
"/shared/utils.js",
|
||||
"/shared/banners.js",
|
||||
"/content-script/main.js"
|
||||
],
|
||||
"css": ["/content-script/main.css"],
|
||||
@@ -51,5 +52,9 @@
|
||||
],
|
||||
"host_permissions": [
|
||||
"*://*.youtube.com/*"
|
||||
]
|
||||
],
|
||||
"web_accessible_resources": [{
|
||||
"resources": ["/images/rys.svg"],
|
||||
"matches": ["*://*.youtube.com/*"]
|
||||
}]
|
||||
}
|
||||
|
||||
+220
-44
@@ -191,61 +191,139 @@ html[global_enable="true"] ytd-rich-grid-row[empty="true"] #contents {
|
||||
}
|
||||
|
||||
|
||||
/* Reveal suggestions button */
|
||||
.rys_reveal_button_container {
|
||||
width: auto;
|
||||
height: auto;
|
||||
/* Reveal suggestions box */
|
||||
.rys_reveal_box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
padding: 14px 18px;
|
||||
margin: auto;
|
||||
margin-top: 15%;
|
||||
background: var(--rys-primary);
|
||||
border-radius: 12px;
|
||||
font-size: 14px;
|
||||
font-family: var(--rys-font);
|
||||
z-index: 1000000;
|
||||
position: relative;
|
||||
width: fit-content;
|
||||
box-shadow: 0 4px 16px var(--rys-shadow);
|
||||
}
|
||||
|
||||
.rys_reveal_box * {
|
||||
color: var(--rys-text);
|
||||
}
|
||||
|
||||
.rys_reveal_header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid var(--rys-separator);
|
||||
}
|
||||
|
||||
.rys_reveal_button {
|
||||
position: relative;
|
||||
margin-top: 20%;
|
||||
font-size: 20px;
|
||||
padding: var(--yt-button-padding);
|
||||
|
||||
cursor: default;
|
||||
z-index: 1000000;
|
||||
|
||||
color: var(--yt-spec-text-primary);
|
||||
background-color: var(--yt-spec-base-background);
|
||||
border: 3px solid var(--yt-spec-raised-background);
|
||||
border-radius: var(--yt-button-border-radius);
|
||||
.rys_reveal_branding {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.rys_reveal_button:hover {
|
||||
background-color: var(--yt-spec-raised-background);
|
||||
}
|
||||
#close_reveal_button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 3px;
|
||||
|
||||
.rys_reveal_logo {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.rys_reveal_brand {
|
||||
font-weight: 600;
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.rys_reveal_actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.rys_reveal_content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
gap: 24px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.rys_reveal_message {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.rys_reveal_show {
|
||||
background: var(--rys-text);
|
||||
color: var(--rys-primary) !important;
|
||||
padding: 6px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
z-index: 1000001;
|
||||
color: var(--yt-spec-text-primary);
|
||||
font-size: 12px;
|
||||
}
|
||||
#close_reveal_button:hover {
|
||||
text-decoration: none;
|
||||
box-shadow: 0 2px 6px var(--rys-shadow);
|
||||
}
|
||||
|
||||
html:not([global_enable="true"]) #rys_homepage_reveal_button,
|
||||
html:not([add_reveal_button="true"]) #rys_homepage_reveal_button,
|
||||
html:not([remove_homepage="true"]) #rys_homepage_reveal_button,
|
||||
html:not([on_homepage="true"]) #rys_homepage_reveal_button,
|
||||
.rys_reveal_show:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
html:not([global_enable="true"]) #rys_sidebar_reveal_button,
|
||||
html:not([add_reveal_button="true"]) #rys_sidebar_reveal_button,
|
||||
html:not([remove_sidebar="true"]) #rys_sidebar_reveal_button,
|
||||
html:not([on_video="true"]) #rys_sidebar_reveal_button,
|
||||
.rys_reveal_dismiss {
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
opacity: 0.75;
|
||||
text-decoration: none;
|
||||
transition: opacity 0.15s ease;
|
||||
}
|
||||
|
||||
html:not([global_enable="true"]) #rys_end_of_video_reveal_button,
|
||||
html:not([add_reveal_button="true"]) #rys_end_of_video_reveal_button,
|
||||
html:not([remove_end_of_video="true"]) #rys_end_of_video_reveal_button,
|
||||
html:not([on_video="true"]) #rys_end_of_video_reveal_button,
|
||||
#movie_player:not(.ended-mode) #rys_end_of_video_reveal_button,
|
||||
.rys_reveal_dismiss:hover {
|
||||
opacity: 1;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.rys_reveal_close {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 11px;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
opacity: 0.6;
|
||||
line-height: 1;
|
||||
color: var(--rys-text);
|
||||
transition: opacity 0.15s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.rys_reveal_close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
html:not([global_enable="true"]) #rys_homepage_reveal_box,
|
||||
html:not([add_reveal_homepage="true"]) #rys_homepage_reveal_box,
|
||||
html:not([remove_homepage="true"]) #rys_homepage_reveal_box,
|
||||
html:not([on_homepage="true"]) #rys_homepage_reveal_box,
|
||||
|
||||
html:not([global_enable="true"]) #rys_sidebar_reveal_box,
|
||||
html:not([add_reveal_sidebar="true"]) #rys_sidebar_reveal_box,
|
||||
html:not([remove_sidebar="true"]) #rys_sidebar_reveal_box,
|
||||
html:not([on_video="true"]) #rys_sidebar_reveal_box,
|
||||
|
||||
html:not([global_enable="true"]) #rys_end_of_video_reveal_box,
|
||||
html:not([add_reveal_end_of_video="true"]) #rys_end_of_video_reveal_box,
|
||||
html:not([remove_end_of_video="true"]) #rys_end_of_video_reveal_box,
|
||||
html:not([on_video="true"]) #rys_end_of_video_reveal_box,
|
||||
#movie_player:not(.ended-mode) #rys_end_of_video_reveal_box,
|
||||
|
||||
html[foo="bar"] {
|
||||
display: none;
|
||||
@@ -399,4 +477,102 @@ html[global_enable="true"][foo=bar]
|
||||
|
||||
html[global_enable='true'][grayscale_mode='true'] ytd-app {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
}
|
||||
|
||||
/* RYS UI Variables */
|
||||
:root {
|
||||
--rys-primary: #065fd4;
|
||||
--rys-text: #fff;
|
||||
--rys-separator: rgba(255, 255, 255, 0.15);
|
||||
--rys-shadow: rgba(0, 0, 0, 0.15);
|
||||
--rys-font: "Roboto", "Arial", sans-serif;
|
||||
--rys-banner-height: 40px;
|
||||
}
|
||||
|
||||
/* Announcement Banner on YouTube */
|
||||
.rys_announcement_banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 16px;
|
||||
background: var(--rys-primary);
|
||||
font-size: 13px;
|
||||
font-family: var(--rys-font);
|
||||
z-index: 2350;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/* Push down YouTube's fixed header and content when banner is visible */
|
||||
html[rys-banner-visible="true"] #masthead-container,
|
||||
html[rys-banner-visible="true"] ytd-masthead {
|
||||
top: var(--rys-banner-height) !important;
|
||||
}
|
||||
|
||||
html[rys-banner-visible="true"] ytd-app {
|
||||
margin-top: var(--rys-banner-height);
|
||||
}
|
||||
|
||||
html[rys-banner-visible="true"] tp-yt-app-drawer #contentContainer,
|
||||
html[rys-banner-visible="true"] ytd-mini-guide-renderer {
|
||||
margin-top: var(--rys-banner-height);
|
||||
}
|
||||
|
||||
.rys_announcement_banner * {
|
||||
color: var(--rys-text);
|
||||
}
|
||||
|
||||
.rys_banner_logo {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.rys_banner_brand {
|
||||
font-weight: 600;
|
||||
margin-right: 8px;
|
||||
padding-right: 12px;
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.rys_banner_message {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.rys_banner_link {
|
||||
text-decoration: underline;
|
||||
opacity: 0.9;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.rys_banner_link:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.rys_banner_dismiss {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.rys_banner_dismiss:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.rys_banner_close {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
padding: 0 4px;
|
||||
opacity: 0.7;
|
||||
line-height: 1;
|
||||
color: var(--rys-text);
|
||||
}
|
||||
|
||||
.rys_banner_close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
+80
-38
@@ -19,6 +19,31 @@ const subsRegex = new RegExp(/\/feed\/subscriptions$/, 'i');
|
||||
|
||||
// Dynamic settings variables
|
||||
const cache = {};
|
||||
const closedRevealBoxes = new Set();
|
||||
const rysLogoUrl = browser.runtime.getURL('images/rys.svg');
|
||||
const REVEAL_BOX_CONFIGS = [
|
||||
{
|
||||
containerSelector: 'ytd-page-manager',
|
||||
boxId: 'rys_homepage_reveal_box',
|
||||
message: 'Homepage suggestions are hidden.',
|
||||
showAction: () => HTML.setAttribute('remove_homepage', false),
|
||||
revealSetting: 'add_reveal_homepage',
|
||||
},
|
||||
{
|
||||
containerSelector: '#secondary-inner',
|
||||
boxId: 'rys_sidebar_reveal_box',
|
||||
message: 'Sidebar suggestions are hidden.',
|
||||
showAction: () => HTML.setAttribute('remove_sidebar', false),
|
||||
revealSetting: 'add_reveal_sidebar',
|
||||
},
|
||||
{
|
||||
containerSelector: '#movie_player',
|
||||
boxId: 'rys_end_of_video_reveal_box',
|
||||
message: 'End-of-video suggestions are hidden.',
|
||||
showAction: () => HTML.setAttribute('remove_end_of_video', false),
|
||||
revealSetting: 'add_reveal_end_of_video',
|
||||
},
|
||||
];
|
||||
let url = location.href;
|
||||
let theaterClicked = false, hyper = false;
|
||||
let onResultsPage = resultsPageRegex.test(url);
|
||||
@@ -62,6 +87,11 @@ browser.storage.onChanged.addListener(logStorageChange);
|
||||
browser.storage.local.get(settings => {
|
||||
if (!settings) return;
|
||||
|
||||
const revealUpdates = migrateRevealSettings(settings);
|
||||
if (Object.keys(revealUpdates).length) {
|
||||
browser.storage.local.set(revealUpdates);
|
||||
}
|
||||
|
||||
Object.entries({ ...DEFAULT_SETTINGS, ...settings}).forEach(([ id, value ]) => {
|
||||
HTML.setAttribute(id, value);
|
||||
cache[id] = value;
|
||||
@@ -478,51 +508,47 @@ function runDynamicSettings() {
|
||||
});
|
||||
}
|
||||
|
||||
// Reveal suggestions button
|
||||
const revealButtons = [
|
||||
{
|
||||
containerSelector: 'ytd-page-manager', buttonId: 'rys_homepage_reveal_button',
|
||||
innerText: 'Show homepage suggestions',
|
||||
clickListener: e => HTML.setAttribute('remove_homepage', false),
|
||||
},
|
||||
{
|
||||
containerSelector: '#secondary-inner', buttonId: 'rys_sidebar_reveal_button',
|
||||
innerText: 'Show sidebar suggestions',
|
||||
clickListener: e => HTML.setAttribute('remove_sidebar', false),
|
||||
},
|
||||
{
|
||||
containerSelector: '#movie_player', buttonId: 'rys_end_of_video_reveal_button',
|
||||
innerText: 'Show end-of-video suggestions',
|
||||
clickListener: e => HTML.setAttribute('remove_end_of_video', false),
|
||||
},
|
||||
];
|
||||
revealButtons.forEach(obj => {
|
||||
const { containerSelector, buttonId, innerText, clickListener } = obj;
|
||||
// Reveal suggestions boxes
|
||||
REVEAL_BOX_CONFIGS.forEach(({ containerSelector, boxId, message, showAction, revealSetting }) => {
|
||||
|
||||
const existingButton = qs(`#${buttonId}`);
|
||||
if (existingButton) return;
|
||||
if (closedRevealBoxes.has(boxId)) return;
|
||||
if (qs(`#${boxId}`)) return;
|
||||
|
||||
const container = qs(containerSelector);
|
||||
const buttonContainer = document.createElement('div');
|
||||
buttonContainer.classList.add('rys_reveal_button_container');
|
||||
if (!container) return;
|
||||
|
||||
const newButton = document.createElement('button');
|
||||
newButton.setAttribute('id', buttonId);
|
||||
newButton.classList.add('rys_reveal_button');
|
||||
newButton.innerText = innerText;
|
||||
newButton.addEventListener('click', clickListener);
|
||||
const box = document.createElement('div');
|
||||
box.id = boxId;
|
||||
box.className = 'rys_reveal_box';
|
||||
box.innerHTML = `
|
||||
<div class="rys_reveal_header">
|
||||
<div class="rys_reveal_branding">
|
||||
<img src="${rysLogoUrl}" alt="RYS" class="rys_reveal_logo">
|
||||
<span class="rys_reveal_brand">RYS</span>
|
||||
</div>
|
||||
<div class="rys_reveal_actions">
|
||||
<a class="rys_reveal_dismiss">Don't show again</a>
|
||||
<button class="rys_reveal_close" aria-label="Close">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rys_reveal_content">
|
||||
<span class="rys_reveal_message">${message}</span>
|
||||
<a class="rys_reveal_show">Reveal</a>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const closeButton = document.createElement('div');
|
||||
closeButton.setAttribute('id', 'close_reveal_button');
|
||||
closeButton.innerHTML = "✖";
|
||||
closeButton.addEventListener('click', e => {
|
||||
e.stopPropagation();
|
||||
updateSetting('add_reveal_button', false);
|
||||
box.querySelector('.rys_reveal_show')?.addEventListener('click', showAction);
|
||||
box.querySelector('.rys_reveal_dismiss')?.addEventListener('click', () => {
|
||||
if (revealSetting) {
|
||||
updateSetting(revealSetting, false);
|
||||
}
|
||||
});
|
||||
box.querySelector('.rys_reveal_close')?.addEventListener('click', () => {
|
||||
closedRevealBoxes.add(boxId);
|
||||
box.remove();
|
||||
});
|
||||
newButton.appendChild(closeButton);
|
||||
|
||||
buttonContainer.appendChild(newButton);
|
||||
container?.appendChild(buttonContainer);
|
||||
container.appendChild(box);
|
||||
});
|
||||
|
||||
// Expand the "You" section in the left sidebar
|
||||
@@ -557,6 +583,21 @@ function requestRunDynamicSettings() {
|
||||
}
|
||||
|
||||
|
||||
function injectAnnouncementBanners() {
|
||||
if (!onHomepage) return;
|
||||
if (!document.body) return;
|
||||
|
||||
const logoUrl = browser.runtime.getURL('images/rys.svg');
|
||||
const banners = getActiveBanners('youtube_homepage');
|
||||
|
||||
banners.forEach(banner => {
|
||||
initBanner(banner, logoUrl, () => ({
|
||||
element: document.body,
|
||||
insertMethod: 'prepend'
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function injectScripts() {
|
||||
const on = cache['global_enable'] === true;
|
||||
if (!on) return;
|
||||
@@ -651,6 +692,7 @@ function handleNewPage() {
|
||||
}
|
||||
|
||||
injectScripts();
|
||||
injectAnnouncementBanners();
|
||||
requestRunDynamicSettings();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"/shared/main.js",
|
||||
"/shared/https.js",
|
||||
"/shared/utils.js",
|
||||
"/shared/banners.js",
|
||||
"/content-script/main.js"
|
||||
],
|
||||
"css": ["/content-script/main.css"],
|
||||
@@ -52,5 +53,8 @@
|
||||
"permissions": [
|
||||
"storage",
|
||||
"*://*.youtube.com/*"
|
||||
],
|
||||
"web_accessible_resources": [
|
||||
"/images/rys.svg"
|
||||
]
|
||||
}
|
||||
@@ -300,7 +300,7 @@ html[foo=bar] {
|
||||
gap: 15px;
|
||||
}
|
||||
#password_lock_container button {
|
||||
color: black;
|
||||
color: var(--body-color);
|
||||
}
|
||||
|
||||
/* Password Modal */
|
||||
@@ -318,7 +318,7 @@ html[foo=bar] {
|
||||
}
|
||||
|
||||
#password_container_background button {
|
||||
color: black;
|
||||
color: var(--body-color);
|
||||
}
|
||||
|
||||
#enable_password_container, #enable_password_container * {
|
||||
@@ -382,7 +382,7 @@ html[foo=bar] {
|
||||
}
|
||||
|
||||
#password-button button {
|
||||
color: var(--body-background-color);
|
||||
color: var(--body-color);
|
||||
}
|
||||
|
||||
#disable_password_container a:first-child {
|
||||
|
||||
+22
-9
@@ -101,7 +101,7 @@ input:focus {
|
||||
}
|
||||
|
||||
/* Announcement Banner */
|
||||
#announcement_banner {
|
||||
.rys_announcement_banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
@@ -112,35 +112,48 @@ input:focus {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#announcement_banner * {
|
||||
.rys_announcement_banner * {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#announcement_banner span {
|
||||
.rys_banner_logo {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.rys_banner_brand {
|
||||
font-weight: 600;
|
||||
margin-right: 8px;
|
||||
padding-right: 12px;
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.rys_banner_message {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#announcement_banner a {
|
||||
.rys_banner_link {
|
||||
text-decoration: underline;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
#announcement_banner a:hover {
|
||||
.rys_banner_link:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#dismiss_announcement {
|
||||
.rys_banner_dismiss {
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#dismiss_announcement:hover {
|
||||
.rys_banner_dismiss:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#close_announcement {
|
||||
.rys_banner_close {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 18px;
|
||||
@@ -150,6 +163,6 @@ input:focus {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
#close_announcement:hover {
|
||||
.rys_banner_close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<script defer src="/shared/https.js"></script>
|
||||
<script defer src="/shared/analytics.js"></script>
|
||||
<script defer src="/shared/utils.js"></script>
|
||||
<script defer src="/shared/banners.js"></script>
|
||||
<script defer src="/options/reload.js"></script>
|
||||
<script defer src="/options/main.js"></script>
|
||||
<script defer src="/options/settings-menu.js"></script>
|
||||
@@ -230,12 +231,7 @@
|
||||
<button id='unlock-password-button'>Confirm</button>
|
||||
</div>
|
||||
|
||||
<div id="announcement_banner" hidden>
|
||||
<span>Premium features coming soon.</span>
|
||||
<a href="https://lawrencehook.com/rys/premium" target="_blank">Learn more</a>
|
||||
<a id="dismiss_announcement">Don't show again</a>
|
||||
<button id="close_announcement" aria-label="Close">×</button>
|
||||
</div>
|
||||
<div id="banner_container"></div>
|
||||
|
||||
<div id="main_container">
|
||||
|
||||
|
||||
+28
-19
@@ -24,6 +24,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
recordEvent('Page View: Options');
|
||||
initAnnouncementBanner();
|
||||
browser.storage.local.get(localSettings => {
|
||||
const revealUpdates = migrateRevealSettings(localSettings);
|
||||
if (Object.keys(revealUpdates).length) {
|
||||
browser.storage.local.set(revealUpdates);
|
||||
}
|
||||
|
||||
const settings = { ...DEFAULT_SETTINGS, ...localSettings };
|
||||
const headerSettings = Object.entries(OTHER_SETTINGS).reduce((acc, [id, value]) => {
|
||||
acc[id] = id in localSettings ? localSettings[id] : value;
|
||||
@@ -155,6 +160,19 @@ function populateOptions(SECTIONS, headerSettings, SETTING_VALUES) {
|
||||
|
||||
const searchBar = document.getElementById('search_bar');
|
||||
searchBar.addEventListener('input', onSearchInput);
|
||||
const searchInput = searchBar.querySelector('input');
|
||||
const focusSearchInput = () => {
|
||||
if (!searchInput) return;
|
||||
if (document.activeElement === searchInput) return;
|
||||
searchInput.focus();
|
||||
};
|
||||
focusSearchInput();
|
||||
setTimeout(focusSearchInput, 0);
|
||||
setTimeout(focusSearchInput, 50);
|
||||
window.addEventListener('focus', focusSearchInput);
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.visibilityState === 'visible') focusSearchInput();
|
||||
});
|
||||
|
||||
const turnBackOn = document.getElementById('turn_back_on');
|
||||
turnBackOn.addEventListener('click', e => {
|
||||
@@ -406,27 +424,18 @@ function timeLoop() {
|
||||
}
|
||||
|
||||
|
||||
// Announcement banner
|
||||
const ANNOUNCEMENT_KEY = 'announcement_dismissed_premium_coming';
|
||||
|
||||
// Announcement banners
|
||||
function initAnnouncementBanner() {
|
||||
const banner = document.getElementById('announcement_banner');
|
||||
const dismissBtn = document.getElementById('dismiss_announcement');
|
||||
const closeBtn = document.getElementById('close_announcement');
|
||||
if (!banner) return;
|
||||
const container = document.getElementById('banner_container');
|
||||
if (!container) return;
|
||||
|
||||
browser.storage.local.get(ANNOUNCEMENT_KEY, result => {
|
||||
if (!result[ANNOUNCEMENT_KEY]) {
|
||||
banner.removeAttribute('hidden');
|
||||
}
|
||||
});
|
||||
const logoUrl = browser.runtime.getURL('images/rys.svg');
|
||||
const banners = getActiveBanners('options');
|
||||
|
||||
dismissBtn?.addEventListener('click', () => {
|
||||
banner.setAttribute('hidden', '');
|
||||
browser.storage.local.set({ [ANNOUNCEMENT_KEY]: true });
|
||||
});
|
||||
|
||||
closeBtn?.addEventListener('click', () => {
|
||||
banner.setAttribute('hidden', '');
|
||||
banners.forEach(banner => {
|
||||
initBanner(banner, logoUrl, () => ({
|
||||
element: container,
|
||||
insertMethod: 'append'
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
// Shared banner configuration and utilities
|
||||
|
||||
const BANNERS = [
|
||||
{
|
||||
id: 'premium_coming',
|
||||
storageKey: 'announcement_dismissed_premium_coming',
|
||||
message: 'Premium features coming soon.',
|
||||
linkText: 'Learn more',
|
||||
linkUrl: 'https://lawrencehook.com/rys/premium',
|
||||
dismissText: "Don't show again",
|
||||
showOn: ['options', 'youtube_homepage'],
|
||||
},
|
||||
];
|
||||
|
||||
function createBannerHTML(banner, logoUrl) {
|
||||
const container = document.createElement('div');
|
||||
container.id = `rys_banner_${banner.id}`;
|
||||
container.className = 'rys_announcement_banner';
|
||||
container.innerHTML = `
|
||||
<img src="${logoUrl}" alt="RYS" class="rys_banner_logo">
|
||||
<span class="rys_banner_brand">RYS</span>
|
||||
<span class="rys_banner_message">${banner.message}</span>
|
||||
<a href="${banner.linkUrl}" target="_blank" class="rys_banner_link">${banner.linkText}</a>
|
||||
<a class="rys_banner_dismiss">${banner.dismissText}</a>
|
||||
<button class="rys_banner_close" aria-label="Close">×</button>
|
||||
`;
|
||||
return container;
|
||||
}
|
||||
|
||||
function initBanner(banner, logoUrl, getContainer) {
|
||||
const existingBanner = document.getElementById(`rys_banner_${banner.id}`);
|
||||
if (existingBanner) return;
|
||||
|
||||
browser.storage.local.get(banner.storageKey, result => {
|
||||
if (result[banner.storageKey]) return;
|
||||
|
||||
const container = getContainer();
|
||||
if (!container) return;
|
||||
|
||||
const bannerEl = createBannerHTML(banner, logoUrl);
|
||||
|
||||
// Insert banner
|
||||
if (container.insertMethod === 'prepend') {
|
||||
container.element.insertBefore(bannerEl, container.element.firstChild);
|
||||
} else {
|
||||
container.element.appendChild(bannerEl);
|
||||
}
|
||||
|
||||
// Mark that a banner is visible (for CSS adjustments)
|
||||
document.documentElement.setAttribute('rys-banner-visible', 'true');
|
||||
|
||||
// Event listeners
|
||||
const dismissBtn = bannerEl.querySelector('.rys_banner_dismiss');
|
||||
const closeBtn = bannerEl.querySelector('.rys_banner_close');
|
||||
|
||||
const removeBanner = () => {
|
||||
bannerEl.remove();
|
||||
// Check if any banners still visible
|
||||
if (!document.querySelector('.rys_announcement_banner')) {
|
||||
document.documentElement.removeAttribute('rys-banner-visible');
|
||||
}
|
||||
};
|
||||
|
||||
dismissBtn?.addEventListener('click', () => {
|
||||
removeBanner();
|
||||
browser.storage.local.set({ [banner.storageKey]: true });
|
||||
});
|
||||
|
||||
closeBtn?.addEventListener('click', () => {
|
||||
removeBanner();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getActiveBanners(location) {
|
||||
return BANNERS.filter(b => b.showOn.includes(location));
|
||||
}
|
||||
+40
-6
@@ -67,18 +67,17 @@ const SECTIONS = [
|
||||
id: "remove_end_of_video",
|
||||
defaultValue: true
|
||||
},
|
||||
{
|
||||
name: "Add a button to reveal suggestions",
|
||||
tags: "Homepage, Video Player",
|
||||
id: "add_reveal_button",
|
||||
defaultValue: true
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Homepage",
|
||||
tags: "Homepage",
|
||||
options: [
|
||||
{
|
||||
name: "Show reveal box for homepage suggestions",
|
||||
id: "add_reveal_homepage",
|
||||
defaultValue: true
|
||||
},
|
||||
{
|
||||
name: "Hide the header",
|
||||
id: "remove_header",
|
||||
@@ -269,6 +268,11 @@ const SECTIONS = [
|
||||
name: "Video Player - UI",
|
||||
tags: "Video Player",
|
||||
options: [
|
||||
{
|
||||
name: "Show reveal box for end-of-video suggestions",
|
||||
id: "add_reveal_end_of_video",
|
||||
defaultValue: true
|
||||
},
|
||||
{
|
||||
name: "Hide info cards",
|
||||
id: "remove_info_cards",
|
||||
@@ -320,6 +324,11 @@ const SECTIONS = [
|
||||
name: "Video Player - Sidebar",
|
||||
tags: "Video Player",
|
||||
options: [
|
||||
{
|
||||
name: "Show reveal box for sidebar suggestions",
|
||||
id: "add_reveal_sidebar",
|
||||
defaultValue: true
|
||||
},
|
||||
{
|
||||
name: "Center contents - removes the sidebar",
|
||||
id: "remove_entire_sidebar",
|
||||
@@ -613,6 +622,26 @@ const DEFAULT_SETTINGS = SECTIONS.reduce((acc, fieldset) => {
|
||||
return acc;
|
||||
}, { ...OTHER_SETTINGS });
|
||||
|
||||
// Migrate legacy add_reveal_button to per-surface settings
|
||||
function migrateRevealSettings(settings) {
|
||||
if (!settings || !('add_reveal_button' in settings)) return {};
|
||||
const val = settings.add_reveal_button;
|
||||
const updates = {};
|
||||
if (!('add_reveal_homepage' in settings)) {
|
||||
settings.add_reveal_homepage = val;
|
||||
updates.add_reveal_homepage = val;
|
||||
}
|
||||
if (!('add_reveal_sidebar' in settings)) {
|
||||
settings.add_reveal_sidebar = val;
|
||||
updates.add_reveal_sidebar = val;
|
||||
}
|
||||
if (!('add_reveal_end_of_video' in settings)) {
|
||||
settings.add_reveal_end_of_video = val;
|
||||
updates.add_reveal_end_of_video = val;
|
||||
}
|
||||
return updates;
|
||||
}
|
||||
|
||||
|
||||
// For import/export
|
||||
const idToShortId = {
|
||||
@@ -703,6 +732,11 @@ const idToShortId = {
|
||||
"shrink_video_thumbnails": '84',
|
||||
"password": '85',
|
||||
"hashed_password": '86',
|
||||
"add_reveal_homepage": '87',
|
||||
"add_reveal_sidebar": '88',
|
||||
"add_reveal_end_of_video": '89',
|
||||
"add_reveal_button": '90', // deprecated; migrated to add_reveal_* settings
|
||||
"remove_sidebar_infinite_scroll": '91',
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user