| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- #!/usr/bin/env python3
- """Generate results/index.html — a landing page linking to every dashboard
- in the results/ directory. Rerun anytime new dashboards are added."""
- import os, re, html
- RESULTS = "/home/user/polisci/results"
- # Metadata for each dashboard (name, party, chamber, district/state).
- # Anything not listed here is auto-rendered with just the filename.
- META = {
- "ThomasMassie119.html": ("Thomas Massie", "R", "House", "KY-4"),
- "RoKhanna119.html": ("Ro Khanna", "D", "House", "CA-17"),
- "AlexandriaOcasioCortez119.html":("Alexandria Ocasio-Cortez", "D", "House", "NY-14"),
- "IlhanOmar119.html": ("Ilhan Omar", "D", "House", "MN-5"),
- "MarjorieTaylorGreene119.html": ("Marjorie Taylor Greene", "R", "House", "GA-14"),
- "JimJordan119.html": ("Jim Jordan", "R", "House", "OH-4"),
- "ByronDonalds119.html": ("Byron Donalds", "R", "House", "FL-19"),
- "LindseyGraham119.html": ("Lindsey Graham", "R", "Senate", "SC"),
- }
- PARTY_COLOR = {"R": "#d93b3b", "D": "#3b6ed9", "I": "#888"}
- CHAMBER_COLOR = {"House": "#1e6b1e", "Senate": "#5a3d8a"}
- def main():
- files = sorted(f for f in os.listdir(RESULTS) if f.endswith(".html") and f != "index.html")
- cards = []
- for f in files:
- meta = META.get(f)
- if meta:
- name, party, chamber, loc = meta
- else:
- name = re.sub(r"119\.html$", "", f)
- party, chamber, loc = "?", "?", ""
- pc = PARTY_COLOR.get(party, "#888")
- cc = CHAMBER_COLOR.get(chamber, "#888")
- cards.append(f"""
- <a class="card" href="{html.escape(f)}">
- <div class="name">{html.escape(name)}</div>
- <div class="pills">
- <span class="pill" style="background:{pc}">{html.escape(party)}</span>
- <span class="pill" style="background:{cc}">{html.escape(chamber)}</span>
- <span class="loc">{html.escape(loc)}</span>
- </div>
- <div class="file">{html.escape(f)}</div>
- </a>""")
- page = f"""<!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8">
- <title>119th Congress Voting Dashboards — Index</title>
- <style>
- body{{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;
- margin:0;padding:32px;background:#f5f5f7;color:#1d1d1f;max-width:1100px;margin-left:auto;margin-right:auto;}}
- h1{{margin:0 0 6px;font-size:28px;}}
- .sub{{color:#6e6e73;margin-bottom:28px;line-height:1.5;}}
- .sub a{{color:#1644a0;}}
- .grid{{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px;}}
- .card{{background:#fff;border-radius:12px;padding:18px;box-shadow:0 1px 3px rgba(0,0,0,.06);
- text-decoration:none;color:inherit;transition:transform .12s,box-shadow .12s;display:block;}}
- .card:hover{{transform:translateY(-2px);box-shadow:0 4px 12px rgba(0,0,0,.1);}}
- .name{{font-size:17px;font-weight:600;margin-bottom:8px;}}
- .pills{{display:flex;align-items:center;gap:6px;margin-bottom:8px;flex-wrap:wrap;}}
- .pill{{display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:600;color:#fff;}}
- .loc{{font-size:12px;color:#6e6e73;margin-left:4px;}}
- .file{{font-size:11px;color:#9a9aa1;font-family:ui-monospace,SF Mono,Menlo,monospace;}}
- .footer{{margin-top:32px;text-align:center;color:#6e6e73;font-size:12px;}}
- </style>
- </head>
- <body>
- <h1>119th Congress — Voting Dashboards</h1>
- <div class="sub">
- Per-member voting analysis for the 119th U.S. Congress (Jan 2025 – present).
- Click any card to open its dashboard. See
- <a href="../DOCUMENTATION.md">DOCUMENTATION.md</a> for methodology, data sources, and roster notes.
- </div>
- <div class="grid">{''.join(cards)}
- </div>
- <div class="footer">{len(files)} dashboards · Sources: clerk.house.gov (House) · senate.gov LIS (Senate)</div>
- </body></html>
- """
- out = os.path.join(RESULTS, "index.html")
- with open(out, "w") as f: f.write(page)
- print(f"Wrote {out} with {len(files)} entries")
- if __name__ == "__main__":
- main()
|