document.addEventListener('DOMContentLoaded', () => {
const grid = document.getElementById('grid-container');
const searchInput = document.getElementById('search-input');
let allRunbooks = [];
fetch('./registry.json')
.then(response => {
if (!response.ok) throw new Error("Failed to load registry");
return response.json();
})
.then(data => {
allRunbooks = data;
renderRunbooks(allRunbooks);
})
.catch(err => {
grid.innerHTML = `<div class="loading" style="color: #ff4b4b;">Error: ${err.message}</div>`;
});
function renderRunbooks(items) {
grid.innerHTML = '';
if (items.length === 0) {
grid.innerHTML = '<div class="loading">No runbooks found.</div>';
return;
}
items.forEach(book => {
const card = document.createElement('div');
card.className = 'card';
const repoUrl = book.url.replace('.git', '');
const repoName = repoUrl.split('/').slice(-2).join('/');
const cloneCmd = `compass clone ${book.url}`;
card.innerHTML = `
<div class="card-header">
<div>
<h3>${book.name}</h3>
<div class="author">by ${book.author || 'Community'}</div>
</div>
</div>
<p class="description">${book.description}</p>
<div class="snippet">
<code>${cloneCmd}</code>
<button class="copy-btn" onclick="copyToClipboard('${cloneCmd}', this)" title="Copy command">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
</button>
</div>
<div class="tags">
${(book.tags || []).map(tag => `<span class="tag">#${tag}</span>`).join('')}
<span class="tag" style="margin-left:auto; opacity:0.6;">📦 v${book.version || '1.0'}</span>
</div>
`;
grid.appendChild(card);
});
}
searchInput.addEventListener('input', (e) => {
const query = e.target.value.toLowerCase();
const filtered = allRunbooks.filter(book =>
book.name.toLowerCase().includes(query) ||
book.description.toLowerCase().includes(query) ||
(book.tags && book.tags.some(t => t.toLowerCase().includes(query)))
);
renderRunbooks(filtered);
});
});
function copyToClipboard(text, btn) {
navigator.clipboard.writeText(text).then(() => {
const originalIcon = btn.innerHTML;
btn.innerHTML = '<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#4ade80" stroke-width="2"><polyline points="20 6 9 17 4 12"></polyline></svg>';
setTimeout(() => {
btn.innerHTML = originalIcon;
}, 2000);
});
}