slack status without the slack status.zzstoatzz.io
hatk statusphere
0
fork

Configure Feed

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

integrate find-bufo.com semantic search into bufo picker

When the custom (🐸) tab is active, the search bar uses the
find-bufo API for semantic search instead of basic name filtering.
Results show relevance scores. 300ms debounce on API calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

zzstoatzz 56b0e322 d339a835

+66 -7
+42 -5
site/app.js
··· 464 464 return bufoList; 465 465 } 466 466 467 + async function searchBufos(query, topK = 20) { 468 + const params = new URLSearchParams({ query, top_k: topK }); 469 + const res = await fetch(`https://find-bufo.fly.dev/api/search?${params}`); 470 + if (!res.ok) throw new Error('bufo search failed'); 471 + const data = await res.json(); 472 + return data.results; 473 + } 474 + 467 475 async function loadEmojiData() { 468 476 if (emojiData) return emojiData; 469 477 try { ··· 527 535 <button class="category-btn" data-category="flags">🏁</button> 528 536 </div> 529 537 <div class="emoji-grid"></div> 530 - <div class="bufo-helper hidden"><a href="https://find-bufo.fly.dev/" target="_blank">need help finding a bufo?</a></div> 538 + <div class="bufo-helper hidden"><a href="https://find-bufo.com" target="_blank">powered by find-bufo.com</a></div> 531 539 </div> 532 540 `; 533 541 ··· 540 548 541 549 let currentCategory = 'frequent'; 542 550 let data = null; 551 + let bufoSearchTimer = null; 543 552 544 553 async function renderCategory(cat) { 545 554 currentCategory = cat; ··· 547 556 bufoHelper.classList.toggle('hidden', cat !== 'custom'); 548 557 549 558 if (cat === 'custom') { 559 + search.placeholder = 'describe a bufo... try "happy" or "apocalyptic"'; 550 560 grid.classList.add('bufo-grid'); 551 561 grid.innerHTML = '<div class="loading">loading bufos...</div>'; 552 562 try { ··· 562 572 return; 563 573 } 564 574 575 + search.placeholder = 'search emojis...'; 576 + 565 577 grid.classList.remove('bufo-grid'); 566 578 567 579 // Load user's frequent emojis for the frequent category ··· 588 600 function close() { 589 601 overlay.classList.add('hidden'); 590 602 search.value = ''; 603 + clearTimeout(bufoSearchTimer); 591 604 } 592 605 593 606 function open() { ··· 612 625 const q = search.value.trim(); 613 626 if (!q) { renderCategory(currentCategory); return; } 614 627 615 - // Search both emojis and bufos 628 + // When on the custom tab, use the findbufo semantic search API 629 + if (currentCategory === 'custom') { 630 + clearTimeout(bufoSearchTimer); 631 + bufoSearchTimer = setTimeout(async () => { 632 + grid.classList.add('bufo-grid'); 633 + bufoHelper.classList.remove('hidden'); 634 + grid.innerHTML = '<div class="loading">searching bufos...</div>'; 635 + try { 636 + const results = await searchBufos(q, 30); 637 + if (search.value.trim() !== q) return; // stale 638 + if (results.length === 0) { 639 + grid.innerHTML = '<div class="no-results">no bufos found</div>'; 640 + return; 641 + } 642 + grid.innerHTML = results.map(r => ` 643 + <button class="emoji-btn bufo-btn" data-emoji="custom:${r.name}" title="${r.name} (${Math.round(r.score * 100)}%)"> 644 + <img src="https://all-the.bufo.zone/${r.name}.png" alt="${r.name}" loading="lazy" onerror="this.src='https://all-the.bufo.zone/${r.name}.gif'"> 645 + <span class="bufo-score">${Math.round(r.score * 100)}%</span> 646 + </button> 647 + `).join(''); 648 + } catch (e) { 649 + grid.innerHTML = '<div class="no-results">search failed — try again</div>'; 650 + } 651 + }, 300); 652 + return; 653 + } 654 + 655 + // Default: search both emojis and bufos by name 616 656 if (!data) data = await loadEmojiData(); 617 657 const emojiResults = searchEmojis(q, data); 618 658 619 - // Search bufos by name 620 659 let bufoResults = []; 621 660 try { 622 661 const bufos = await loadBufoList(); ··· 633 672 } 634 673 635 674 let html = ''; 636 - // Show emoji results first 637 675 html += emojiResults.map(e => `<button class="emoji-btn" data-emoji="${e}">${e}</button>`).join(''); 638 - // Then bufo results 639 676 html += bufoResults.map(name => ` 640 677 <button class="emoji-btn bufo-btn" data-emoji="custom:${name}" title="${name}"> 641 678 <img src="https://all-the.bufo.zone/${name}.png" alt="${name}" onerror="this.src='https://all-the.bufo.zone/${name}.gif'">
+24 -2
site/styles.css
··· 889 889 890 890 .bufo-btn { 891 891 padding: 0.25rem; 892 + position: relative; 892 893 } 893 894 894 895 .bufo-grid .bufo-btn { ··· 902 903 max-width: 48px; 903 904 max-height: 48px; 904 905 object-fit: contain; 906 + } 907 + 908 + .bufo-score { 909 + position: absolute; 910 + bottom: 1px; 911 + right: 1px; 912 + font-size: 0.6rem; 913 + background: rgba(0, 0, 0, 0.6); 914 + color: #fff; 915 + padding: 1px 3px; 916 + border-radius: 3px; 917 + line-height: 1; 918 + pointer-events: none; 905 919 } 906 920 907 921 .loading { ··· 955 969 } 956 970 957 971 .bufo-helper { 958 - padding: 0.75rem; 972 + padding: 0.5rem 0.75rem; 959 973 text-align: center; 960 974 border-top: 1px solid var(--border); 961 975 } 962 976 963 977 .bufo-helper a { 978 + color: var(--text-secondary); 979 + font-size: 0.75rem; 980 + text-decoration: none; 981 + opacity: 0.7; 982 + transition: opacity 0.15s; 983 + } 984 + 985 + .bufo-helper a:hover { 986 + opacity: 1; 964 987 color: var(--accent); 965 - font-size: 0.875rem; 966 988 } 967 989 968 990 /* Settings Modal */