diff --git a/netbox_documentation/templates/netbox_documentation/document.html b/netbox_documentation/templates/netbox_documentation/document.html index 7dfa96e..d1a11e1 100644 --- a/netbox_documentation/templates/netbox_documentation/document.html +++ b/netbox_documentation/templates/netbox_documentation/document.html @@ -40,6 +40,29 @@ .documentation-content .doc-cell-blue { background: #dbeafe !important; color: #212529; } .documentation-content .doc-cell-middle { vertical-align: middle !important; } .documentation-content p { max-width: 90rem; } + .documentation-content .doc-code-block { position: relative; margin: 0 0 1rem; } + .documentation-content pre { + margin: 0; + padding: .85rem 4.5rem .85rem 1rem; + background: #1e1e1e !important; + color: #e9ecef !important; + border-radius: 6px; + font-family: Consolas, 'Courier New', monospace; + font-size: 10pt; + line-height: 1.5; + white-space: pre-wrap; + overflow-x: auto; + } + .documentation-content pre * { background: transparent !important; font-family: inherit !important; } + .documentation-content pre ::selection, + .documentation-content pre::selection { background: #4c8bf5 !important; color: #fff !important; } + .documentation-content .doc-code-copy { + position: absolute; top: .4rem; right: .4rem; + padding: .15rem .5rem; font-size: .75rem; + color: #e9ecef; background: rgba(255,255,255,.1); + border: 1px solid rgba(255,255,255,.25); border-radius: 4px; + } + .documentation-content .doc-code-copy:hover { background: rgba(255,255,255,.2); } .documentation-content table { cursor: zoom-in; } #documentation-viewer.documentation-page-focus { position: fixed; @@ -120,6 +143,36 @@ openViewer(); }); }); + viewer.querySelectorAll('.documentation-content pre').forEach(pre => { + const wrapper = document.createElement('div'); + wrapper.className = 'doc-code-block'; + pre.parentNode.insertBefore(wrapper, pre); + wrapper.appendChild(pre); + const copyButton = document.createElement('button'); + copyButton.type = 'button'; + copyButton.className = 'doc-code-copy'; + copyButton.innerHTML = ' Kopieren'; + copyButton.addEventListener('click', async () => { + const text = pre.innerText.replace(/ +$/, ''); + try { + await navigator.clipboard.writeText(text); + } catch (error) { + // Fallback for plain-HTTP deployments without Clipboard API. + const area = document.createElement('textarea'); + area.value = text; + area.style.position = 'fixed'; + area.style.opacity = '0'; + document.body.appendChild(area); + area.select(); + document.execCommand('copy'); + area.remove(); + } + copyButton.innerHTML = ' Kopiert'; + setTimeout(() => { copyButton.innerHTML = ' Kopieren'; }, 1500); + }); + wrapper.appendChild(copyButton); + }); document.addEventListener('keydown', event => { if (event.key === 'Escape' && viewer.classList.contains('documentation-page-focus')) closeViewer(); }); diff --git a/netbox_documentation/templates/netbox_documentation/document_edit.html b/netbox_documentation/templates/netbox_documentation/document_edit.html index 4a8c2e5..2f86f61 100644 --- a/netbox_documentation/templates/netbox_documentation/document_edit.html +++ b/netbox_documentation/templates/netbox_documentation/document_edit.html @@ -31,10 +31,10 @@ license_key: 'gpl', height: 650, menubar: 'file edit view insert format tools table help', - plugins: 'advlist anchor autolink charmap code fullscreen image link lists media preview searchreplace table visualblocks wordcount', + plugins: 'advlist anchor autolink charmap code codesample fullscreen image link lists media preview searchreplace table visualblocks wordcount', toolbar: [ 'undo redo | blocks styles fontfamily fontsize | bold italic underline strikethrough | forecolor backcolor', - 'alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table tablecellcolor link image media | removeformat code fullscreen' + 'alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table tablecellcolor link image media codesample | removeformat code fullscreen' ], toolbar_mode: 'sliding', table_toolbar: 'tableprops tablecellprops tablecellcolor | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol | tablemergecells tablesplitcells | tabledelete', @@ -88,9 +88,24 @@ .doc-cell-red { background: #ffe3e3 !important; } .doc-cell-blue { background: #dbeafe !important; } .doc-cell-middle { vertical-align: middle !important; } + pre { background: #1e1e1e; color: #e9ecef; padding: .75rem 1rem; border-radius: 6px; font-family: Consolas, 'Courier New', monospace; font-size: 10pt; white-space: pre-wrap; } + pre ::selection, pre::selection { background: #4c8bf5; color: #fff; } `, + codesample_global_prismjs: false, + codesample_languages: [ + {text: 'Bash / Shell', value: 'bash'}, + {text: 'PowerShell', value: 'powershell'}, + {text: 'Cisco / Netzwerk-Konfiguration', value: 'none'}, + {text: 'Python', value: 'python'}, + {text: 'JSON', value: 'json'}, + {text: 'YAML', value: 'yaml'}, + {text: 'SQL', value: 'sql'}, + {text: 'HTML/XML', value: 'markup'}, + {text: 'JavaScript', value: 'javascript'}, + {text: 'Nur Text', value: 'plaintext'} + ], browser_spellcheck: true, - contextmenu: 'link image table', + contextmenu: 'link image table codesample', promotion: false, branding: false, convert_unsafe_embeds: true,