build_index.py 4.0 KB

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