mirror of
https://github.com/baz-scm/awesome-reviewers.git
synced 2025-08-20 18:58:52 +03:00
Add reviewer bundling UI
This commit is contained in:
@@ -816,6 +816,23 @@ h1, h2, h3, h4, h5, h6 {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.bundle-button {
|
||||
background: none;
|
||||
border: 1px solid var(--border);
|
||||
color: var(--text-secondary);
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.bundle-button.added {
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
|
||||
.reviewer-card .share-button {
|
||||
position: absolute;
|
||||
@@ -849,6 +866,37 @@ h1, h2, h3, h4, h5, h6 {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.bundle-bar {
|
||||
position: fixed;
|
||||
bottom: 1rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 8px;
|
||||
box-shadow: var(--shadow-lg);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.bundle-bar button {
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
border: 1px solid var(--accent);
|
||||
border-radius: 4px;
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bundle-bar button#bundle-clear {
|
||||
background: var(--danger-border);
|
||||
border-color: var(--danger-border);
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.footer {
|
||||
background: var(--bg-secondary);
|
||||
|
||||
@@ -115,3 +115,94 @@ if (menuToggle && headerEl) {
|
||||
if (closeIcon) closeIcon.style.display = open ? 'block' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
// Reviewer bundling functionality
|
||||
const bundleBar = document.getElementById('bundle-bar');
|
||||
const bundleCountEl = document.getElementById('bundle-count');
|
||||
let bundleCart = [];
|
||||
|
||||
function updateBundleUI() {
|
||||
const buttons = document.querySelectorAll('.bundle-button');
|
||||
buttons.forEach(btn => {
|
||||
const slug = btn.dataset.slug;
|
||||
if (bundleCart.includes(slug)) {
|
||||
btn.classList.add('added');
|
||||
btn.textContent = 'Added';
|
||||
} else {
|
||||
btn.classList.remove('added');
|
||||
btn.textContent = 'Add';
|
||||
}
|
||||
});
|
||||
|
||||
bundleCountEl.textContent = bundleCart.length;
|
||||
bundleBar.style.display = bundleCart.length > 0 ? 'flex' : 'none';
|
||||
}
|
||||
|
||||
function toggleBundle(e, slug) {
|
||||
e.stopPropagation();
|
||||
const idx = bundleCart.indexOf(slug);
|
||||
if (idx >= 0) {
|
||||
bundleCart.splice(idx, 1);
|
||||
} else {
|
||||
bundleCart.push(slug);
|
||||
}
|
||||
updateBundleUI();
|
||||
}
|
||||
|
||||
function clearBundle() {
|
||||
bundleCart = [];
|
||||
updateBundleUI();
|
||||
}
|
||||
|
||||
async function downloadBundle() {
|
||||
if (bundleCart.length === 0) return;
|
||||
|
||||
const sections = [];
|
||||
for (const slug of bundleCart) {
|
||||
const res = await fetch(`/_reviewers/${slug}.md`);
|
||||
if (!res.ok) continue;
|
||||
const text = await res.text();
|
||||
const parsed = parseFrontMatter(text);
|
||||
sections.push(createSection(parsed.meta, parsed.body));
|
||||
}
|
||||
|
||||
const content = '# Bundled Reviewers\n\n' + sections.join('\n');
|
||||
const blob = new Blob([content], { type: 'text/markdown' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'AGENTS.md';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
function parseFrontMatter(text) {
|
||||
if (text.startsWith('---')) {
|
||||
const end = text.indexOf('---', 3);
|
||||
if (end !== -1) {
|
||||
const yaml = text.slice(3, end).trim();
|
||||
const body = text.slice(end + 3).trim();
|
||||
const meta = {};
|
||||
yaml.split(/\n/).forEach(line => {
|
||||
const sep = line.indexOf(':');
|
||||
if (sep !== -1) {
|
||||
const key = line.slice(0, sep).trim();
|
||||
const val = line.slice(sep + 1).trim();
|
||||
meta[key] = val;
|
||||
}
|
||||
});
|
||||
return { meta, body };
|
||||
}
|
||||
}
|
||||
return { meta: {}, body: text };
|
||||
}
|
||||
|
||||
function createSection(meta, body) {
|
||||
const title = meta.title || 'Untitled';
|
||||
const description = meta.description ? `${meta.description}\n` : '';
|
||||
return `## ${title}\n${description}\n${body.trim()}\n`;
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', updateBundleUI);
|
||||
|
||||
@@ -81,6 +81,7 @@ layout: default
|
||||
<div class="card-actions">
|
||||
<a href="{{ reviewer.url }}" class="fullpage-button" onclick="event.stopPropagation()">⛶</a>
|
||||
<button class="share-button" onclick="shareFromCard(event, '{{ slug }}')">Share</button>
|
||||
<button class="bundle-button" data-slug="{{ slug }}" onclick="toggleBundle(event, '{{ slug }}')">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -103,6 +104,12 @@ layout: default
|
||||
</button>
|
||||
<button class="drawer-close" onclick="closeDrawer()">×</button>
|
||||
</div>
|
||||
<div id="drawer-content"></div>
|
||||
<div id="drawer-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="bundle-bar" class="bundle-bar" style="display:none">
|
||||
<span id="bundle-count">0</span> selected
|
||||
<button id="bundle-download" onclick="downloadBundle()">Download AGENTS.md</button>
|
||||
<button id="bundle-clear" onclick="clearBundle()">Clear</button>
|
||||
</div>
|
||||
Reference in New Issue
Block a user