Skip to content

Instantly share code, notes, and snippets.

@roflsunriz
Last active April 24, 2025 15:15
Show Gist options
  • Save roflsunriz/31e3b65acd467e4d852423dc178d3c9b to your computer and use it in GitHub Desktop.
Save roflsunriz/31e3b65acd467e4d852423dc178d3c9b to your computer and use it in GitHub Desktop.
fanbox_floating_menu : Fanboxのページ移動用フローティングメニューを追加
// ==UserScript==
// @name Fanbox Floating Menu
// @namespace fanboxFloatingMenu
// @version 1.5
// @description Fanboxのページ移動用フローティングメニューを追加
// @author roflsunriz
// @match https://*.fanbox.cc/*
// @grant none
// @updateURL https://gist.githubusercontent.com/roflsunriz/31e3b65acd467e4d852423dc178d3c9b/raw/fanbox_floating_menu.user.js
// @downloadURL https://gist.githubusercontent.com/roflsunriz/31e3b65acd467e4d852423dc178d3c9b/raw/fanbox_floating_menu.user.js
// @icon https://www.google.com/s2/favicons?sz=64&domain=fanbox.cc
// ==/UserScript==
(function() {
'use strict';
// 現在のURLを保存
let currentUrl = location.href;
// フローティングメニューを作成する関数
function createFloatingMenu(originalMenu) {
const menu = originalMenu.cloneNode(true);
menu.classList.add('floating-menu');
menu.style.position = 'fixed';
menu.style.left = '0';
menu.style.top = '50%';
menu.style.transform = 'translateY(-50%)';
menu.style.zIndex = '1000';
menu.style.backgroundColor = 'rgba(255, 255, 255, 0.9)';
menu.style.padding = '10px';
menu.style.borderRadius = '0 5px 5px 0';
menu.style.boxShadow = '2px 2px 5px rgba(0,0,0,0.2)';
menu.style.display = 'flex';
menu.style.flexDirection = 'column';
menu.style.gap = '10px';
// 各リンクと特定のdiv要素のスタイルを調整
const links = menu.querySelectorAll('a, div[class*="FooterLinks__PrevPostWrapper-sc-"], div[class*="FooterLinks__NextPostWrapper-sc-"]');
links.forEach(link => {
link.style.padding = '5px 10px';
link.style.borderRadius = '3px';
link.style.textDecoration = 'none';
link.style.color = '#333';
link.style.transition = 'background-color 0.2s';
// ホバー時のスタイル
link.addEventListener('mouseenter', () => {
link.style.backgroundColor = 'rgba(0,0,0,0.1)';
});
link.addEventListener('mouseleave', () => {
link.style.backgroundColor = 'transparent';
});
});
return menu;
}
function waitForMenu(selector, timeout = 5000) {
return new Promise((resolve, reject) => {
const startTime = Date.now();
const checkInterval = 100;
const checkMenu = () => {
const menu = document.querySelector(selector);
if (menu) {
resolve(menu);
} else if (Date.now() - startTime >= timeout) {
reject(new Error('メニューが見つかりません'));
} else {
setTimeout(checkMenu, checkInterval);
}
};
checkMenu();
});
}
// メニューを初期化または更新する関数
async function initOrUpdateMenu() {
try {
// メニューが表示されるまで最大5秒待つ
const originalMenu = await waitForMenu('[class*="FooterLinks__Wrapper-sc-"]');
// 既存のメニューを削除
const oldMenu = document.querySelector('.floating-menu');
if (oldMenu) oldMenu.remove();
// 新しいメニューを作成
const menu = createFloatingMenu(originalMenu);
document.body.appendChild(menu);
} catch (error) {
console.error('フローティングメニューを表示できませんでした:', error);
}
}
// History APIをオーバーライドして、URL変更を検知する
const originalPushState = history.pushState;
const originalReplaceState = history.replaceState;
history.pushState = function() {
originalPushState.apply(this, arguments);
handleUrlChange();
};
history.replaceState = function() {
originalReplaceState.apply(this, arguments);
handleUrlChange();
};
// URL変更時の処理
function handleUrlChange() {
if (currentUrl !== location.href) {
currentUrl = location.href;
// URLが変わったらメニューを更新
setTimeout(initOrUpdateMenu, 500); // 少し遅延させてDOMの更新を待つ
}
}
// popstateイベント(ブラウザの戻る・進むボタン)のリスナー
window.addEventListener('popstate', function() {
handleUrlChange();
});
// 最初のロード時
window.addEventListener('load', initOrUpdateMenu);
})();
@roflsunriz
Copy link
Author

Rawボタンを押してTampermonkeyにインストール。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment