Fork of Chiri for Astro for my blog
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 0900a8639345fb90c485c56379cc9c6c7dc931cd 181 lines 5.4 kB view raw
1--- 2import { themeConfig } from '@/config' 3--- 4 5<script define:vars={{ copyCode: themeConfig.post.copyCode }}> 6 function initCopyCode() { 7 const copyIcon = ` 8 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="14" height="14" fill="currentColor"> 9 <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path> 10 <path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> 11 </svg> 12 ` 13 14 const copiedIcon = ` 15 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" fill="currentColor"> 16 <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> 17 </svg> 18 ` 19 20 document.body.setAttribute('data-copy-code', copyCode ? 'enabled' : 'disabled') 21 22 if (!copyCode) { 23 return 24 } 25 26 const copyButtons = document.querySelectorAll('.copy-button') 27 28 copyButtons.forEach((button) => { 29 const preElement = button.closest('.copy-code-block') 30 if (!preElement) return 31 32 const codeElement = preElement.querySelector('code') 33 if (!codeElement) return 34 35 if (!button.querySelector('svg')) { 36 button.innerHTML = copyIcon 37 } 38 39 button.style.opacity = '0' 40 button.style.pointerEvents = 'none' 41 42 preElement.addEventListener('mouseenter', () => { 43 button.style.opacity = '1' 44 button.style.pointerEvents = 'auto' 45 }) 46 47 preElement.addEventListener('mouseleave', () => { 48 if (!button.hasAttribute('data-copying')) { 49 button.style.opacity = '0' 50 button.style.pointerEvents = 'none' 51 } 52 }) 53 54 button.addEventListener('click', async () => { 55 const codeText = codeElement.textContent || '' 56 57 try { 58 // Primary method: use modern clipboard API 59 await navigator.clipboard.writeText(codeText) 60 button.setAttribute('data-copying', 'true') 61 button.innerHTML = copiedIcon 62 63 setTimeout(() => { 64 if (!preElement.matches(':hover')) { 65 button.style.opacity = '0' 66 button.style.pointerEvents = 'none' 67 } 68 button.removeAttribute('data-copying') 69 70 setTimeout(() => { 71 button.innerHTML = copyIcon 72 }, 500) 73 }, 1500) 74 } catch (err) { 75 console.error('Failed to copy code:', err) 76 77 // Fallback method: create temporary textarea for older browsers 78 try { 79 const textArea = document.createElement('textarea') 80 textArea.value = codeText 81 textArea.style.position = 'fixed' 82 textArea.style.opacity = '0' 83 document.body.appendChild(textArea) 84 textArea.focus() 85 textArea.select() 86 87 navigator.clipboard 88 .writeText(codeText) 89 .then(() => { 90 document.body.removeChild(textArea) 91 }) 92 .catch(() => { 93 console.error('Both clipboard methods failed') 94 document.body.removeChild(textArea) 95 }) 96 } catch (fallbackErr) { 97 console.error('All clipboard methods failed:', fallbackErr) 98 } 99 100 button.setAttribute('data-copying', 'true') 101 button.innerHTML = copiedIcon 102 103 setTimeout(() => { 104 if (!preElement.matches(':hover')) { 105 button.style.opacity = '0' 106 button.style.pointerEvents = 'none' 107 } 108 button.removeAttribute('data-copying') 109 110 setTimeout(() => { 111 button.innerHTML = copyIcon 112 }, 500) 113 }, 1500) 114 } 115 }) 116 }) 117 } 118 119 document.addEventListener('astro:page-load', initCopyCode) 120 document.addEventListener('DOMContentLoaded', initCopyCode) 121</script> 122 123<style is:inline> 124 .copy-code-block { 125 position: relative !important; 126 } 127 128 .copy-button { 129 position: absolute; 130 top: 0.5rem; 131 right: 0.5rem; 132 width: 2rem; 133 height: 2rem; 134 z-index: 10; 135 background: var(--bg); 136 border-radius: 0.375rem; 137 font-size: 0.75rem; 138 color: var(--text-secondary); 139 cursor: pointer; 140 transition: all 0.15s ease-out; 141 display: flex; 142 align-items: center; 143 justify-content: center; 144 border: 1px solid var(--border); 145 backdrop-filter: blur(48px); 146 opacity: 0; 147 pointer-events: none; 148 } 149 150 body[data-copy-code='disabled'] .copy-button { 151 display: none !important; 152 } 153 154 .copy-button::before { 155 content: ''; 156 position: absolute; 157 top: 0; 158 left: 0; 159 right: 0; 160 bottom: 0; 161 background: var(--code-bg); 162 border-radius: 0.325rem; 163 opacity: 0; 164 transition: opacity 0.15s ease-out; 165 pointer-events: none; 166 } 167 168 .copy-button:hover::before { 169 opacity: 1; 170 } 171 172 .copy-button:hover { 173 color: var(--text-primary); 174 } 175 176 .copy-button svg { 177 flex-shrink: 0; 178 position: relative; 179 z-index: 1; 180 } 181</style>