|
| 1 | +// Page toolbar functionality for documentation pages |
| 2 | +// Adds toolbar with Copy Page, View Markdown, Ask in ChatGPT, and Ask in Claude |
| 3 | +(function() { |
| 4 | + 'use strict'; |
| 5 | + |
| 6 | + // Check if we're on the setup page |
| 7 | + function isSetupPage() { |
| 8 | + // Check if current page path includes 'setup' |
| 9 | + var path = window.location.pathname; |
| 10 | + // Handle various URL formats: /setup/, /setup, /setup.html, /users/setup/, etc. |
| 11 | + var normalizedPath = path.replace(/\/$/, '').replace(/\.html$/, '').toLowerCase(); |
| 12 | + return normalizedPath.endsWith('/setup') || normalizedPath.endsWith('setup') || |
| 13 | + normalizedPath === '/setup' || normalizedPath === 'setup'; |
| 14 | + } |
| 15 | + |
| 16 | + // Create the toolbar HTML |
| 17 | + function createToolbar() { |
| 18 | + var toolbar = document.createElement('div'); |
| 19 | + toolbar.className = 'page-toolbar'; |
| 20 | + toolbar.innerHTML = |
| 21 | + '<a href="#" class="page-toolbar-link" id="copy-page-btn">' + |
| 22 | + '<img src="data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'16\' height=\'16\' viewBox=\'0 0 24 24\' fill=\'none\' stroke=\'%23ffffff\' stroke-width=\'2\' stroke-linecap=\'round\' stroke-linejoin=\'round\'%3E%3Crect x=\'9\' y=\'9\' width=\'13\' height=\'13\' rx=\'2\' ry=\'2\'%3E%3C/rect%3E%3Cpath d=\'M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\'%3E%3C/path%3E%3C/svg%3E" class="page-toolbar-icon" alt="" />' + |
| 23 | + 'Copy Page' + |
| 24 | + '</a>' + |
| 25 | + '<span class="page-toolbar-separator">|</span>' + |
| 26 | + '<a href="#" class="page-toolbar-link" id="view-markdown-btn">' + |
| 27 | + '<img src="data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'16\' height=\'16\' viewBox=\'0 0 24 24\' fill=\'none\' stroke=\'%23ffffff\' stroke-width=\'2\' stroke-linecap=\'round\' stroke-linejoin=\'round\'%3E%3Cpath d=\'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\'%3E%3C/path%3E%3Cpolyline points=\'14 2 14 8 20 8\'%3E%3C/polyline%3E%3Cline x1=\'16\' y1=\'13\' x2=\'8\' y2=\'13\'%3E%3C/line%3E%3Cline x1=\'16\' y1=\'17\' x2=\'8\' y2=\'17\'%3E%3C/line%3E%3Cpolyline points=\'10 9 9 9 8 9\'%3E%3C/polyline%3E%3C/svg%3E" class="page-toolbar-icon" alt="" />' + |
| 28 | + 'View Markdown' + |
| 29 | + '</a>' + |
| 30 | + '<span class="page-toolbar-separator">|</span>' + |
| 31 | + '<a href="#" class="page-toolbar-link" id="ask-chatgpt-btn">' + |
| 32 | + '<img src="data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'16\' height=\'16\' fill=\'%23ffffff\' viewBox=\'0 0 256 256\'%3E%3Cpath d=\'M224.32,114.24a56,56,0,0,0-60.07-76.57A56,56,0,0,0,67.93,51.44a56,56,0,0,0-36.25,90.32A56,56,0,0,0,69,217,56.39,56.39,0,0,0,83.59,219a55.75,55.75,0,0,0,8.17-.61,56,56,0,0,0,96.31-13.78,56,56,0,0,0,36.25-90.32ZM182.85,54.43a40,40,0,0,1,28.56,48c-.95-.63-1.91-1.24-2.91-1.81L164,74.88a8,8,0,0,0-8,0l-44,25.41V81.81l40.5-23.38A39.76,39.76,0,0,1,182.85,54.43ZM144,137.24l-16,9.24-16-9.24V118.76l16-9.24,16,9.24ZM80,72a40,40,0,0,1,67.53-29c-1,.51-2,1-3,1.62L100,70.27a8,8,0,0,0-4,6.92V128l-16-9.24ZM40.86,86.93A39.75,39.75,0,0,1,64.12,68.57C64.05,69.71,64,70.85,64,72v51.38a8,8,0,0,0,4,6.93l44,25.4L96,165,55.5,141.57A40,40,0,0,1,40.86,86.93ZM73.15,201.57a40,40,0,0,1-28.56-48c.95.63,1.91,1.24,2.91,1.81L92,181.12a8,8,0,0,0,8,0l44-25.41v18.48l-40.5,23.38A39.76,39.76,0,0,1,73.15,201.57ZM176,184a40,40,0,0,1-67.52,29.05c1-.51,2-1.05,3-1.63L156,185.73a8,8,0,0,0,4-6.92V128l16,9.24Zm39.14-14.93a39.75,39.75,0,0,1-23.26,18.36c.07-1.14.12-2.28.12-3.43V132.62a8,8,0,0,0-4-6.93l-44-25.4,16-9.24,40.5,23.38A40,40,0,0,1,215.14,169.07Z\'/%3E%3C/svg%3E" class="page-toolbar-icon" alt="" />' + |
| 33 | + 'Ask in ChatGPT' + |
| 34 | + '</a>' + |
| 35 | + '<span class="page-toolbar-separator">|</span>' + |
| 36 | + '<a href="#" class="page-toolbar-link" id="ask-claude-btn">' + |
| 37 | + '<img src="https://www.google.com/s2/favicons?domain=claude.ai&sz=16" class="page-toolbar-icon page-toolbar-favicon" alt="" />' + |
| 38 | + 'Ask in Claude' + |
| 39 | + '</a>'; |
| 40 | + return toolbar; |
| 41 | + } |
| 42 | + |
| 43 | + // Get page content as text |
| 44 | + function getPageContent() { |
| 45 | + var content = document.querySelector('.md-content__inner'); |
| 46 | + if (!content) { |
| 47 | + content = document.querySelector('main'); |
| 48 | + } |
| 49 | + if (!content) { |
| 50 | + content = document.body; |
| 51 | + } |
| 52 | + return content ? content.innerText || content.textContent : ''; |
| 53 | + } |
| 54 | + |
| 55 | + // Get page title |
| 56 | + function getPageTitle() { |
| 57 | + var title = document.querySelector('h1'); |
| 58 | + return title ? title.textContent.trim() : document.title; |
| 59 | + } |
| 60 | + |
| 61 | + // Copy page content to clipboard |
| 62 | + function copyPageToClipboard() { |
| 63 | + var content = getPageContent(); |
| 64 | + var title = getPageTitle(); |
| 65 | + var textToCopy = title + '\n\n' + content; |
| 66 | + |
| 67 | + if (navigator.clipboard && navigator.clipboard.writeText) { |
| 68 | + navigator.clipboard.writeText(textToCopy).then(function() { |
| 69 | + showCopyFeedback('copy-page-btn'); |
| 70 | + }).catch(function(err) { |
| 71 | + console.error('Failed to copy:', err); |
| 72 | + fallbackCopy(textToCopy); |
| 73 | + }); |
| 74 | + } else { |
| 75 | + fallbackCopy(textToCopy); |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + // Fallback copy method for older browsers |
| 80 | + function fallbackCopy(text) { |
| 81 | + var textArea = document.createElement('textarea'); |
| 82 | + textArea.value = text; |
| 83 | + textArea.style.position = 'fixed'; |
| 84 | + textArea.style.left = '-999999px'; |
| 85 | + document.body.appendChild(textArea); |
| 86 | + textArea.select(); |
| 87 | + try { |
| 88 | + document.execCommand('copy'); |
| 89 | + showCopyFeedback('copy-page-btn'); |
| 90 | + } catch (err) { |
| 91 | + console.error('Fallback copy failed:', err); |
| 92 | + } |
| 93 | + document.body.removeChild(textArea); |
| 94 | + } |
| 95 | + |
| 96 | + // Show copy feedback |
| 97 | + function showCopyFeedback(buttonId) { |
| 98 | + var btn = document.getElementById(buttonId); |
| 99 | + if (btn) { |
| 100 | + var icon = btn.querySelector('.page-toolbar-icon'); |
| 101 | + var textNode = Array.from(btn.childNodes).find(function(node) { |
| 102 | + return node.nodeType === 3 && node.textContent.trim(); |
| 103 | + }); |
| 104 | + if (textNode) { |
| 105 | + var originalText = textNode.textContent.trim(); |
| 106 | + textNode.textContent = 'Copied!'; |
| 107 | + btn.classList.add('copied'); |
| 108 | + setTimeout(function() { |
| 109 | + textNode.textContent = originalText; |
| 110 | + btn.classList.remove('copied'); |
| 111 | + }, 2000); |
| 112 | + } |
| 113 | + } |
| 114 | + } |
| 115 | + |
| 116 | + // View markdown source |
| 117 | + function viewMarkdown() { |
| 118 | + // Get the current page path |
| 119 | + var path = window.location.pathname; |
| 120 | + // Remove leading/trailing slashes and .html extension |
| 121 | + path = path.replace(/^\/|\/$/g, '').replace(/\.html$/, ''); |
| 122 | + |
| 123 | + // Default to setup.md if path is empty or just 'setup' |
| 124 | + if (!path || path === 'setup') { |
| 125 | + path = 'setup'; |
| 126 | + } |
| 127 | + |
| 128 | + // Construct GitHub raw URL |
| 129 | + // Repository: malbeclabs/docs |
| 130 | + var repoOwner = 'malbeclabs'; |
| 131 | + var repoName = 'docs'; |
| 132 | + var branch = 'main'; |
| 133 | + |
| 134 | + // Try to construct GitHub raw URL |
| 135 | + var markdownUrl = 'https://raw.githubusercontent.com/' + repoOwner + '/' + repoName + '/' + branch + '/docs/' + path + '.md'; |
| 136 | + |
| 137 | + // Open in new tab |
| 138 | + window.open(markdownUrl, '_blank'); |
| 139 | + } |
| 140 | + |
| 141 | + // Ask in ChatGPT |
| 142 | + function askInChatGPT() { |
| 143 | + var content = getPageContent(); |
| 144 | + var title = getPageTitle(); |
| 145 | + var prompt = 'I\'m reading this documentation page: "' + title + '"\n\n' + content.substring(0, 3000) + (content.length > 3000 ? '...' : ''); |
| 146 | + var url = 'https://chat.openai.com/?q=' + encodeURIComponent(prompt); |
| 147 | + window.open(url, '_blank'); |
| 148 | + } |
| 149 | + |
| 150 | + // Ask in Claude |
| 151 | + function askInClaude() { |
| 152 | + var content = getPageContent(); |
| 153 | + var title = getPageTitle(); |
| 154 | + var prompt = 'I\'m reading this documentation page: "' + title + '"\n\n' + content.substring(0, 3000) + (content.length > 3000 ? '...' : ''); |
| 155 | + var url = 'https://claude.ai/new?prompt=' + encodeURIComponent(prompt); |
| 156 | + window.open(url, '_blank'); |
| 157 | + } |
| 158 | + |
| 159 | + // Initialize toolbar |
| 160 | + function initToolbar() { |
| 161 | + // Only add toolbar on setup page |
| 162 | + if (!isSetupPage()) { |
| 163 | + return; |
| 164 | + } |
| 165 | + |
| 166 | + // Wait for page to be ready |
| 167 | + if (document.readyState === 'loading') { |
| 168 | + document.addEventListener('DOMContentLoaded', function() { |
| 169 | + addToolbar(); |
| 170 | + }); |
| 171 | + } else { |
| 172 | + addToolbar(); |
| 173 | + } |
| 174 | + } |
| 175 | + |
| 176 | + // Add toolbar to page |
| 177 | + function addToolbar() { |
| 178 | + // Create a fixed footer at the bottom of the screen |
| 179 | + var footer = document.createElement('footer'); |
| 180 | + footer.className = 'page-toolbar-footer'; |
| 181 | + |
| 182 | + // Create and insert toolbar |
| 183 | + var toolbar = createToolbar(); |
| 184 | + footer.appendChild(toolbar); |
| 185 | + |
| 186 | + // Insert at the end of body |
| 187 | + document.body.appendChild(footer); |
| 188 | + |
| 189 | + // Attach event listeners |
| 190 | + document.getElementById('copy-page-btn').addEventListener('click', function(e) { |
| 191 | + e.preventDefault(); |
| 192 | + copyPageToClipboard(); |
| 193 | + }); |
| 194 | + document.getElementById('view-markdown-btn').addEventListener('click', function(e) { |
| 195 | + e.preventDefault(); |
| 196 | + viewMarkdown(); |
| 197 | + }); |
| 198 | + document.getElementById('ask-chatgpt-btn').addEventListener('click', function(e) { |
| 199 | + e.preventDefault(); |
| 200 | + askInChatGPT(); |
| 201 | + }); |
| 202 | + document.getElementById('ask-claude-btn').addEventListener('click', function(e) { |
| 203 | + e.preventDefault(); |
| 204 | + askInClaude(); |
| 205 | + }); |
| 206 | + } |
| 207 | + |
| 208 | + // Initialize when script loads |
| 209 | + initToolbar(); |
| 210 | +})(); |
0 commit comments