1/* Sakana AI Blog Filter 2 * Filters articles by label. 3 * Filter state is stored in URL query parameters: 4 * ?label=research â label filter 5 * ?label=finance â label filter 6 * 7 * Language switching (JP â EN) is handled per-article in the post layout. 8 */ 9(function () { 10 // Display name lookup â ordered for chip display 11 var LABEL_NAMES = { 12 'research': 'Research', 13 'product': 'Product', 14 'finance': 'Finance', 15 'defense-intel': 'Defense & Intel', 16 'partnerships': 'Partnerships', 17 'event-media': 'Event & Media', 18 'funding-ir': 'Funding & IR', 19 'inside-sakana': 'Inside Sakana AI' 20 }; 21 22 // --- State --- 23 var activeLabel = null; // string or null 24 25 // All <article> elements with a data-labels attribute 26 var articles = Array.prototype.slice.call( 27 document.querySelectorAll('article[data-labels]') 28 ); 29 30 // --------------------------------------------------------------- 31 // URL helpers 32 // --------------------------------------------------------------- 33 function readParams() { 34 var p = new URLSearchParams(window.location.search); 35 activeLabel = p.get('label') || null; 36 } 37 38 function writeParams() { 39 var p = new URLSearchParams(); 40 if (activeLabel) p.set('label', activeLabel); 41 var qs = p.toString(); 42 history.replaceState(null, '', qs ? '?' + qs : window.location.pathname); 43 } 44 45 // --------------------------------------------------------------- 46 // Filtering 47 // --------------------------------------------------------------- 48 function applyFilter() { 49 articles.forEach(function (a) { 50 var labelList = a.dataset.labels ? a.dataset.labels.split(',') : []; 51 var ok = !activeLabel || labelList.indexOf(activeLabel) !== -1; 52 a.style.display = ok ? '' : 'none'; 53 }); 54 } 55 56 // Return labels present across all visible articles 57 function labelsInUse() { 58 var seen = {}; 59 articles.forEach(function (a) { 60 if (a.dataset.labels) { 61 a.dataset.labels.split(',').forEach(function (l) { 62 if (l && LABEL_NAMES[l]) seen[l] = true; 63 }); 64 } 65 }); 66 // Return in LABEL_NAMES definition order 67 return Object.keys(LABEL_NAMES).filter(function (l) { return seen[l]; }); 68 } 69 70 // --------------------------------------------------------------- 71 // Render 72 // --------------------------------------------------------------- 73 function render() { 74 var el = document.getElementById('label-chips'); 75 if (!el) return; 76 77 var labels = labelsInUse(); 78 79 var html = '<button class="cat-chip' + (!activeLabel ? ' active' : '') + 80 '" data-label="">All</button>'; 81 labels.forEach(function (label) { 82 var active = activeLabel === label; 83 html += '<button class="cat-chip' + (active ? ' active' : '') + 84 '" data-label="' + label + '">' + LABEL_NAMES[label] + '</button>'; 85 }); 86 el.innerHTML = html; 87 88 el.querySelectorAll('.cat-chip').forEach(function (btn) { 89 btn.addEventListener('click', function () { 90 activeLabel = btn.dataset.label || null; 91 writeParams(); 92 render(); 93 applyFilter(); 94 }); 95 }); 96 97 renderPubLink(); 98 } 99 100 // Show a small link to pub.sakana.ai only when the Research filter is active 101 function renderPubLink() { 102 var container = document.getElementById('blog-filter'); 103 if (!container) return; 104 105 var link = document.getElementById('pub-link'); 106 if (activeLabel === 'research') { 107 if (!link) { 108 link = document.createElement('p'); 109 link.id = 'pub-link'; 110 link.className = 'pub-link'; 111 link.style.marginTop = '1.4em'; 112 link.style.marginBottom = '-0.5em'; 113 link.innerHTML = '<a href="https://pub.sakana.ai/" ' + 114 'target="_blank" rel="noopener">' + 115 'See more interactive research blogs</a>'; 116 container.appendChild(link); 117 } 118 } else if (link) { 119 link.parentNode.removeChild(link); 120 } 121 } 122 123 // --------------------------------------------------------------- 124 // Boot 125 // --------------------------------------------------------------- 126 readParams(); 127 render(); 128 applyFilter(); 129 130})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.