ブックマーカー図鑑ツールチップ
by
Lhankor_Mhy
14 hours ago [2026/07/30 15:53:55]
はてブで https://bookmarker-encyclopedia.netlify.app のキャッチフレーズをツールチップで表示します。アイコンの上で2秒ぐらいホバーしてください。
@@ -1,6 +1,6 @@
// ==UserScript==
-// @title ブックマーカー図鑑ツールチップ
// @name ブックマーカー図鑑ツールチップ
+// @title ブックマーカー図鑑ツールチップ
// @namespace https://let.hatelabo.jp/Lhankor_Mhy/let/laGdx-DigsAA
// @version 0.1
// @description はてブで https://bookmarker-encyclopedia.netlify.app のキャッチフレーズをツールチップで表示します。
@@ -29,7 +29,7 @@
// document.querySelectorAll('a:has(img[src*="profile.png"])')
document.body.insertAdjacentHTML('beforeend', `
<div id="${ID}" popover>...</div>
- <style>
+ <style>
#${ID} {
--ink: #1c1a17;
--paper: #f5f0e6;
@@ -62,18 +62,20 @@
height: 0px;
overflow: hidden;
- interest-delay: 2s .1s;
- --interest-delay: 2s .1s;
-
&:popover-open {
height: auto;
opacity: 1;
@starting-style {
height: 0px;
opacity: .5;
- }
+ }
}
}
+
+ [interestfor="${ID}"] {
+ interest-delay: 2s .1s;
+ --interest-delay: 2s .1s;
+ }
</style>
`);
const tooltip = document.getElementById(ID);
// ==UserScript==
// @name ブックマーカー図鑑ツールチップ
// @title ブックマーカー図鑑ツールチップ
// @namespace https://let.hatelabo.jp/Lhankor_Mhy/let/laGdx-DigsAA
// @version 0.1
// @description はてブで https://bookmarker-encyclopedia.netlify.app のキャッチフレーズをツールチップで表示します。
// @author Lhankor_Mhy
// @match https://b.hatena.ne.jp/entry/*
// @icon https://b.hatena.ne.jp/favicon.ico
// @license CC0
// @noframes
// @grant none
// ==/UserScript==
(async function () {
'use strict';
const ID = "bookmarker-encyclopedia-tooltip";
// polyfill for interestfor
const supported = Object.hasOwn(
HTMLButtonElement.prototype,
"interestForElement",
);
if (!supported) {
await import('https://cdn.jsdelivr.net/npm/interestfor@1.0.8/src/interestfor.min.js');
}
// insert tooltip elements and styles
// document.querySelectorAll('a:has(img[src*="profile.png"])')
document.body.insertAdjacentHTML('beforeend', `
<div id="${ID}" popover>...</div>
<style>
#${ID} {
--ink: #1c1a17;
--paper: #f5f0e6;
--card: #fffdf7;
--gold: #b8893a;
--gold-soft: #e8d9b5;
--accent: #2f6f6b;
--danger: #b14a3b;
--muted: #8a8071;
--line: #d8cdb4;
font-size: 0.8rem;
font-weight: 700;
color: var(--gold);
max-width: 700px;
margin: -7px;
background: var(--card);
border: 3px solid var(--ink);
border-radius: 7px;
box-shadow: 10px 12px 0 rgba(28, 26, 23, .18);
opacity: .5;
position-area: center span-right;
align-self: start;
transition: all .7s .2s allow-discrete;
interpolate-size: allow-keywords;
width: fit-content;
height: 0px;
overflow: hidden;
&:popover-open {
height: auto;
opacity: 1;
@starting-style {
height: 0px;
opacity: .5;
}
}
}
[interestfor="${ID}"] {
interest-delay: 2s .1s;
--interest-delay: 2s .1s;
}
</style>
`);
const tooltip = document.getElementById(ID);
function init() {
// add interest invokers
document.querySelectorAll('.entry-user-icon').forEach(icon => {
icon.setAttribute('interestfor', tooltip.id);
})
}
// add interest event listener
tooltip.addEventListener("interest", async (e) => {
const icon = e.source;
const userId = icon.getAttribute('href').split('/')[1].toLowerCase();
let profile = localStorage.getItem(`bookmarker-encyclopedia_profile_${userId}`);
if (!profile) {
const response = await fetch(`https://bookmarker-encyclopedia.netlify.app/api/profiles/${userId}.json`);
if (!response.ok) return;
profile = await response.text();
localStorage.setItem(`bookmarker-encyclopedia_profile_${userId}`, profile);
}
const { generated: { catchphrase } } = JSON.parse(profile);
tooltip.textContent = catchphrase;
const clonedIcon = icon.cloneNode(true);
clonedIcon.setAttribute('interestfor', null);
tooltip.insertBefore(clonedIcon, tooltip.firstChild);
});
tooltip.addEventListener("loseinterest", (e) => {
tooltip.textContent = "...";
});
// add mutation observer for lazy-loaded bookmarks
const targetNode = document.querySelector('.js-bookmarks-recent');
const mutationConfig = { childList: true };
const mutationCallback = function (mutationsList, observer) {
for (const mutation of mutationsList) {
if (mutation.type === 'childList') {
init();
}
}
};
const mutationObserver = new MutationObserver(mutationCallback);
mutationObserver.observe(targetNode, mutationConfig);
init();
})();
- Permalink
- このページへの個別リンクです。
- RAW
- 書かれたコードへの直接のリンクです。
- Packed
- 文字列が圧縮された書かれたコードへのリンクです。
- Userscript
- Greasemonkey 等で利用する場合の .user.js へのリンクです。
- Loader
- @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
- Metadata
- コード中にコメントで @xxx と書かれたメタデータの JSON です。