Created
February 19, 2026 00:56
-
-
Save robkerr1992/d5efdeaa8f7522192e9af6f19b7a7816 to your computer and use it in GitHub Desktop.
Project Dashboard — Robert Kerr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!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 — 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`} · <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