Skip to content

Instantly share code, notes, and snippets.

@robkerr1992
Created February 19, 2026 00:56
Show Gist options
  • Select an option

  • Save robkerr1992/d5efdeaa8f7522192e9af6f19b7a7816 to your computer and use it in GitHub Desktop.

Select an option

Save robkerr1992/d5efdeaa8f7522192e9af6f19b7a7816 to your computer and use it in GitHub Desktop.
Project Dashboard — Robert Kerr
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Project Dashboard — Robert Kerr</title>
<style>
:root {
--bg: #0d1117;
--surface: #161b22;
--border: #30363d;
--text: #e6edf3;
--text-muted: #8b949e;
--accent: #58a6ff;
--green: #3fb950;
--yellow: #d29922;
--orange: #db6d28;
--red: #f85149;
--purple: #bc8cff;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: var(--bg); color: var(--text); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; line-height: 1.5; }
.header { background: var(--surface); border-bottom: 1px solid var(--border); padding: 24px 32px; }
.header h1 { font-size: 24px; font-weight: 600; }
.header .subtitle { color: var(--text-muted); font-size: 14px; margin-top: 4px; }
.stats-bar { display: flex; gap: 24px; padding: 16px 32px; background: var(--surface); border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.stat { text-align: center; min-width: 100px; }
.stat .number { font-size: 28px; font-weight: 700; }
.stat .label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted); }
.stat.green .number { color: var(--green); }
.stat.yellow .number { color: var(--yellow); }
.stat.orange .number { color: var(--orange); }
.stat.red .number { color: var(--red); }
.stat.blue .number { color: var(--accent); }
.stat.purple .number { color: var(--purple); }
.filters { padding: 16px 32px; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.filter-btn { background: var(--surface); border: 1px solid var(--border); color: var(--text-muted); padding: 6px 14px; border-radius: 20px; cursor: pointer; font-size: 13px; transition: all 0.15s; }
.filter-btn:hover, .filter-btn.active { background: var(--accent); color: var(--bg); border-color: var(--accent); }
.filter-label { color: var(--text-muted); font-size: 12px; margin-right: 4px; }
.search-box { background: var(--surface); border: 1px solid var(--border); color: var(--text); padding: 6px 14px; border-radius: 6px; font-size: 13px; width: 220px; margin-left: auto; }
.search-box::placeholder { color: var(--text-muted); }
.section { padding: 20px 32px; }
.section-title { font-size: 18px; font-weight: 600; margin-bottom: 16px; display: flex; align-items: center; gap: 8px; }
.section-title .count { background: var(--border); color: var(--text-muted); font-size: 12px; padding: 2px 8px; border-radius: 10px; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 12px; }
.card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 16px; transition: border-color 0.15s; cursor: default; position: relative; }
.card:hover { border-color: var(--accent); }
.card .card-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px; }
.card .name { font-weight: 600; font-size: 15px; color: var(--accent); }
.card .badge { font-size: 11px; padding: 2px 8px; border-radius: 10px; font-weight: 500; white-space: nowrap; }
.badge.active { background: rgba(63, 185, 80, 0.15); color: var(--green); }
.badge.recent { background: rgba(88, 166, 255, 0.15); color: var(--accent); }
.badge.stale { background: rgba(210, 153, 34, 0.15); color: var(--yellow); }
.badge.dormant { background: rgba(139, 148, 158, 0.15); color: var(--text-muted); }
.badge.attention { background: rgba(248, 81, 73, 0.15); color: var(--red); }
.card .commit-msg { color: var(--text-muted); font-size: 13px; margin-bottom: 8px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card .meta { display: flex; gap: 12px; flex-wrap: wrap; }
.card .meta-item { font-size: 12px; color: var(--text-muted); display: flex; align-items: center; gap: 4px; }
.card .meta-item svg { width: 14px; height: 14px; fill: currentColor; }
.card .tags { display: flex; gap: 4px; margin-top: 8px; flex-wrap: wrap; }
.tag { font-size: 10px; padding: 1px 6px; border-radius: 4px; background: rgba(139, 148, 158, 0.15); color: var(--text-muted); }
.tag.stack { background: rgba(188, 140, 255, 0.1); color: var(--purple); }
.tag.prs { background: rgba(63, 185, 80, 0.15); color: var(--green); }
.tag.dirty { background: rgba(248, 81, 73, 0.15); color: var(--red); }
.pr-section { padding: 20px 32px; }
.pr-card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 12px 16px; margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; }
.pr-card .pr-title { font-size: 14px; }
.pr-card .pr-meta { font-size: 12px; color: var(--text-muted); }
.pr-card .pr-author { color: var(--purple); font-size: 12px; }
.legend { padding: 12px 32px; display: flex; gap: 16px; flex-wrap: wrap; font-size: 12px; color: var(--text-muted); border-top: 1px solid var(--border); margin-top: 16px; }
.legend-item { display: flex; align-items: center; gap: 4px; }
.legend-dot { width: 8px; height: 8px; border-radius: 50%; }
.hidden { display: none !important; }
@media (max-width: 768px) {
.grid { grid-template-columns: 1fr; }
.stats-bar { gap: 12px; }
.filters { flex-direction: column; align-items: stretch; }
.search-box { width: 100%; margin-left: 0; }
.header, .section, .pr-section, .filters { padding-left: 16px; padding-right: 16px; }
}
</style>
</head>
<body>
<div class="header">
<h1>Project Dashboard</h1>
<div class="subtitle">Last scanned: February 18, 2026 at 6:47 PM CST &mdash; 48 repos across 2 groups</div>
</div>
<div class="stats-bar">
<div class="stat green"><div class="number">17</div><div class="label">Active (7d)</div></div>
<div class="stat blue"><div class="number">14</div><div class="label">Recent (30d)</div></div>
<div class="stat yellow"><div class="number">10</div><div class="label">Stale (30-90d)</div></div>
<div class="stat orange"><div class="number">7</div><div class="label">Dormant (90d+)</div></div>
<div class="stat red"><div class="number">30</div><div class="label">Open PRs</div></div>
<div class="stat purple"><div class="number">0</div><div class="label">Uncommitted</div></div>
</div>
<div class="filters">
<span class="filter-label">Filter:</span>
<button class="filter-btn active" data-filter="all">All</button>
<button class="filter-btn" data-filter="active">Active</button>
<button class="filter-btn" data-filter="recent">Recent</button>
<button class="filter-btn" data-filter="stale">Stale</button>
<button class="filter-btn" data-filter="dormant">Dormant</button>
<button class="filter-btn" data-filter="attention">Needs Attention</button>
<span style="color:var(--border)">|</span>
<button class="filter-btn" data-group="auctic">Auctic</button>
<button class="filter-btn" data-group="personal">Personal</button>
<input type="text" class="search-box" placeholder="Search repos..." id="search">
</div>
<div class="section" id="auctic-section">
<div class="section-title">Auctic <span class="count">32 repos</span></div>
<div class="grid" id="auctic-grid"></div>
</div>
<div class="section" id="personal-section">
<div class="section-title">Personal Projects <span class="count">16 repos</span></div>
<div class="grid" id="personal-grid"></div>
</div>
<div class="pr-section">
<div class="section-title">Open Pull Requests — auctic-core <span class="count">30</span></div>
<div id="pr-list"></div>
</div>
<div class="legend">
<div class="legend-item"><div class="legend-dot" style="background:var(--green)"></div> Active (commit in last 7 days)</div>
<div class="legend-item"><div class="legend-dot" style="background:var(--accent)"></div> Recent (8-30 days)</div>
<div class="legend-item"><div class="legend-dot" style="background:var(--yellow)"></div> Stale (31-90 days)</div>
<div class="legend-item"><div class="legend-dot" style="background:var(--text-muted)"></div> Dormant (90+ days)</div>
</div>
<script>
const today = new Date('2026-02-18');
const aucticRepos = [
{name:"auctic-core",date:"2026-02-18",msg:"fix: dev-4728 get greatest between min and max prebids",branch:"develop",uncommitted:0,branches:410,stack:"php/laravel",prs:30,category:"platform"},
{name:"fasigtipton",date:"2026-02-18",msg:"missed (#1742)",branch:"develop",uncommitted:0,branches:186,stack:"php/laravel",prs:0,category:"client"},
{name:"barrettjackson",date:"2026-02-17",msg:"Merge pull request #13 fix-team-policy-user-typehint",branch:"develop",uncommitted:0,branches:18,stack:"php/laravel",prs:0,category:"client"},
{name:"booker",date:"2026-02-17",msg:"fix: use Auctic\\Core\\User type-hint in TeamPolicy",branch:"develop",uncommitted:0,branches:161,stack:"php/laravel",prs:0,category:"client"},
{name:"edsmachinery",date:"2026-02-17",msg:"fix: use Auctic\\Core\\User type-hint in TeamPolicy",branch:"develop",uncommitted:0,branches:144,stack:"php/laravel",prs:0,category:"client"},
{name:"govauction",date:"2026-02-17",msg:"fix: use Auctic\\Core\\User type-hint in TeamPolicy",branch:"develop",uncommitted:0,branches:95,stack:"php/laravel",prs:0,category:"client"},
{name:"liveag",date:"2026-02-17",msg:"fix: use Auctic\\Core\\User type-hint in TeamPolicy",branch:"develop",uncommitted:0,branches:154,stack:"php/laravel",prs:0,category:"client"},
{name:"mast",date:"2026-02-17",msg:"fix: use Auctic\\Core\\User type-hint in TeamPolicy",branch:"develop",uncommitted:0,branches:77,stack:"php/laravel",prs:0,category:"client"},
{name:"norvinhill",date:"2026-02-17",msg:"fix: use Auctic\\Core\\User type-hint in TeamPolicy",branch:"develop",uncommitted:0,branches:24,stack:"php/laravel",prs:0,category:"client"},
{name:"phasemedical",date:"2026-02-17",msg:"fix: use Auctic\\Core\\User type-hint in TeamPolicy",branch:"develop",uncommitted:0,branches:157,stack:"php/laravel",prs:0,category:"client"},
{name:"preferredequine",date:"2026-02-17",msg:"fix: use Auctic\\Core\\User type-hint in TeamPolicy",branch:"develop",uncommitted:0,branches:145,stack:"php/laravel",prs:0,category:"client"},
{name:"rebel",date:"2026-02-17",msg:"fix: use Auctic\\Core\\User type-hint in TeamPolicy",branch:"develop",uncommitted:0,branches:148,stack:"php/laravel",prs:0,category:"client"},
{name:"res",date:"2026-02-17",msg:"fix: use Auctic\\Core\\User type-hint in TeamPolicy",branch:"develop",uncommitted:0,branches:221,stack:"php/laravel",prs:0,category:"client"},
{name:"salesco",date:"2026-02-17",msg:"fix: use Auctic\\Core\\User type-hint in TeamPolicy",branch:"develop",uncommitted:0,branches:220,stack:"php/laravel",prs:0,category:"client"},
{name:"theriaults",date:"2026-02-17",msg:"fix: use Auctic\\Core\\User type-hint in TeamPolicy",branch:"develop",uncommitted:0,branches:162,stack:"php/laravel",prs:0,category:"client"},
{name:"trucklist",date:"2026-02-17",msg:"fix: use Auctic\\Core\\User type-hint in TeamPolicy",branch:"develop",uncommitted:0,branches:149,stack:"php/laravel",prs:0,category:"client"},
{name:"shared-workflows",date:"2026-02-13",msg:"release(version): Release 1.9.4 [skip ci]",branch:"main",uncommitted:0,branches:13,stack:"node",prs:0,category:"infra"},
{name:"auctic-autoclerk-poc",date:"2026-02-05",msg:"docs: Add original research proposal from January 2025",branch:"trunk",uncommitted:0,branches:3,stack:"node",prs:0,category:"poc"},
{name:"mobile-app",date:"2026-02-04",msg:"chore(release): 1.31.1 [skip ci]",branch:"main",uncommitted:0,branches:7,stack:"node",prs:0,category:"platform"},
{name:"auctic-wrap",date:"2026-01-22",msg:"fix: add constant back to get cli working",branch:"main",uncommitted:0,branches:28,stack:"php/laravel",prs:0,category:"platform"},
{name:"auctic-atlas",date:"2026-01-21",msg:"chore(release): 1.9.5 [skip ci]",branch:"main",uncommitted:0,branches:8,stack:"php/laravel",prs:0,category:"platform"},
{name:"auctic-exo",date:"2026-01-19",msg:"chore(release): 1.13.0 [skip ci]",branch:"main",uncommitted:0,branches:4,stack:"php/laravel",prs:0,category:"platform"},
{name:"auctic-tracker",date:"2026-01-15",msg:"ci: add auto-deploy workflow for Forge",branch:"main",uncommitted:0,branches:4,stack:"php/laravel",prs:0,category:"platform"},
{name:"iac-imports-bucket",date:"2026-01-07",msg:"fix: disable S3 Block Public Access",branch:"main",uncommitted:0,branches:4,stack:"terraform",prs:0,category:"infra"},
{name:"bid-service",date:"2026-01-06",msg:"release(version): Release 1.1.1 [skip ci]",branch:"main",uncommitted:0,branches:7,stack:"php/laravel",prs:0,category:"platform"},
{name:"auctic-cli",date:"2025-12-22",msg:"chore: release js 1.1.1 (#6)",branch:"main",uncommitted:0,branches:6,stack:"node",prs:0,category:"platform"},
{name:"config-commitlint",date:"2025-12-18",msg:"release(version): Release 1.3.1 [skip ci]",branch:"main",uncommitted:0,branches:3,stack:"node",prs:0,category:"infra"},
{name:"linear",date:"2025-12-16",msg:"feat: add directory-based profile selection via .linearrc",branch:"main",uncommitted:0,branches:3,stack:"node",prs:0,category:"tool"},
{name:"iac-build-cache",date:"2025-12-14",msg:"feat: initial iac-build-cache module",branch:"main",uncommitted:0,branches:3,stack:"terraform",prs:0,category:"infra"},
{name:"auctic-www",date:"2025-12-08",msg:"update careers (#24)",branch:"master",uncommitted:0,branches:26,stack:"php/laravel",prs:0,category:"platform"},
{name:"base-docker-image",date:"2025-09-22",msg:"release(version): Release 1.5.0 [skip ci]",branch:"main",uncommitted:0,branches:5,stack:"docker",prs:0,category:"infra"},
{name:"omnipay-cardpointe",date:"2023-11-09",msg:"release(version): Release 1.0.0 [skip ci]",branch:"main",uncommitted:0,branches:5,stack:"php",prs:0,category:"platform"},
];
const personalRepos = [
{name:"live-hud",date:"2026-02-18",msg:"feat: initial project documentation and brand identity",branch:"main",uncommitted:0,branches:3,stack:"docs",project:"Poker Suite"},
{name:"stack",date:"2026-02-17",msg:"chore: make repo standalone (remove dotfiles-specific paths)",branch:"main",uncommitted:0,branches:3,stack:"shell",project:"Tools"},
{name:"feedwiz",date:"2026-02-16",msg:"feat: initial MVP scaffold — feed poller, summarizer, HTMX UI",branch:"main",uncommitted:0,branches:3,stack:"go",project:"Tools"},
{name:"betondrew-api",date:"2026-02-15",msg:"fix(ci): add synchronize trigger to preview deploy",branch:"main",uncommitted:0,branches:10,stack:"php/laravel",project:"BetOnDrew"},
{name:"client-portal",date:"2026-02-15",msg:"fix(ci): add synchronize trigger to preview deploy",branch:"main",uncommitted:0,branches:18,stack:"php/laravel",project:"Client Work"},
{name:"eyeslikefire",date:"2026-02-15",msg:"feat: featured release hero - So Sick single",branch:"main",uncommitted:0,branches:13,stack:"php/laravel",project:"Client Work"},
{name:"hand-history-whiteboard",date:"2026-02-15",msg:"feat: v4 — swim lane whiteboard + panel-as-input timeline",branch:"main",uncommitted:0,branches:4,stack:"html",project:"Poker Suite"},
{name:"hvac",date:"2026-02-15",msg:"fix(ci): add synchronize trigger to preview deploy",branch:"main",uncommitted:0,branches:10,stack:"php/laravel",project:"Client Work"},
{name:"tipt",date:"2026-02-15",msg:"fix(ci): add synchronize trigger to preview deploy workflow",branch:"main",uncommitted:0,branches:12,stack:"php/laravel",project:"Client Work"},
{name:"betondrew-mobile",date:"2026-02-14",msg:"chore: migrate to shared reusable workflows",branch:"main",uncommitted:0,branches:14,stack:"react-native",project:"BetOnDrew"},
{name:"poker-engine",date:"2026-02-14",msg:"feat: export card utilities, colors, and replayToPlayerStates",branch:"main",uncommitted:0,branches:7,stack:"node",project:"Poker Suite"},
{name:"infrastructure",date:"2026-02-12",msg:"docs: add plan 001 - infrastructure tracking system",branch:"main",uncommitted:0,branches:3,stack:"docs",project:"Tools"},
{name:"pitboss",date:"2026-02-08",msg:"fix(middleware): add http.Hijacker support for WebSocket upgrades",branch:"main",uncommitted:0,branches:3,stack:"go",project:"Poker Suite"},
{name:"mama-poker",date:"2026-01-09",msg:"feat: [ui] - implement Flow 11 hand builder screen",branch:"main",uncommitted:0,branches:4,stack:"react-native",project:"Poker Suite"},
{name:"montana",date:"2026-01-09",msg:"fix: [server] - Phase 2.4 review fixes and test improvements",branch:"main",uncommitted:0,branches:3,stack:"node",project:"Poker Suite"},
];
const openPRs = [
{num:4651,title:"feat: dev-4781 - add tax functionality for title fee in billing system",author:"donaldogallegos",date:"2026-02-18"},
{num:4649,title:"fix: resolve External API 500 errors with comprehensive contract tests",author:"ivannovak",date:"2026-02-18"},
{num:4647,title:"fix: dev 000 user search add more fields",author:"numeralsix",date:"2026-02-18"},
{num:4646,title:"feat: dev-4549 - Admin User Alerts",author:"MattStrauss",date:"2026-02-18"},
{num:4640,title:"fix: dev 000 more bidding protection",author:"numeralsix",date:"2026-02-17"},
{num:4639,title:"feat: dev-4770 - add ability to apply tax to custom fee on settlements",author:"donaldogallegos",date:"2026-02-17"},
{num:4632,title:"feat: dev-4763 - consignor pay",author:"robkerr1992",date:"2026-02-17"},
{num:4624,title:"fix: dev-4973 event heading touchup",author:"numeralsix",date:"2026-02-15"},
{num:4606,title:"fix: dev 4696 phase punch 1 26",author:"numeralsix",date:"2026-02-09"},
{num:4605,title:"fix: dev 000 inventory tag UI port from nova",author:"numeralsix",date:"2026-02-10"},
{num:4586,title:"fix: dev-000 handle missing resolver name",author:"numeralsix",date:"2026-02-05"},
{num:4583,title:"feat: dev-4584 Email Attachments and Settlement Templates",author:"spittman7",date:"2026-02-18"},
{num:4562,title:"fix: correct whitelisted filter to use computed logic",author:"robkerr1992",date:"2026-01-31"},
{num:4558,title:"fix: dev-000 offer text",author:"numeralsix",date:"2026-01-29"},
{num:4552,title:"feat: DEV-203 VIN/Serial Auto-Population for Mobile Sync",author:"gueroverdenwshq",date:"2026-01-29"},
{num:4491,title:"feat: vitest-integration",author:"donaldogallegos",date:"2026-01-15"},
{num:4466,title:"feat: MySQL search service as alternative to Elasticsearch",author:"ivannovak",date:"2026-01-09"},
{num:4465,title:"feat(sms): SMS provider abstraction (Phases 1-3)",author:"ivannovak",date:"2026-01-09"},
{num:4453,title:"feat(bidding): BAL-001 Bidding Adapter Layer Integration",author:"ivannovak",date:"2026-02-03"},
{num:4344,title:"fix(ci): add npm registry auth for release workflow",author:"ivannovak",date:"2025-12-30"},
{num:4285,title:"fix: dev-000 allow multi rotation",author:"numeralsix",date:"2025-12-30"},
{num:4241,title:"fix: dev hubspot crm integration",author:"ivannovak",date:"2025-12-30"},
{num:4223,title:"fix: dev 000 jwp player",author:"numeralsix",date:"2025-12-30"},
{num:4096,title:"fix: dev 000 bid unlock",author:"numeralsix",date:"2026-01-29"},
{num:4036,title:"Taxonomy module rebase test",author:"jtallant",date:"2025-12-30"},
{num:3863,title:"POC: dev 000 bid performance do not merge",author:"numeralsix",date:"2025-12-30"},
{num:3374,title:"Ai module",author:"ivannovak",date:"2025-12-30"},
{num:3358,title:"fix: legacy Dev 3439 prod legacy invoices offer updates",author:"numeralsix",date:"2025-08-04"},
{num:2820,title:"fix: dev-1140 Client Settings",author:"robkerr1992",date:"2025-12-30"},
{num:2458,title:"add video conversion support",author:"ivannovak",date:"2025-12-30"},
];
function daysSince(dateStr) {
const d = new Date(dateStr);
return Math.floor((today - d) / (1000*60*60*24));
}
function statusClass(dateStr) {
const days = daysSince(dateStr);
if (days <= 7) return 'active';
if (days <= 30) return 'recent';
if (days <= 90) return 'stale';
return 'dormant';
}
function statusLabel(dateStr) {
const days = daysSince(dateStr);
if (days <= 7) return 'Active';
if (days <= 30) return 'Recent';
if (days <= 90) return 'Stale';
return 'Dormant';
}
function renderCard(repo, group) {
const status = statusClass(repo.date);
const days = daysSince(repo.date);
const daysLabel = days === 0 ? 'today' : days === 1 ? 'yesterday' : `${days}d ago`;
const needsAttention = repo.uncommitted > 0 || repo.prs > 10;
let tags = `<span class="tag stack">${repo.stack}</span>`;
if (repo.prs > 0) tags += `<span class="tag prs">${repo.prs} PRs</span>`;
if (repo.uncommitted > 0) tags += `<span class="tag dirty">${repo.uncommitted} uncommitted</span>`;
if (repo.category) tags += `<span class="tag">${repo.category}</span>`;
if (repo.project) tags += `<span class="tag">${repo.project}</span>`;
return `<div class="card" data-status="${status}" data-group="${group}" data-name="${repo.name}" ${needsAttention ? 'data-attention="true"' : ''}>
<div class="card-header">
<span class="name">${repo.name}</span>
<span class="badge ${status}">${statusLabel(repo.date)}</span>
</div>
<div class="commit-msg">${repo.msg}</div>
<div class="meta">
<span class="meta-item"><svg viewBox="0 0 16 16"><path d="M1.75 1A1.75 1.75 0 000 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0016 13.25v-8.5A1.75 1.75 0 0014.25 3H7.5a.25.25 0 01-.2-.1l-.9-1.2c-.33-.44-.85-.7-1.4-.7z"/></svg>${repo.branch}</span>
<span class="meta-item"><svg viewBox="0 0 16 16"><path d="M1.643 3.143L.427 1.927A.25.25 0 000 2.104V5.75c0 .138.112.25.25.25h3.646a.25.25 0 00.177-.427L2.715 4.215a6.5 6.5 0 11-1.18 4.458.75.75 0 10-1.493.154 8.001 8.001 0 101.6-5.684z"/></svg>${daysLabel}</span>
<span class="meta-item">${repo.branches} branches</span>
</div>
<div class="tags">${tags}</div>
</div>`;
}
// Render grids
document.getElementById('auctic-grid').innerHTML = aucticRepos.map(r => renderCard(r, 'auctic')).join('');
document.getElementById('personal-grid').innerHTML = personalRepos.map(r => renderCard(r, 'personal')).join('');
// Render PRs
document.getElementById('pr-list').innerHTML = openPRs.map(pr => {
const days = daysSince(pr.date);
const age = days <= 7 ? '' : days <= 30 ? ' style="border-left: 3px solid var(--yellow)"' : ' style="border-left: 3px solid var(--red)"';
return `<div class="pr-card"${age}>
<div>
<div class="pr-title">#${pr.num} ${pr.title}</div>
<div class="pr-meta">${days === 0 ? 'today' : `${days}d ago`} &middot; <span class="pr-author">@${pr.author}</span></div>
</div>
</div>`;
}).join('');
// Filter logic
let activeStatusFilter = 'all';
let activeGroupFilter = null;
function applyFilters() {
const search = document.getElementById('search').value.toLowerCase();
document.querySelectorAll('.card').forEach(card => {
const name = card.dataset.name.toLowerCase();
const status = card.dataset.status;
const group = card.dataset.group;
const attention = card.dataset.attention;
let show = true;
if (activeStatusFilter === 'attention') {
show = attention === 'true';
} else if (activeStatusFilter !== 'all') {
show = status === activeStatusFilter;
}
if (activeGroupFilter && group !== activeGroupFilter) show = false;
if (search && !name.includes(search)) show = false;
card.classList.toggle('hidden', !show);
});
// Show/hide sections
const aucticVisible = document.querySelectorAll('#auctic-grid .card:not(.hidden)').length > 0;
const personalVisible = document.querySelectorAll('#personal-grid .card:not(.hidden)').length > 0;
document.getElementById('auctic-section').classList.toggle('hidden', !aucticVisible);
document.getElementById('personal-section').classList.toggle('hidden', !personalVisible);
}
document.querySelectorAll('.filter-btn[data-filter]').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.filter-btn[data-filter]').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
activeStatusFilter = btn.dataset.filter;
applyFilters();
});
});
document.querySelectorAll('.filter-btn[data-group]').forEach(btn => {
btn.addEventListener('click', () => {
if (activeGroupFilter === btn.dataset.group) {
activeGroupFilter = null;
btn.classList.remove('active');
} else {
document.querySelectorAll('.filter-btn[data-group]').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
activeGroupFilter = btn.dataset.group;
}
applyFilters();
});
});
document.getElementById('search').addEventListener('input', applyFilters);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment