89 lines
3.9 KiB
JavaScript
89 lines
3.9 KiB
JavaScript
// ═══════════════════════════════════════════════════════
|
|
// Particles
|
|
// ═══════════════════════════════════════════════════════
|
|
(function initParticles() {
|
|
const c = document.getElementById('particles');
|
|
for (let i = 0; i < 30; i++) {
|
|
const p = document.createElement('div');
|
|
p.className = 'particle';
|
|
p.style.left = Math.random() * 100 + '%';
|
|
p.style.animationDelay = Math.random() * 15 + 's';
|
|
p.style.animationDuration = (10 + Math.random() * 20) + 's';
|
|
p.style.width = p.style.height = (1 + Math.random() * 3) + 'px';
|
|
c.appendChild(p);
|
|
}
|
|
})();
|
|
|
|
// ═══════════════════════════════════════════════════════
|
|
// Navigation
|
|
// ═══════════════════════════════════════════════════════
|
|
function showPage(name) {
|
|
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
|
|
document.getElementById('page-' + name).classList.add('active');
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════
|
|
// Search & Filter
|
|
// ═══════════════════════════════════════════════════════
|
|
function filterTools(query) {
|
|
const q = query.toLowerCase();
|
|
document.querySelectorAll('.tool-card').forEach(card => {
|
|
const name = card.dataset.name.toLowerCase();
|
|
card.style.display = name.includes(q) ? '' : 'none';
|
|
});
|
|
}
|
|
function filterCategory(cat, btn) {
|
|
document.querySelectorAll('.cat-btn').forEach(b => b.classList.remove('active'));
|
|
if (btn) btn.classList.add('active');
|
|
document.querySelectorAll('.tool-card').forEach(card => {
|
|
card.style.display = (cat === 'all' || card.dataset.cat === cat) ? '' : 'none';
|
|
});
|
|
}
|
|
// Ctrl+K to focus search
|
|
document.addEventListener('keydown', e => {
|
|
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
|
e.preventDefault();
|
|
const el = document.getElementById('searchInput');
|
|
if (el) el.focus();
|
|
}
|
|
});
|
|
|
|
// ═══════════════════════════════════════════════════════
|
|
// Helpers
|
|
// ═══════════════════════════════════════════════════════
|
|
// ✦ Change this for production deployment:
|
|
const BASE_URL = window.location.origin; // e.g. "https://winnieapi-v2.yourdomain.com"
|
|
|
|
function copyText(text) {
|
|
navigator.clipboard.writeText(text).then(() => {
|
|
const t = document.getElementById('copyToast');
|
|
t.classList.add('show');
|
|
setTimeout(() => t.classList.remove('show'), 1500);
|
|
});
|
|
}
|
|
function copyOutput(id) { copyText(document.getElementById(id).value); }
|
|
function setStatus(id, type, msg) {
|
|
const el = document.getElementById(id);
|
|
el.className = 'status ' + type;
|
|
el.textContent = msg;
|
|
}
|
|
async function apiPost(url, body) {
|
|
const r = await fetch(BASE_URL + url, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(body) });
|
|
return r.json();
|
|
}
|
|
async function apiGet(url) {
|
|
const r = await fetch(BASE_URL + url);
|
|
return r.json();
|
|
}
|
|
function toggleApiUsage(btn) {
|
|
btn.classList.toggle('open');
|
|
const body = btn.nextElementSibling;
|
|
body.classList.toggle('open');
|
|
}
|
|
function copyApiCode(btn) {
|
|
const code = btn.parentElement.textContent.replace('Copy', '').trim();
|
|
copyText(code);
|
|
}
|
|
|