mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-14 20:48:17 +08:00
169 lines
5.0 KiB
JavaScript
169 lines
5.0 KiB
JavaScript
// Clashoo 文档站交互:主题、手机目录、站内搜索。无第三方依赖。
|
|
(function () {
|
|
'use strict';
|
|
|
|
var THEME_KEY = 'clashoo-docs-theme';
|
|
var root = document.documentElement;
|
|
|
|
function applyTheme(theme) {
|
|
if (theme) root.setAttribute('data-theme', theme);
|
|
else root.removeAttribute('data-theme');
|
|
var toggle = document.getElementById('theme-toggle');
|
|
if (toggle) toggle.setAttribute('aria-pressed', String(theme === 'dark'));
|
|
}
|
|
|
|
try {
|
|
applyTheme(localStorage.getItem(THEME_KEY));
|
|
} catch (e) {}
|
|
|
|
document.addEventListener('click', function (event) {
|
|
var toggle = event.target.closest('#theme-toggle');
|
|
if (toggle) {
|
|
var next = root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
|
|
try {
|
|
localStorage.setItem(THEME_KEY, next);
|
|
} catch (e) {}
|
|
applyTheme(next);
|
|
return;
|
|
}
|
|
|
|
var menu = event.target.closest('#menu-toggle');
|
|
if (menu) {
|
|
var sidebar = document.getElementById('sidebar');
|
|
if (!sidebar) return;
|
|
var open = sidebar.classList.toggle('open');
|
|
menu.setAttribute('aria-expanded', String(open));
|
|
}
|
|
});
|
|
|
|
// ── 站内搜索 ──
|
|
var overlay = document.getElementById('search');
|
|
var input = document.getElementById('search-input');
|
|
var results = document.getElementById('search-results');
|
|
var index = null;
|
|
var active = -1;
|
|
|
|
function loadIndex() {
|
|
if (index) return Promise.resolve(index);
|
|
return fetch('search-index.json')
|
|
.then(function (response) {
|
|
return response.ok ? response.json() : [];
|
|
})
|
|
.then(function (data) {
|
|
index = data;
|
|
return index;
|
|
})
|
|
.catch(function () {
|
|
index = [];
|
|
return index;
|
|
});
|
|
}
|
|
|
|
function openSearch() {
|
|
if (!overlay) return;
|
|
overlay.hidden = false;
|
|
loadIndex().then(function () {
|
|
if (input) {
|
|
input.value = '';
|
|
input.focus();
|
|
}
|
|
render('');
|
|
});
|
|
}
|
|
|
|
function closeSearch() {
|
|
if (!overlay) return;
|
|
overlay.hidden = true;
|
|
active = -1;
|
|
}
|
|
|
|
function score(entry, needle) {
|
|
var hits = [];
|
|
if (entry.title.toLowerCase().indexOf(needle) >= 0) hits.push({ url: entry.page, label: entry.title, kind: entry.group });
|
|
entry.headings.forEach(function (heading) {
|
|
if (heading.text.toLowerCase().indexOf(needle) >= 0) {
|
|
hits.push({ url: entry.page + '#' + heading.id, label: heading.text, kind: entry.title });
|
|
}
|
|
});
|
|
return hits;
|
|
}
|
|
|
|
function render(query) {
|
|
if (!results) return;
|
|
var needle = query.trim().toLowerCase();
|
|
results.innerHTML = '';
|
|
active = -1;
|
|
if (!needle || !index) return;
|
|
|
|
var hits = [];
|
|
index.forEach(function (entry) {
|
|
hits = hits.concat(score(entry, needle));
|
|
if (hits.length >= 24) return;
|
|
});
|
|
if (!hits.length && index) {
|
|
index.forEach(function (entry) {
|
|
if (hits.length >= 8) return;
|
|
if (entry.text.toLowerCase().indexOf(needle) >= 0) hits.push({ url: entry.page, label: entry.title, kind: '正文命中 · ' + entry.group });
|
|
});
|
|
}
|
|
|
|
hits.slice(0, 24).forEach(function (hit) {
|
|
var item = document.createElement('li');
|
|
var link = document.createElement('a');
|
|
link.href = hit.url;
|
|
link.textContent = hit.label;
|
|
var meta = document.createElement('small');
|
|
meta.textContent = hit.kind;
|
|
link.appendChild(meta);
|
|
item.appendChild(link);
|
|
results.appendChild(item);
|
|
});
|
|
}
|
|
|
|
document.addEventListener('click', function (event) {
|
|
if (event.target.closest('[data-search-open]')) {
|
|
openSearch();
|
|
return;
|
|
}
|
|
if (event.target.closest('[data-search-close]')) {
|
|
closeSearch();
|
|
return;
|
|
}
|
|
if (overlay && !overlay.hidden && event.target === overlay) closeSearch();
|
|
});
|
|
|
|
document.addEventListener('input', function (event) {
|
|
if (event.target === input) render(input.value);
|
|
});
|
|
|
|
document.addEventListener('keydown', function (event) {
|
|
var isK = event.key === 'k' || event.key === 'K';
|
|
if (isK && (event.metaKey || event.ctrlKey)) {
|
|
event.preventDefault();
|
|
if (overlay && overlay.hidden) openSearch();
|
|
else closeSearch();
|
|
return;
|
|
}
|
|
if (event.key === 'Escape' && overlay && !overlay.hidden) {
|
|
closeSearch();
|
|
return;
|
|
}
|
|
if (overlay && overlay.hidden) return;
|
|
if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp' && event.key !== 'Enter') return;
|
|
|
|
var links = results ? Array.prototype.slice.call(results.querySelectorAll('a')) : [];
|
|
if (!links.length) return;
|
|
if (event.key === 'Enter' && active >= 0) {
|
|
links[active].click();
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
active = event.key === 'ArrowDown' ? (active + 1) % links.length : (active + links.length - 1) % links.length;
|
|
links.forEach(function (link, i) {
|
|
if (i === active) link.setAttribute('data-active', 'true');
|
|
else link.removeAttribute('data-active');
|
|
});
|
|
links[active].scrollIntoView({ block: 'nearest' });
|
|
});
|
|
})();
|