1+ document . addEventListener ( 'DOMContentLoaded' , function ( ) {
2+ // SVG Icons
3+ const copyIconSVG = `<svg class="copy-icon" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>` ;
4+ const checkIconSVG = `<svg class="check-icon" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg>` ;
5+
6+ // Find all code blocks
7+ const codeBlocks = document . querySelectorAll ( 'pre' ) ;
8+
9+ codeBlocks . forEach ( ( pre ) => {
10+ // Create wrapper
11+ const wrapper = document . createElement ( 'div' ) ;
12+ wrapper . className = 'code-block-wrapper' ;
13+
14+ // Insert wrapper before pre
15+ pre . parentNode . insertBefore ( wrapper , pre ) ;
16+
17+ // Move pre into wrapper
18+ wrapper . appendChild ( pre ) ;
19+
20+ // Create copy button
21+ const button = document . createElement ( 'button' ) ;
22+ button . className = 'copy-button' ;
23+ button . type = 'button' ;
24+ button . innerHTML = copyIconSVG + '<span class="copy-button-text">Copy</span>' ;
25+ button . title = 'Copy code to clipboard' ;
26+
27+ // Add button to wrapper
28+ wrapper . appendChild ( button ) ;
29+
30+ // Copy functionality
31+ button . addEventListener ( 'click' , async function ( e ) {
32+ e . preventDefault ( ) ;
33+
34+ // Get code text from the pre element
35+ const code = pre . innerText ;
36+
37+ try {
38+ // Copy to clipboard
39+ await navigator . clipboard . writeText ( code ) ;
40+
41+ // Change button appearance
42+ button . classList . add ( 'copied' ) ;
43+ button . innerHTML = checkIconSVG + '<span class="copy-button-text">Copied!</span>' ;
44+
45+ // Reset button after 2 seconds
46+ setTimeout ( ( ) => {
47+ button . classList . remove ( 'copied' ) ;
48+ button . innerHTML = copyIconSVG + '<span class="copy-button-text">Copy</span>' ;
49+ } , 2000 ) ;
50+ } catch ( err ) {
51+ console . error ( 'Failed to copy code:' , err ) ;
52+ button . innerHTML = '❌ <span class="copy-button-text">Failed</span>' ;
53+ setTimeout ( ( ) => {
54+ button . innerHTML = copyIconSVG + '<span class="copy-button-text">Copy</span>' ;
55+ } , 2000 ) ;
56+ }
57+ } ) ;
58+ } ) ;
59+
60+ // Watch for theme changes (for mkdocs-shadcn theme toggle)
61+ const observer = new MutationObserver ( function ( mutations ) {
62+ mutations . forEach ( function ( mutation ) {
63+ if ( mutation . attributeName === 'class' || mutation . attributeName === 'data-theme' ) {
64+ // Force CSS variables update by triggering a repaint
65+ document . documentElement . style . colorScheme = document . documentElement . classList . contains ( 'dark' ) ? 'dark' : 'light' ;
66+ }
67+ } ) ;
68+ } ) ;
69+
70+ // Observe html element for class/attribute changes
71+ observer . observe ( document . documentElement , {
72+ attributes : true ,
73+ attributeFilter : [ 'class' , 'data-theme' ]
74+ } ) ;
75+ } ) ;
0 commit comments