Last active 1 month ago

makes the ao3 editor into a markdown editor instead. plain text forever

veryroundbird's Avatar veryroundbird revised this gist 1 month ago. Go to revision

No changes

veryroundbird's Avatar veryroundbird revised this gist 1 month ago. Go to revision

1 file changed, 5 insertions

ao3markdown.user.js

@@ -5,6 +5,11 @@
5 5 // @description replaces the standard AO3 editor with a markdown editor that has syntax highlighting and a previewer for people with my brain disease
6 6 // @author You
7 7 // @match https://archiveofourown.org/works/*
8 + // @match https://squidgeworld.org/works/*
9 + // @match https://sunset.femslash.club/works/*
10 + // @match https://superlove.sayitditto.net/works/*
11 + // @match https://adastrafanfic.com/works/*
12 + // @match https://cfaarchive.org/works/*
8 13 // @icon https://www.google.com/s2/favicons?sz=64&domain=archiveofourown.org
9 14 // @require https://unpkg.com/turndown/dist/turndown.js
10 15 // @require https://unpkg.com/@highlightjs/cdn-assets@11.11.1/highlight.min.js

veryroundbird's Avatar veryroundbird revised this gist 1 month ago. Go to revision

1 file changed, 2 insertions, 7 deletions

ao3markdown.user.js

@@ -1,19 +1,14 @@
1 1 // ==UserScript==
2 - // @name AO3 Better Editor
2 + // @name AO3 Markdown Editor
3 3 // @namespace https://veryroundbird.house
4 4 // @version 2026-03-31
5 - // @description try to take over the world!
5 + // @description replaces the standard AO3 editor with a markdown editor that has syntax highlighting and a previewer for people with my brain disease
6 6 // @author You
7 7 // @match https://archiveofourown.org/works/*
8 8 // @icon https://www.google.com/s2/favicons?sz=64&domain=archiveofourown.org
9 9 // @require https://unpkg.com/turndown/dist/turndown.js
10 10 // @require https://unpkg.com/@highlightjs/cdn-assets@11.11.1/highlight.min.js
11 11 // @require https://cdn.jsdelivr.net/npm/marked/lib/marked.umd.js
12 - // @require https://openuserjs.org/src/libs/sizzle/GM_config.js
13 - // @grant GM_getValue
14 - // @grant GM_setValue
15 - // @grant GM.getValue
16 - // @grant GM.setValue
17 12 // ==/UserScript==
18 13
19 14 const addCss = (url, container) => {

veryroundbird's Avatar veryroundbird revised this gist 1 month ago. Go to revision

1 file changed, 157 insertions

ao3markdown.user.js(file created)

@@ -0,0 +1,157 @@
1 + // ==UserScript==
2 + // @name AO3 Better Editor
3 + // @namespace https://veryroundbird.house
4 + // @version 2026-03-31
5 + // @description try to take over the world!
6 + // @author You
7 + // @match https://archiveofourown.org/works/*
8 + // @icon https://www.google.com/s2/favicons?sz=64&domain=archiveofourown.org
9 + // @require https://unpkg.com/turndown/dist/turndown.js
10 + // @require https://unpkg.com/@highlightjs/cdn-assets@11.11.1/highlight.min.js
11 + // @require https://cdn.jsdelivr.net/npm/marked/lib/marked.umd.js
12 + // @require https://openuserjs.org/src/libs/sizzle/GM_config.js
13 + // @grant GM_getValue
14 + // @grant GM_setValue
15 + // @grant GM.getValue
16 + // @grant GM.setValue
17 + // ==/UserScript==
18 +
19 + const addCss = (url, container) => {
20 + const css = document.createElement('link');
21 + css.setAttribute('rel', 'stylesheet');
22 + css.setAttribute('type', 'text/css');
23 + css.setAttribute('href', url);
24 + container.appendChild(css);
25 + return css;
26 + }
27 +
28 +
29 + (() => {
30 + 'use strict';
31 +
32 + addCss('https://unpkg.com/@highlightjs/cdn-assets@11.11.1/styles/base16/cupcake.min.css', document.head);
33 + addCss('https://unpkg.com/@fontsource/maple-mono@5.2.6/index.css', document.head);
34 + const styles = document.createElement('style');
35 + styles.setAttribute('type', 'text/css');
36 + styles.innerHTML = `
37 + #editor-tabs {
38 + display: flex;
39 + gap: 10px;
40 + }
41 +
42 + #editor-tabs button {
43 + border-radius: 10px 10px 0 0;
44 + box-shadow: none;
45 + }
46 +
47 + #editor-tabs button[disabled] {
48 + opacity: 0.5;
49 + }
50 +
51 + #editor-container,
52 + #preview {
53 + border: 1px white solid;
54 + }
55 +
56 + #editor,
57 + #preview {
58 + height: 500px;
59 + overflow: auto;
60 + display: block;
61 + }
62 +
63 + #editor {
64 + font-family: 'Maple Mono', monospace;
65 + font-size: 16px;
66 + }
67 +
68 + #preview {
69 + padding: 20px;
70 + }
71 +
72 + #preview p {
73 + padding: 0;
74 + margin: 1em 0;
75 + }
76 + `;
77 + document.head.appendChild(styles);
78 +
79 + const content = document.getElementById('content');
80 + const buttons = document.querySelector('.rtf-html-switch');
81 + if (buttons) {
82 + buttons.style.display = 'none';
83 + }
84 + const turndownService = new TurndownService({
85 + headingStyle: 'atx',
86 + emDelimiter: '*',
87 + codeBlockStyle: 'fenced'
88 + });
89 + if (content) {
90 + content.style.display = 'none';
91 + const initialText = turndownService.turndown(content.textContent);
92 +
93 + const wrapper = document.createElement('div');
94 + wrapper.id = 'editor-wrapper';
95 +
96 + const tabs = document.createElement('div');
97 + tabs.id = 'editor-tabs';
98 +
99 + const mdBtn = document.createElement('button');
100 + mdBtn.setAttribute('type', 'button');
101 + mdBtn.textContent = "Markdown";
102 + mdBtn.setAttribute("disabled", "disabled");
103 + mdBtn.id = 'editor-btn-markdown';
104 + tabs.appendChild(mdBtn);
105 +
106 + const htmlBtn = document.createElement('button');
107 + htmlBtn.setAttribute('type', 'button');
108 + htmlBtn.id = 'editor-btn-html';
109 + htmlBtn.textContent = "Preview";
110 + tabs.appendChild(htmlBtn);
111 +
112 + wrapper.appendChild(tabs);
113 +
114 + const editorContainer = document.createElement('pre');
115 + editorContainer.id = 'editor-container';
116 +
117 + const editor = document.createElement('code');
118 + editor.id = 'editor';
119 + editor.classList.add('language-markdown');
120 + editor.setAttribute("contenteditable", "plaintext-only");
121 + editor.textContent = initialText;
122 + editorContainer.appendChild(editor);
123 + wrapper.appendChild(editorContainer);
124 +
125 + const preview = document.createElement('div');
126 + preview.id = 'preview';
127 + preview.style.display = "none";
128 + preview.innerHTML = content.value;
129 + wrapper.appendChild(preview);
130 +
131 + content.after(wrapper);
132 +
133 + mdBtn.addEventListener('click', (e) => {
134 + e.preventDefault();
135 + htmlBtn.removeAttribute("disabled");
136 + mdBtn.setAttribute("disabled", "disabled");
137 + editorContainer.style.display = "block";
138 + preview.style.display = "none";
139 + });
140 +
141 + htmlBtn.addEventListener('click', (e) => {
142 + e.preventDefault();
143 + mdBtn.removeAttribute("disabled");
144 + htmlBtn.setAttribute("disabled", "disabled");
145 + editorContainer.style.display = "none";
146 + preview.style.display = "block";
147 + });
148 +
149 + editor.addEventListener('input', (_e) => {
150 + const text = marked.parse(editor.innerHTML.replaceAll(/<\/?span(\sclass="hljs-[a-z]+")>/g, ""));
151 + preview.innerHTML = text;
152 + content.value = text;
153 + });
154 +
155 + hljs.highlightAll();
156 + }
157 + })();
Newer Older