Last active
July 29, 2026 15:58
-
-
Save tsantos8080/1afda240f9ef0bd9faa237805bff791d to your computer and use it in GitHub Desktop.
Copy stories from hochanh.github.io
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==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