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 a2f7dec4d7c309420bc9d4e87b4de27dcd8a4142 479 lines 12 kB view raw
1<div class="tag-card"> 2 <div class="tag-container"> 3 <div id="tag-component" class="tag-component"> 4 <button id="add-button" class="add-button"> 5 <svg 6 class="add-icon" 7 xmlns="http://www.w3.org/2000/svg" 8 viewBox="0 0 16 16" 9 width="16" 10 height="16" 11 > 12 <path 13 d="M7.75 2a.75.75 0 0 1 .75.75V7h4.25a.75.75 0 0 1 0 1.5H8.5v4.25a.75.75 0 0 1-1.5 0V8.5H2.75a.75.75 0 0 1 0-1.5H7V2.75A.75.75 0 0 1 7.75 2Z" 14 ></path> 15 </svg> 16 </button> 17 18 <div id="input-state" class="input-state"> 19 <input id="tag-input" type="text" placeholder="Tag Name" class="tag-input" /> 20 <button id="confirm-button" class="confirm-button disabled"> 21 <svg 22 class="confirm-icon" 23 xmlns="http://www.w3.org/2000/svg" 24 viewBox="0 0 16 16" 25 width="16" 26 height="16" 27 > 28 <path 29 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" 30 ></path> 31 </svg> 32 </button> 33 <button id="cancel-button" class="cancel-button"> 34 <svg 35 class="cancel-icon" 36 xmlns="http://www.w3.org/2000/svg" 37 viewBox="0 0 16 16" 38 width="16" 39 height="16" 40 > 41 <path 42 d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z" 43 ></path> 44 </svg> 45 </button> 46 </div> 47 48 <div id="tag-display" class="tag-display"> 49 <span id="tag-text" class="tag-text"></span> 50 <button id="delete-button" class="delete-button"> 51 <svg 52 class="delete-icon" 53 xmlns="http://www.w3.org/2000/svg" 54 viewBox="0 0 16 16" 55 width="16" 56 height="16" 57 > 58 <path 59 d="M11 1.75V3h2.25a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1 0-1.5H5V1.75C5 .784 5.784 0 6.75 0h2.5C10.216 0 11 .784 11 1.75ZM4.496 6.675l.66 6.6a.25.25 0 0 0 .249.225h5.19a.25.25 0 0 0 .249-.225l.66-6.6a.75.75 0 0 1 1.492.149l-.66 6.6A1.748 1.748 0 0 1 10.595 15h-5.19a1.75 1.75 0 0 1-1.741-1.575l-.66-6.6a.75.75 0 1 1 1.492-.15ZM6.5 1.75V3h3V1.75a.25.25 0 0 0-.25-.25h-2.5a.25.25 0 0 0-.25.25Z" 60 ></path> 61 </svg> 62 </button> 63 </div> 64 </div> 65 </div> 66</div> 67 68<script is:inline> 69 function setupTag() { 70 let currentState = 'add' // 'add', 'input', 'display' 71 let tagValue = localStorage.getItem('tagValue') || '' 72 73 const addButton = document.getElementById('add-button') 74 const inputState = document.getElementById('input-state') 75 const tagDisplay = document.getElementById('tag-display') 76 const tagInput = document.getElementById('tag-input') 77 const confirmButton = document.getElementById('confirm-button') 78 const cancelButton = document.getElementById('cancel-button') 79 const deleteButton = document.getElementById('delete-button') 80 const tagText = document.getElementById('tag-text') 81 82 if (tagValue) { 83 addButton.classList.add('hidden') 84 inputState.classList.remove('active') 85 tagDisplay.classList.add('active') 86 tagText.textContent = truncateText(tagValue) 87 currentState = 'display' 88 } else { 89 addButton.classList.remove('hidden') 90 inputState.classList.remove('active') 91 tagDisplay.classList.remove('active') 92 tagInput.value = '' 93 currentState = 'add' 94 } 95 96 // Switch to input state 97 function switchToInput() { 98 currentState = 'input' 99 addButton.classList.add('hidden') 100 setTimeout(() => { 101 inputState.classList.add('active') 102 tagInput.focus() 103 }, 100) 104 } 105 106 // Switch to display state 107 function switchToDisplay() { 108 currentState = 'display' 109 inputState.classList.remove('active') 110 setTimeout(() => { 111 tagDisplay.classList.add('active') 112 tagText.textContent = truncateText(tagValue) 113 // Store to localStorage 114 localStorage.setItem('tagValue', tagValue) 115 }, 300) 116 } 117 118 // Return to add state 119 function switchToAdd() { 120 if (currentState === 'display') { 121 tagDisplay.classList.remove('active') 122 } else if (currentState === 'input') { 123 inputState.classList.remove('active') 124 } 125 currentState = 'add' 126 setTimeout(() => { 127 addButton.classList.remove('hidden') 128 tagValue = '' 129 tagInput.value = '' 130 localStorage.removeItem('tagValue') 131 updateConfirmButton() 132 }, 250) 133 } 134 135 // Update confirm button state 136 function updateConfirmButton() { 137 if (tagInput.value.trim()) { 138 confirmButton.classList.remove('disabled') 139 } else { 140 confirmButton.classList.add('disabled') 141 } 142 } 143 144 // Truncate text to max 24 characters 145 function truncateText(text, maxLength = 24) { 146 if (text.length <= maxLength) { 147 return text 148 } 149 return text.substring(0, maxLength) + '...' 150 } 151 152 // Bind events 153 addButton.onclick = switchToInput 154 155 tagInput.oninput = function (e) { 156 const inputValue = e.target.value 157 if (inputValue.length > 24) { 158 e.target.value = inputValue.substring(0, 24) 159 tagValue = inputValue 160 } else { 161 tagValue = inputValue 162 } 163 updateConfirmButton() 164 } 165 166 tagInput.onkeydown = function (e) { 167 if (e.key === 'Enter' && tagValue.trim()) { 168 switchToDisplay() 169 } else if (e.key === 'Escape') { 170 switchToAdd() 171 } 172 } 173 174 confirmButton.onclick = function () { 175 if (tagValue.trim()) { 176 switchToDisplay() 177 } 178 } 179 180 cancelButton.onclick = switchToAdd 181 deleteButton.onclick = switchToAdd 182 } 183 184 setupTag() 185 186 document.addEventListener('astro:page-load', setupTag) 187</script> 188 189<style> 190 .tag-card { 191 border: 1px solid var(--border); 192 width: 100%; 193 height: 12rem; 194 display: flex; 195 align-items: center; 196 justify-content: center; 197 border-radius: 10px; 198 } 199 200 .tag-container { 201 display: flex; 202 justify-content: center; 203 align-items: center; 204 width: 100%; 205 padding: 0 2rem; 206 overflow: hidden; 207 } 208 209 .tag-component { 210 display: flex; 211 align-items: center; 212 justify-content: center; 213 gap: 0.5rem; 214 position: relative; 215 width: 100%; 216 min-height: 40px; 217 } 218 219 .add-button { 220 background-color: var(--text-primary); 221 color: var(--bg); 222 border: none; 223 border-radius: 50%; 224 width: 36px; 225 height: 36px; 226 cursor: pointer; 227 display: flex; 228 align-items: center; 229 justify-content: center; 230 transition: 231 all 0.3s ease, 232 visibility 0s; 233 position: absolute; 234 top: 50%; 235 left: 50%; 236 transform: translate(-50%, -50%) scale(1); 237 z-index: 1; 238 opacity: 1; 239 visibility: visible; 240 overflow: visible; 241 will-change: transform; 242 -webkit-transform: translate(-50%, -50%) scale(1); 243 box-sizing: border-box; 244 padding: 0; 245 margin: 0; 246 } 247 248 .add-button.hidden { 249 opacity: 0; 250 transform: translate(-50%, -50%) scale(0.8); 251 pointer-events: none; 252 visibility: hidden; 253 transition: 254 all 0.3s ease, 255 visibility 0s 0.2s; 256 } 257 258 .add-icon, 259 .confirm-icon, 260 .cancel-icon, 261 .delete-icon { 262 fill: currentColor; 263 width: 1rem; 264 height: 1rem; 265 position: relative; 266 display: block; 267 transform: translateZ(0); 268 } 269 270 .add-button:hover { 271 opacity: 0.8; 272 transform: translate(-50%, -50%) scale(1); 273 -webkit-transform: translate(-50%, -50%) scale(1); 274 } 275 276 .input-state { 277 display: flex; 278 align-items: center; 279 gap: 0.125rem; 280 background-color: var(--astro-code-background); 281 border: 1px solid var(--code-bg); 282 border-radius: 18px; 283 padding: 0.28125rem 0.375rem; 284 width: 40px; 285 max-width: 40px; 286 opacity: 0; 287 overflow: hidden; 288 transition: all 0.3s ease; 289 position: relative; 290 z-index: 2; 291 pointer-events: none; 292 } 293 294 .input-state.active { 295 width: 10rem; 296 max-width: 10rem; 297 opacity: 1; 298 pointer-events: all; 299 } 300 301 .tag-input { 302 background: transparent; 303 border: none; 304 outline: none; 305 color: var(--text-primary); 306 font-size: 0.9rem; 307 font-family: var(--mono); 308 min-width: 4rem; 309 padding: 0.25rem 0.5rem; 310 opacity: 0; 311 transform: translateX(-8px); 312 transition: 313 opacity 0.2s ease 0.15s, 314 transform 0.2s ease 0.15s; 315 } 316 317 .input-state.active .tag-input { 318 opacity: 1; 319 transform: translateX(0); 320 } 321 322 .tag-input::placeholder { 323 color: var(--text-tertiary); 324 } 325 326 .confirm-button, 327 .cancel-button { 328 background: none; 329 border: none; 330 border-radius: 50%; 331 width: 24px; 332 height: 24px; 333 cursor: pointer; 334 display: flex; 335 align-items: center; 336 justify-content: center; 337 font-size: 0.8rem; 338 opacity: 0; 339 transform: scale(0.8); 340 transition: all 0.2s ease; 341 position: relative; 342 min-width: 24px; 343 min-height: 24px; 344 } 345 346 .confirm-button::before, 347 .cancel-button::before { 348 content: ''; 349 position: absolute; 350 top: 50%; 351 left: 50%; 352 transform: translate(-50%, -50%); 353 border-radius: 50%; 354 background-color: var(--code-bg); 355 opacity: 0; 356 transition: opacity 0.2s ease; 357 z-index: -1; 358 width: 28px; 359 height: 28px; 360 } 361 362 .confirm-button:hover::before, 363 .cancel-button:hover::before { 364 opacity: 1; 365 } 366 367 .input-state.active .confirm-button, 368 .input-state.active .cancel-button { 369 transform: scale(1); 370 } 371 372 .confirm-button { 373 color: var(--text-primary); 374 opacity: 0.6; 375 } 376 377 .confirm-button.disabled { 378 opacity: 0.3; 379 cursor: not-allowed; 380 } 381 382 .confirm-button:not(.disabled):hover { 383 opacity: 1; 384 } 385 386 .confirm-button.disabled:hover::before { 387 opacity: 0; 388 } 389 390 .cancel-button { 391 color: var(--text-primary); 392 opacity: 0.6; 393 } 394 395 .cancel-button:hover { 396 opacity: 1; 397 } 398 399 .tag-display { 400 display: flex; 401 align-items: center; 402 gap: 0.25rem; 403 background-color: var(--astro-code-background); 404 border: 1px solid var(--code-bg); 405 border-radius: 18px; 406 padding: 0.28125rem 0.325rem 0.28125rem 0.75rem; 407 position: absolute; 408 top: 50%; 409 left: 50%; 410 transform: translate(-50%, -50%); 411 z-index: 3; 412 opacity: 0; 413 pointer-events: none; 414 transition: all 0.25s ease-out; 415 will-change: transform, opacity; 416 } 417 418 .tag-display > * { 419 margin-right: 0.125rem; 420 } 421 422 .tag-display > *:last-child { 423 margin-right: 0; 424 } 425 426 .tag-display.active { 427 opacity: 1; 428 transform: translate(-50%, -50%); 429 pointer-events: all; 430 } 431 432 .tag-text { 433 color: var(--text-primary); 434 font-size: 0.9rem; 435 font-family: var(--mono); 436 } 437 438 .delete-button { 439 background: none; 440 border: none; 441 border-radius: 50%; 442 width: 24px; 443 height: 24px; 444 cursor: pointer; 445 display: flex; 446 align-items: center; 447 justify-content: center; 448 font-size: 0.8rem; 449 color: var(--text-primary); 450 opacity: 0.6; 451 transition: all 0.2s ease; 452 position: relative; 453 min-width: 24px; 454 min-height: 24px; 455 } 456 457 .delete-button::before { 458 content: ''; 459 position: absolute; 460 top: 50%; 461 left: 50%; 462 transform: translate(-50%, -50%); 463 border-radius: 50%; 464 background-color: var(--code-bg); 465 opacity: 0; 466 transition: opacity 0.2s ease; 467 z-index: -1; 468 width: 28px; 469 height: 28px; 470 } 471 472 .delete-button:hover { 473 opacity: 1; 474 } 475 476 .delete-button:hover::before { 477 opacity: 1; 478 } 479</style>