您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
TOKIMEKIの「メディア」スタイルで投稿の本文や引用元をクリックした際に、その投稿の個別ページに移動できるようにします。
// ==UserScript== // @name TOKIMEKI メディアスタイル修復 // @namespace https://bsky.app/profile/neon-ai.art // @homepage https://bsky.app/profile/neon-ai.art // @icon data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🌈</text></svg> // @version 1.4 // @description TOKIMEKIの「メディア」スタイルで投稿の本文や引用元をクリックした際に、その投稿の個別ページに移動できるようにします。 // @author ねおん // @match https://tokimeki.blue/* // @grant none // @license CC BY-NC 4.0 // ==/UserScript== (function() { 'use strict'; // body全体にクリックイベントリスナーを設定して、動的に生成される要素に対応します。 // これで後から出てくるポップアップにも対応できるんですよ✨ document.body.addEventListener('click', function(e) { const dialog = e.target.closest('dialog.media-content-wrap'); const selection = window.getSelection(); // 以下の条件のどれか1つでも当てはまったら、何もしないで処理を終わります。 // 1. メディアビューのダイアログの外がクリックされた // 2. リアクションボタンやリンクなどがクリックされた // 3. テキストが選択されている if (!dialog || e.target.closest('.timeline-reaction, button, a') || (selection && !selection.isCollapsed) ) { return; } // クリックされた要素から一番近い[data-aturi]を持つ親要素を探します。 // これで、投稿の本文でも引用部分でも、どっちでもいけます! const postElement = e.target.closest('[data-aturi]'); if (postElement) { const atUri = postElement.dataset.aturi; // atUriがちゃんと投稿のものかチェックします。 if (atUri && atUri.startsWith('at://') && atUri.includes('/app.bsky.feed.post/')) { // atUriをtokimeki.blueのURLに変換します。 const parts = atUri.replace('at://', '').split('/'); const did = parts[0]; const rkey = parts[2]; const postUrl = `https://tokimeki.blue/profile/${did}/post/${rkey}`; // 本来のクリックイベントを止めて、同じタブでURLを書き換えます。 // これでメディアビューを閉じて、投稿のページに移動します🐾 e.preventDefault(); e.stopPropagation(); window.location.href = postUrl; } } }, true); // キャプチャフェーズでイベントを捕捉して、他のイベントより先に動くようにします。 })();