您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Increase or decrease the margins between the paragraphs in a work. Set on a per work or per author basis.
// ==UserScript== // @name AO3 Adjust Paragraph Margins // @description Increase or decrease the margins between the paragraphs in a work. Set on a per work or per author basis. // @author Ifky_ // @namespace https://greasyfork.org/en/scripts/542569 // @version 1.0.1 // @history 1.0.1 — Reset current setting when resetting everything // @history 1.0.0 — Increase or decrease the margin between a work's paragraphs // @match https://archiveofourown.org/works/* // @icon https://archiveofourown.org/images/logo.png // @license GPL-3.0-only // @grant none // ==/UserScript== "use strict"; (function () { // Add styles to increase or decrease margin // If you want to use different values, you can either edit this code or override it with a site skin const styleTag = document.createElement("style"); styleTag.textContent = ` #workskin.a-p-m--i [role=article] .userstuff p, #workskin.a-p-m--i [role=article].userstuff p { margin-block: 3.5em; } #workskin.a-p-m--d [role=article] .userstuff p, #workskin.a-p-m--d [role=article].userstuff p { margin-block: .15em; } #a-p-m fieldset { display: block; } #a-p-m fieldset ul { display: flex; gap: 1em; flex-wrap: wrap; } #a-p-m fieldset label { padding-inline: .75em !important; } `; document.head.appendChild(styleTag); // Get necessary elements and data const workskin = document.querySelector("#workskin"); const actions = document.querySelector("#main .work.actions"); const workId = window.location.pathname.split("/")[2]; const authorEl = document.querySelector("#workskin a[rel='author'][href*='/users/']"); const author = authorEl?.textContent ?? null; // Get existing settings from local storage const getLocal = (key) => { const value = localStorage.getItem(key); return new Set(value ? value.split(',') : []); }; const addLocal = (key, value) => { const local = getLocal(key); local.add(value); const string = Array.from(local).join(','); localStorage.setItem(key, string); }; const removeLocal = (key, value) => { const local = getLocal(key); local.delete(value); const string = Array.from(local).join(','); localStorage.setItem(key, string); }; // Get current settings (if they exist) const workIncrease = getLocal("a-p-m--w-i"); const workDecrease = getLocal("a-p-m--w-d"); const workStandard = getLocal("a-p-m--w-s"); const authorIncrease = getLocal("a-p-m--a-i"); const authorDecrease = getLocal("a-p-m--a-d"); let marginType; (function (marginType) { marginType[marginType["STANDARD"] = 0] = "STANDARD"; marginType[marginType["INCREASE"] = 1] = "INCREASE"; marginType[marginType["DECREASE"] = 2] = "DECREASE"; marginType[marginType["AUTHOR"] = 3] = "AUTHOR"; })(marginType || (marginType = {})); const setMarginClass = (value) => { switch (value) { case marginType.STANDARD: workskin.classList.remove("a-p-m--i"); workskin.classList.remove("a-p-m--d"); break; case marginType.INCREASE: workskin.classList.add("a-p-m--i"); workskin.classList.remove("a-p-m--d"); break; case marginType.DECREASE: workskin.classList.remove("a-p-m--i"); workskin.classList.add("a-p-m--d"); break; } }; const setMarginLocal = (key, value) => { if (key === "work") { switch (value) { case marginType.STANDARD: removeLocal("a-p-m--w-i", workId); removeLocal("a-p-m--w-d", workId); addLocal("a-p-m--w-s", workId); break; case marginType.INCREASE: addLocal("a-p-m--w-i", workId); removeLocal("a-p-m--w-d", workId); removeLocal("a-p-m--w-s", workId); break; case marginType.DECREASE: removeLocal("a-p-m--w-i", workId); addLocal("a-p-m--w-d", workId); removeLocal("a-p-m--w-s", workId); break; case marginType.AUTHOR: removeLocal("a-p-m--w-i", workId); removeLocal("a-p-m--w-d", workId); removeLocal("a-p-m--w-s", workId); break; } } else if (key === "author" && author !== null) { switch (value) { case marginType.STANDARD: removeLocal("a-p-m--a-i", author); removeLocal("a-p-m--a-d", author); break; case marginType.INCREASE: addLocal("a-p-m--a-i", author); removeLocal("a-p-m--a-d", author); break; case marginType.DECREASE: removeLocal("a-p-m--a-i", author); addLocal("a-p-m--a-d", author); break; } } }; // Set margin based on setting const wi = workIncrease.has(workId); const wd = workDecrease.has(workId); const ws = workStandard.has(workId); const wa = !(wi || wd || ws); const ai = authorIncrease.has(author); const ad = authorDecrease.has(author); const aSt = !(ai || ad); let workSetting = 0; let authorSetting = 0; if (wi) { workSetting = marginType.INCREASE; } else if (wd) { workSetting = marginType.DECREASE; } else if (wa) { workSetting = marginType.AUTHOR; } if (ai) { authorSetting = marginType.INCREASE; } else if (ad) { authorSetting = marginType.DECREASE; } if (workSetting !== marginType.AUTHOR) { setMarginClass(workSetting); } else { setMarginClass(authorSetting); } if (actions) { // The HTML for the action button and expandable secondary const marginHtml = ` <li id="a-p-m" aria-haspopup="true"> <a id="a-p-m--toggle" href="#" class="collapsed">Margins</a> <ul id="a-p-m--secondary" class="expandable secondary hidden"> <form id="a-p-m--form" class="verbose"> <!-- Work settings --> <fieldset> <legend>Work settings</legend> <ul> <li> <input type="radio" value="0" ${ws ? 'checked="checked"' : ''} name="a-p-m--w" id="a-p-m--w-s"> <label for="a-p-m--w-s">Standard</label> </li> <li> <input type="radio" value="1" ${wi ? 'checked="checked"' : ''} name="a-p-m--w" id="a-p-m--w-i"> <label for="a-p-m--w-i">Increase</label> </li> <li> <input type="radio" value="2" ${wd ? 'checked="checked"' : ''} name="a-p-m--w" id="a-p-m--w-d"> <label for="a-p-m--w-d">Decrease</label> </li> <li> <input type="radio" value="3" ${wa ? 'checked="checked"' : ''} name="a-p-m--w" id="a-p-m--w-a"> <label for="a-p-m--w-a">Author</label> </li> </ul> </fieldset> <!-- Author settings --> ${author ? `<fieldset> <legend>Author settings</legend> <ul> <li> <input type="radio" value="0" ${aSt ? 'checked="checked"' : ''} name="a-p-m--a" id="a-p-m--a-s"> <label for="a-p-m--a-s">Standard</label> </li> <li> <input type="radio" value="1" ${ai ? 'checked="checked"' : ''} name="a-p-m--a" id="a-p-m--a-i"> <label for="a-p-m--a-i">Increase</label> </li> <li> <input type="radio" value="2" ${ad ? 'checked="checked"' : ''} name="a-p-m--a" id="a-p-m--a-d"> <label for="a-p-m--a-d">Decrease</label> </li> </ul> </fieldset> ` : ''} <!-- Actions --> <ul class="actions"> <li><button type="submit">Apply</button></li> <li><button type="button" id="a-p-m--reset">Reset All</button></li> <li><button type="button" id="a-p-m--close">Close</button></li> </ul> </form> </ul> </li> `; // Append element to DOM (actions) actions.insertAdjacentHTML('afterbegin', marginHtml); // Apply new settings: update settings and store new data locally const submitApmForm = (e) => { e.preventDefault(); const formData = new FormData(e.target); const workSetting = Number(formData.get("a-p-m--w")); const authorSetting = Number(formData.get("a-p-m--a")); if (workSetting !== marginType.AUTHOR) { setMarginClass(workSetting); } else { setMarginClass(authorSetting); } setMarginLocal("work", workSetting); setMarginLocal("author", authorSetting); }; const secondary = document.querySelector("#a-p-m--secondary"); const form = document.querySelector("#a-p-m--form"); const reset = document.querySelector("#a-p-m--reset"); reset.onclick = () => { const response = confirm('Resetting all will permanently delete all work settings and author settings. Are you sure?'); if (response === true) { localStorage.removeItem("a-p-m--w-i"); localStorage.removeItem("a-p-m--w-d"); localStorage.removeItem("a-p-m--w-s"); localStorage.removeItem("a-p-m--a-i"); localStorage.removeItem("a-p-m--a-d"); setMarginClass(marginType.STANDARD); form.reset(); } }; const toggleButton = document.querySelector("#a-p-m--toggle"); toggleButton.onclick = () => { toggleButton.classList.toggle('collapsed'); toggleButton.classList.toggle('expanded'); secondary.classList.toggle('hidden'); }; const close = () => { toggleButton.classList.add('collapsed'); toggleButton.classList.remove('expanded'); secondary.classList.add('hidden'); }; const closeButton = document.querySelector("#a-p-m--close"); closeButton.onclick = close; form.addEventListener('submit', (e) => { submitApmForm(e); close(); }); } })();