mirror of
				https://github.com/imfing/hextra.git
				synced 2025-11-03 22:25:03 -05:00 
			
		
		
		
	chore: add code copy button icons in js (#133)
This commit is contained in:
		@@ -1,30 +1,63 @@
 | 
				
			|||||||
document.querySelectorAll('.code-copy-btn').forEach(function (button) {
 | 
					// Copy button for code blocks
 | 
				
			||||||
  button.addEventListener('click', function (e) {
 | 
					
 | 
				
			||||||
    e.preventDefault();
 | 
					document.addEventListener('DOMContentLoaded', function () {
 | 
				
			||||||
    const targetId = button.getAttribute('data-clipboard-target');
 | 
					  const getCopyIcon = () => {
 | 
				
			||||||
    const target = document.querySelector(targetId);
 | 
					    const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
 | 
				
			||||||
    let codeElement;
 | 
					    svg.innerHTML = `
 | 
				
			||||||
    if (target.tagName === 'CODE') {
 | 
					      <path stroke-linecap="round" stroke-linejoin="round" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
 | 
				
			||||||
      codeElement = target;
 | 
					    `;
 | 
				
			||||||
    } else {
 | 
					    svg.setAttribute('fill', 'none');
 | 
				
			||||||
      // Select the last code element in case line numbers are present
 | 
					    svg.setAttribute('viewBox', '0 0 24 24');
 | 
				
			||||||
      const codeElements = target.querySelectorAll('code');
 | 
					    svg.setAttribute('stroke', 'currentColor');
 | 
				
			||||||
      codeElement = codeElements[codeElements.length - 1];
 | 
					    svg.setAttribute('stroke-width', '2');
 | 
				
			||||||
    }
 | 
					    return svg;
 | 
				
			||||||
    if (codeElement) {
 | 
					  }
 | 
				
			||||||
      // Replace double newlines with single newlines in the innerText
 | 
					
 | 
				
			||||||
      // as each line inside <span> has trailing newline '\n'
 | 
					  const getSuccessIcon = () => {
 | 
				
			||||||
      const code = codeElement.innerText.replace(/\n\n/g, '\n');
 | 
					    const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
 | 
				
			||||||
      navigator.clipboard.writeText(code).then(function () {
 | 
					    svg.innerHTML = `
 | 
				
			||||||
        button.classList.add('copied');
 | 
					      <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
 | 
				
			||||||
        setTimeout(function () {
 | 
					    `;
 | 
				
			||||||
          button.classList.remove('copied');
 | 
					    svg.setAttribute('fill', 'none');
 | 
				
			||||||
        }, 500);
 | 
					    svg.setAttribute('viewBox', '0 0 24 24');
 | 
				
			||||||
      }).catch(function (err) {
 | 
					    svg.setAttribute('stroke', 'currentColor');
 | 
				
			||||||
        console.error('Failed to copy text: ', err);
 | 
					    svg.setAttribute('stroke-width', '2');
 | 
				
			||||||
      });
 | 
					    return svg;
 | 
				
			||||||
    } else {
 | 
					  }
 | 
				
			||||||
      console.error('Target element not found');
 | 
					
 | 
				
			||||||
    }
 | 
					  document.querySelectorAll('.code-copy-btn').forEach(function (button) {
 | 
				
			||||||
 | 
					    // Add copy and success icons
 | 
				
			||||||
 | 
					    button.querySelector('.copy-icon')?.appendChild(getCopyIcon());
 | 
				
			||||||
 | 
					    button.querySelector('.success-icon')?.appendChild(getSuccessIcon());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add click event listener for copy button
 | 
				
			||||||
 | 
					    button.addEventListener('click', function (e) {
 | 
				
			||||||
 | 
					      e.preventDefault();
 | 
				
			||||||
 | 
					      const targetId = button.getAttribute('data-clipboard-target');
 | 
				
			||||||
 | 
					      const target = document.querySelector(targetId);
 | 
				
			||||||
 | 
					      let codeElement;
 | 
				
			||||||
 | 
					      if (target.tagName === 'CODE') {
 | 
				
			||||||
 | 
					        codeElement = target;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        // Select the last code element in case line numbers are present
 | 
				
			||||||
 | 
					        const codeElements = target.querySelectorAll('code');
 | 
				
			||||||
 | 
					        codeElement = codeElements[codeElements.length - 1];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (codeElement) {
 | 
				
			||||||
 | 
					        // Replace double newlines with single newlines in the innerText
 | 
				
			||||||
 | 
					        // as each line inside <span> has trailing newline '\n'
 | 
				
			||||||
 | 
					        const code = codeElement.innerText.replace(/\n\n/g, '\n');
 | 
				
			||||||
 | 
					        navigator.clipboard.writeText(code).then(function () {
 | 
				
			||||||
 | 
					          button.classList.add('copied');
 | 
				
			||||||
 | 
					          setTimeout(function () {
 | 
				
			||||||
 | 
					            button.classList.remove('copied');
 | 
				
			||||||
 | 
					          }, 500);
 | 
				
			||||||
 | 
					        }).catch(function (err) {
 | 
				
			||||||
 | 
					          console.error('Failed to copy text: ', err);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        console.error('Target element not found');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -154,6 +154,7 @@
 | 
				
			|||||||
      "contrast-more:text-gray-800",
 | 
					      "contrast-more:text-gray-800",
 | 
				
			||||||
      "contrast-more:text-gray-900",
 | 
					      "contrast-more:text-gray-900",
 | 
				
			||||||
      "contrast-more:underline",
 | 
					      "contrast-more:underline",
 | 
				
			||||||
 | 
					      "copy-icon",
 | 
				
			||||||
      "cursor-default",
 | 
					      "cursor-default",
 | 
				
			||||||
      "cursor-pointer",
 | 
					      "cursor-pointer",
 | 
				
			||||||
      "dark:before:bg-neutral-800",
 | 
					      "dark:before:bg-neutral-800",
 | 
				
			||||||
@@ -590,4 +591,4 @@
 | 
				
			|||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "ids": null
 | 
					    "ids": null
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,9 +15,13 @@
 | 
				
			|||||||
    <pre><code id="code-block-{{ .Ordinal }}">{{ .Inner }}</code></pre>
 | 
					    <pre><code id="code-block-{{ .Ordinal }}">{{ .Inner }}</code></pre>
 | 
				
			||||||
  {{- end -}}
 | 
					  {{- end -}}
 | 
				
			||||||
  <div class="opacity-0 transition group-hover/code:opacity-100 flex gap-1 absolute m-[11px] right-0 {{ if $filename }}top-8{{ else }}top-0{{ end }}">
 | 
					  <div class="opacity-0 transition group-hover/code:opacity-100 flex gap-1 absolute m-[11px] right-0 {{ if $filename }}top-8{{ else }}top-0{{ end }}">
 | 
				
			||||||
    <button class="code-copy-btn group/copybtn transition-all active:opacity-50 bg-primary-700/5 border border-black/5 text-gray-600 hover:text-gray-900 rounded-md p-1.5 dark:bg-primary-300/10 dark:border-white/10 dark:text-gray-400 dark:hover:text-gray-50" title="Copy code" data-clipboard-target="#code-block-{{ .Ordinal }}">
 | 
					    <button
 | 
				
			||||||
      {{ partial "utils/icon.html" (dict "name" "copy" "attributes" "class=\"group-[.copied]/copybtn:hidden pointer-events-none h-4 w-4\"") }}
 | 
					      class="code-copy-btn group/copybtn transition-all active:opacity-50 bg-primary-700/5 border border-black/5 text-gray-600 hover:text-gray-900 rounded-md p-1.5 dark:bg-primary-300/10 dark:border-white/10 dark:text-gray-400 dark:hover:text-gray-50"
 | 
				
			||||||
      {{ partial "utils/icon.html" (dict "name" "check" "attributes" "class=\"hidden group-[.copied]/copybtn:block success-icon pointer-events-none h-4 w-4\"") }}
 | 
					      title="Copy code"
 | 
				
			||||||
 | 
					      data-clipboard-target="#code-block-{{ .Ordinal }}"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <div class="group-[.copied]/copybtn:hidden copy-icon pointer-events-none h-4 w-4"></div>
 | 
				
			||||||
 | 
					      <div class="hidden group-[.copied]/copybtn:block success-icon pointer-events-none h-4 w-4"></div>
 | 
				
			||||||
    </button>
 | 
					    </button>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user