はてなパークス未読表示
by
Lhankor_Mhy
22 hours ago [2026/09/13 14:31:32]
未読の保存済みを右サイドに表示します。はてなパークスはSPAなのでブックマークレットとして使ってもいいかも。
@@ -3,7 +3,7 @@
// @name はてなパークス未読表示
// @namespace https://let.hatelabo.jp/Lhankor_Mhy/let/lb7m9qPigaAA
// @version 0.1
-// @description 未読の保存済みを右サイドに表示します。
+// @description 未読の保存済みを右サイドに表示します。はてなパークスはSPAなのでブックマークレットとして使ってもいいかも。
// @author Lhankor_Mhy
// @match https://p.hatena.ne.jp/*
// @icon https://p.hatena.ne.jp/icon.png
// ==UserScript==
// @title はてなパークス未読表示
// @name はてなパークス未読表示
// @namespace https://let.hatelabo.jp/Lhankor_Mhy/let/lb7m9qPigaAA
// @version 0.1
// @description 未読の保存済みを右サイドに表示します。はてなパークスはSPAなのでブックマークレットとして使ってもいいかも。
// @author Lhankor_Mhy
// @match https://p.hatena.ne.jp/*
// @icon https://p.hatena.ne.jp/icon.png
// @license CC0
// @grant none
// ==/UserScript==
{
function init() {
if (document.getElementById('unread-replies')) return;
const { version } = JSON.parse(document.querySelector('[data-page="app"]').textContent);
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;
const roundSurface = document.querySelector('aside[class^=_sidebar] [class^=_roundSurface]').cloneNode();
roundSurface.id = 'unread-replies';
roundSurface.insertAdjacentHTML('afterbegin', '<h3>未読の保存済み</h3>');
document.querySelector('aside[class^=_sidebar]')?.insertAdjacentElement('afterbegin', roundSurface);
(async () => {
const { props: { posts } } = await (
await fetch('https://p.hatena.ne.jp/my/favorites', {
headers: {
'X-inertia': 'true',
"X-Inertia-Version": version,
"X-XSRF-TOKEN": csrfToken
}
})
).json();
posts.forEach(({ park: { slug }, id, firstUnreadReplyId, title, unreadRepliesCount }) => {
if (unreadRepliesCount < 1) return;
const url = `/p/${slug}/t/${id}?to_reply=${firstUnreadReplyId}`;
const link = document.createElement('a');
link.href = url;
link.textContent = title;
link.style = `display: block;`;
link.addEventListener('click', (e) => {
e.preventDefault();
forceVisit(url);
});
roundSurface.append(link);
});
})();
}
function forceVisit(targetUrl) {
window.history.pushState({}, "", targetUrl);
const popStateEvent = new PopStateEvent('popstate', { state: window.history.state });
window.dispatchEvent(popStateEvent);
}
// add mutation observer for dynamic content loading
const targetNode = document.body;
const mutationConfig = { childList: true };
const mutationCallback = function (mutationsList, observer) {
for (const mutation of mutationsList) {
if (mutation.type === 'childList') {
console.log(mutation);
init();
}
}
};
const mutationObserver = new MutationObserver(mutationCallback);
mutationObserver.observe(targetNode, mutationConfig);
init();
}
- Permalink
- このページへの個別リンクです。
- RAW
- 書かれたコードへの直接のリンクです。
- Packed
- 文字列が圧縮された書かれたコードへのリンクです。
- Userscript
- Greasemonkey 等で利用する場合の .user.js へのリンクです。
- Loader
- @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
- Metadata
- コード中にコメントで @xxx と書かれたメタデータの JSON です。