Skip to content

Instantly share code, notes, and snippets.

@tsantos8080
Last active July 29, 2026 15:58
Show Gist options
  • Select an option

  • Save tsantos8080/1afda240f9ef0bd9faa237805bff791d to your computer and use it in GitHub Desktop.

Select an option

Save tsantos8080/1afda240f9ef0bd9faa237805bff791d to your computer and use it in GitHub Desktop.
Copy stories from hochanh.github.io
// ==UserScript==
// @name RTK Paragraph Copier (Formatted)
// @namespace http://tampermonkey.net/
// @version 1.4
// @description Copy formatted paragraphs from RTK pages as Rich Text (retaining bold/HTML styles)
// @author You
// @match https://hochanh.github.io/rtk/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Inject CSS styles
const style = document.createElement('style');
style.innerHTML = `
#rtk-copy-btn {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
padding: 10px 16px;
background-color: #2b2b2b;
color: #ffffff;
border: 1px solid #444;
border-radius: 8px;
cursor: pointer;
font-family: sans-serif;
font-size: 14px;
font-weight: bold;
box-shadow: 0 4px 10px rgba(0,0,0,0.3);
transition: all 0.2s ease-in-out;
}
#rtk-copy-btn:hover {
background-color: #3d3d3d;
transform: translateY(-2px);
}
.rtk-single-copy-btn {
margin-left: 8px;
padding: 2px 6px;
background-color: #f0f0f0;
color: #333;
border: 1px solid #ccc;
border-radius: 4px;
cursor: pointer;
font-size: 11px;
vertical-align: middle;
transition: background 0.2s;
}
.rtk-single-copy-btn:hover {
background-color: #e0e0e0;
}
#rtk-toast {
position: fixed;
bottom: 70px;
right: 20px;
z-index: 9999;
background-color: #2e7d32;
color: #ffffff;
padding: 10px 16px;
border-radius: 6px;
font-family: sans-serif;
font-size: 13px;
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
opacity: 0;
transform: translateY(10px);
transition: opacity 0.3s ease, transform 0.3s ease;
pointer-events: none;
}
#rtk-toast.show {
opacity: 1;
transform: translateY(0);
}
`;
document.head.appendChild(style);
// Toast notification element
const toast = document.createElement('div');
toast.id = 'rtk-toast';
toast.innerText = 'Copied to clipboard!';
document.body.appendChild(toast);
function showToast(msg) {
toast.innerText = msg || 'Copied to clipboard!';
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 2000);
}
// Function to copy HTML content as Rich Text
async function copyHtmlAsRichText(htmlContent) {
try {
// Converts raw HTML string into plain text for fallbacks
const tempDiv = document.createElement('div');
tempDiv.innerHTML = htmlContent;
const plainText = tempDiv.innerText || tempDiv.textContent;
const blobHtml = new Blob([htmlContent], { type: 'text/html' });
const blobText = new Blob([plainText], { type: 'text/plain' });
const data = [new ClipboardItem({
'text/html': blobHtml,
'text/plain': blobText
})];
await navigator.clipboard.write(data);
} catch (err) {
console.error('Failed to copy rich text:', err);
}
}
// Main floating button (Copy All)
const mainButton = document.createElement('button');
mainButton.id = 'rtk-copy-btn';
mainButton.innerText = '๐Ÿ“‹ Copy All';
document.body.appendChild(mainButton);
mainButton.addEventListener('click', async () => {
const textToCopy = Array.from(document.querySelectorAll('p'))
.slice(0, -1)
.map(p => p.innerHTML)
.join('<br><br>');
await copyHtmlAsRichText(textToCopy);
showToast('All paragraphs copied!');
});
// Add individual copy buttons to each paragraph (excluding the last one)
const paragraphs = Array.from(document.querySelectorAll('p')).slice(0, -1);
paragraphs.forEach((p, index) => {
const singleBtn = document.createElement('button');
singleBtn.className = 'rtk-single-copy-btn';
singleBtn.innerText = '๐Ÿ“‹ Copy';
singleBtn.title = 'Copy only this paragraph';
singleBtn.addEventListener('click', async (e) => {
e.stopPropagation();
// Clone paragraph and strip the button element before copying
const cloneP = p.cloneNode(true);
const btnInClone = cloneP.querySelector('.rtk-single-copy-btn');
if (btnInClone) btnInClone.remove();
let content = cloneP.innerHTML;
// Remove tudo o que vem antes do primeiro '['
const bracketIndex = content.indexOf('[');
if (bracketIndex !== -1) {
content = content.slice(bracketIndex);
}
await copyHtmlAsRichText(content);
showToast(`Paragraph #${index + 1} copied!`);
});
p.appendChild(singleBtn);
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment