Skip to content

Commit ebb2e94

Browse files
authored
Update index.html
1 parent e4f6fc1 commit ebb2e94

1 file changed

Lines changed: 137 additions & 6 deletions

File tree

docs/index.html

Lines changed: 137 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,143 @@
1-
<!DOCTYPE html>
1+
<!doctype html>
22
<html lang="en">
33
<head>
4-
<meta charset="UTF-8">
5-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6-
<title>Welcome to Democracy Lab</title>
4+
<meta charset="utf-8" />
5+
<title>Democracy Lab — Project Sites</title>
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
<style>
8+
:root { --max: 1100px; }
9+
body { font-family: Arial, Helvetica, sans-serif; margin: 0; background:#0e1116; color:#e6edf3; }
10+
header { padding: 24px; text-align:center; }
11+
header h1 { margin: 0 0 8px; font-size: 28px; }
12+
header p { margin: 0; opacity:.8 }
13+
.container { max-width: var(--max); margin: 0 auto; padding: 16px 24px 48px; }
14+
.toolbar { display:flex; gap:12px; align-items:center; margin-bottom:16px; flex-wrap:wrap; }
15+
input[type="search"] { flex:1; padding:10px 12px; border-radius:10px; border:1px solid #30363d; background:#0d1117; color:#e6edf3; }
16+
select { padding:10px 12px; border-radius:10px; border:1px solid #30363d; background:#0d1117; color:#e6edf3; }
17+
.grid { display:grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap:16px; }
18+
.card { background:#0d1117; border:1px solid #30363d; border-radius:14px; padding:16px; display:flex; flex-direction:column; gap:8px; }
19+
.card h3 { margin:0; font-size:18px; }
20+
.meta { font-size:12px; opacity:.8 }
21+
.links a { text-decoration:none; color:#67b7ff; margin-right:10px; }
22+
footer { text-align:center; padding:24px; opacity:.7; }
23+
.empty { text-align:center; padding:40px; opacity:.8 }
24+
</style>
725
</head>
826
<body>
9-
<h1>Hello from Democracy Lab</h1>
10-
<p>This is a starter GitHub Pages site for our organization.</p>
27+
<header>
28+
<h1>Democracy Lab — Project Sites</h1>
29+
<p>Auto-listing of organization repositories that publish with GitHub Pages.</p>
30+
</header>
31+
32+
<div class="container">
33+
<div class="toolbar">
34+
<input id="q" type="search" placeholder="Search repositories… (name or description)" />
35+
<select id="sort">
36+
<option value="updated">Sort: Recently updated</option>
37+
<option value="name">Sort: Name (A→Z)</option>
38+
</select>
39+
</div>
40+
41+
<div id="grid" class="grid"></div>
42+
<div id="empty" class="empty" style="display:none;">No matches.</div>
43+
</div>
44+
45+
<footer>Built from the public GitHub API • Last refreshed client-side</footer>
46+
47+
<script>
48+
// ---- CONFIG ----
49+
const ORG = 'Democracy-Lab';
50+
const ORG_PAGES_BASE = 'https://democracy-lab.github.io'; // lowercased host is fine
51+
52+
// Fetch all org repos (handles pagination if >100)
53+
async function fetchAllRepos(url = `https://api.github.com/orgs/${ORG}/repos?per_page=100&type=public`) {
54+
const all = [];
55+
while (url) {
56+
const res = await fetch(url);
57+
if (!res.ok) throw new Error(`GitHub API: ${res.status} ${res.statusText}`);
58+
const page = await res.json();
59+
all.push(...page);
60+
// parse Link header for pagination
61+
const link = res.headers.get('Link');
62+
const next = link && [...link.split(',')].find(s => s.includes('rel="next"'));
63+
url = next ? next.split(';')[0].trim().slice(1, -1) : null;
64+
}
65+
return all;
66+
}
67+
68+
// Convert repo → Pages URL (works for org project pages)
69+
function pagesUrl(repo) {
70+
// org root site is <org>.github.io; project sites are under /<repo>
71+
if (repo.name.toLowerCase() === `${ORG.toLowerCase()}.github.io`) {
72+
return `${ORG_PAGES_BASE}/`;
73+
}
74+
return `${ORG_PAGES_BASE}/${encodeURIComponent(repo.name)}/`;
75+
}
76+
77+
function fmtDate(iso) {
78+
try { return new Date(iso).toLocaleString(); } catch { return iso; }
79+
}
80+
81+
function render(list) {
82+
const grid = document.getElementById('grid');
83+
const empty = document.getElementById('empty');
84+
grid.innerHTML = '';
85+
if (!list.length) { empty.style.display = ''; return; }
86+
empty.style.display = 'none';
87+
88+
for (const r of list) {
89+
const card = document.createElement('div');
90+
card.className = 'card';
91+
card.innerHTML = `
92+
<h3>${r.name}</h3>
93+
<div class="meta">${r.description ? r.description : ''}</div>
94+
<div class="meta">Updated: ${fmtDate(r.updated_at)}</div>
95+
<div class="links">
96+
<a href="${pagesUrl(r)}" target="_blank" rel="noopener">View site</a>
97+
<a href="${r.html_url}" target="_blank" rel="noopener">Repo</a>
98+
</div>
99+
`;
100+
grid.appendChild(card);
101+
}
102+
}
103+
104+
function filterSort(repos) {
105+
const q = document.getElementById('q').value.toLowerCase().trim();
106+
const sort = document.getElementById('sort').value;
107+
108+
let list = repos;
109+
if (q) {
110+
list = repos.filter(r =>
111+
(r.name && r.name.toLowerCase().includes(q)) ||
112+
(r.description && r.description.toLowerCase().includes(q))
113+
);
114+
}
115+
116+
if (sort === 'name') {
117+
list.sort((a,b) => a.name.localeCompare(b.name));
118+
} else {
119+
list.sort((a,b) => new Date(b.updated_at) - new Date(a.updated_at));
120+
}
121+
render(list);
122+
}
123+
124+
(async function init() {
125+
try {
126+
const repos = await fetchAllRepos();
127+
// Only show repos with Pages enabled OR the org root repo
128+
const withPages = repos.filter(r =>
129+
r.has_pages || r.name.toLowerCase() === `${ORG.toLowerCase()}.github.io`
130+
);
131+
window.__REPOS__ = withPages;
132+
filterSort(withPages);
133+
134+
document.getElementById('q').addEventListener('input', () => filterSort(window.__REPOS__));
135+
document.getElementById('sort').addEventListener('change', () => filterSort(window.__REPOS__));
136+
} catch (err) {
137+
document.getElementById('grid').innerHTML =
138+
`<div class="empty">Error loading list: ${err.message}</div>`;
139+
}
140+
})();
141+
</script>
11142
</body>
12143
</html>

0 commit comments

Comments
 (0)