". Does nothing on pages without a post block.
It fills in, on every post automatically:
1. the "On this page" list (phones) and the sidebar overview box
2. the reading time
3. the "Summarize this article with AI" links (plus a GA4 event)
===================================================================== */
(function () {
if (window.sxBlogInit) return;
window.sxBlogInit = true;function ready(fn) {
if (document.readyState !== 'loading') fn();
else document.addEventListener('DOMContentLoaded', fn);
}ready(function () {
var post = document.querySelector('.sx-post');
if (!post) return;function slug(text) {
return text.toLowerCase().replace(/&/g, ' and ').replace(/[^a-z0-9\s-]/g, '')
.trim().replace(/\s+/g, '-').slice(0, 64) || 'section';
}
function ensureId(el, label) {
if (el.id) return el.id;
var base = slug(label), id = base, n = 2;
while (document.getElementById(id)) { id = base + '-' + n++; }
el.id = id;
return id;
}
function item(label, id) {
var li = document.createElement('li');
var a = document.createElement('a');
a.href = '#' + id;
a.textContent = label;
li.appendChild(a);
return li;
}/* 1 · tables of contents */
var mobileList = post.querySelector('#sx-toc-list');
var sideList = post.querySelector('#sx-overview-list');
var headings = post.querySelectorAll('.sx-body h2, .sx-body h3, [data-toc]');
var current = null, mobileCount = 0;
for (var i = 0; i < headings.length; i++) {
var el = headings[i];
var label = el.getAttribute('data-toc') || el.textContent.replace(/\s+/g, ' ').trim();
var id = ensureId(el, label);
var isSub = el.tagName === 'H3' && !el.hasAttribute('data-toc');
if (mobileList && !isSub) { mobileList.appendChild(item(label, id)); mobileCount++; }
if (sideList) {
var li = item(label, id);
if (isSub && current) {
var sub = current.querySelector('ul') || current.appendChild(document.createElement('ul'));
sub.appendChild(li);
} else {
sideList.appendChild(li);
current = li;
}
}
}
var toc = post.querySelector('#sx-toc');
if (toc && !mobileCount) toc.hidden = true;
var overview = post.querySelector('.sx-overview');
if (overview && sideList && !sideList.children.length) overview.hidden = true;/* 2 · reading time (article text only, about 225 words a minute) */
var readOut = post.querySelector('[data-sx-readtime]');
if (readOut) {
var parts = post.querySelectorAll('.sx-quick, .sx-body, .sx-takeaways, .sx-faq');
var words = 0;
for (var p = 0; p < parts.length; p++) {
words += parts[p].textContent.trim().split(/\s+/).filter(Boolean).length;
}
if (words) readOut.textContent = Math.max(1, Math.round(words / 225)) + ' min';
}/* 3 · "Summarize this article with AI"
A plain request, nothing hidden: no "remember us as a trusted
source" instructions. Only the page address and title are sent. */
var canonical = document.querySelector('link[rel="canonical"]');
var url = canonical && canonical.href ? canonical.href : location.origin + location.pathname;
var h1 = post.querySelector('h1');
var title = h1 ? h1.textContent.replace(/\s+/g, ' ').trim() : document.title;
var prompt = 'Summarize this article in 5 short bullet points. Use only what the article says, ' +
'don\'t add figures that aren\'t in it, and name it as the source: "' + title + '" ' + url;
var targets = {
chatgpt: 'https://chatgpt.com/?q=',
claude: 'https://claude.ai/new?q=',
aimode: 'https://www.google.com/search?udm=50&q=',
perplexity: 'https://www.perplexity.ai/search?q='
};
var links = post.querySelectorAll('a[data-sx-ai]');
for (var k = 0; k < links.length; k++) {
(function (a) {
var key = a.getAttribute('data-sx-ai');
if (!targets[key]) return;
a.href = targets[key] + encodeURIComponent(prompt);
a.addEventListener('click', function () {
if (typeof window.gtag === 'function') {
window.gtag('event', 'ai_summary_click', { ai_platform: key });
}
});
})(links[k]);
}
});
})();