From 0c08745194776c46b90082923c13f81754e4c2a7 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sun, 26 Apr 2026 12:36:20 -0400 Subject: [PATCH] feat: top-level nav and chat list view --- chat/app.py | 2 + chat/static/app.css | 37 ++++++++++-- chat/templates/base.html | 7 +-- chat/templates/bot_form.html | 2 +- chat/templates/bot_list.html | 2 +- chat/templates/chat_list.html | 26 +++++++++ chat/templates/kickoff_confirm.html | 2 +- chat/templates/layout.html | 14 +++++ chat/templates/settings.html | 2 +- chat/web/bots.py | 8 ++- chat/web/kickoff.py | 4 +- chat/web/nav.py | 34 +++++++++++ chat/web/settings.py | 8 ++- tests/test_chat_list.py | 89 +++++++++++++++++++++++++++++ 14 files changed, 218 insertions(+), 19 deletions(-) create mode 100644 chat/templates/chat_list.html create mode 100644 chat/templates/layout.html create mode 100644 chat/web/nav.py create mode 100644 tests/test_chat_list.py diff --git a/chat/app.py b/chat/app.py index 4251290..a0924d4 100644 --- a/chat/app.py +++ b/chat/app.py @@ -16,6 +16,7 @@ import chat.state.world # noqa: F401 from chat.web.bots import router as bots_router from chat.web.kickoff import router as kickoff_router +from chat.web.nav import router as nav_router from chat.web.settings import router as settings_router @@ -36,6 +37,7 @@ app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static") app.include_router(bots_router) app.include_router(kickoff_router) app.include_router(settings_router) +app.include_router(nav_router) @app.get("/health") diff --git a/chat/static/app.css b/chat/static/app.css index 9c261a8..4645d19 100644 --- a/chat/static/app.css +++ b/chat/static/app.css @@ -4,11 +4,33 @@ body { margin: 0; color: #1c1c1c; background: #fafafa; + display: flex; + min-height: 100vh; } -.topbar { - padding: 12px 24px; - border-bottom: 1px solid #e5e5e5; - background: #fff; +.rail { + width: 200px; + background: #1c1c1c; + color: #fff; + padding: 16px; + flex-shrink: 0; +} +.rail a { color: #fff; text-decoration: none; } +.rail-brand { + font-weight: 600; + display: block; + padding-bottom: 16px; + border-bottom: 1px solid #333; + margin-bottom: 16px; +} +.rail ul { list-style: none; padding: 0; margin: 0; } +.rail li { margin: 4px 0; } +.rail li a { display: block; padding: 6px 8px; border-radius: 3px; } +.rail li a.active { background: #333; } +.content { + flex: 1; + padding: 24px; + background: #fafafa; + overflow: auto; } .brand { font-weight: 600; text-decoration: none; color: inherit; } .container { max-width: 720px; margin: 24px auto; padding: 0 16px; } @@ -29,6 +51,13 @@ h1 { margin-top: 0; } .bot-form small { display: block; color: #666; margin-top: 2px; } .bot-list { list-style: none; padding: 0; } .bot-list li { padding: 8px 0; border-bottom: 1px solid #eee; } +.chat-list { list-style: none; padding: 0; margin: 0; } +.chat-row { border-bottom: 1px solid #eee; } +.chat-row a { display: block; padding: 12px 0; text-decoration: none; color: inherit; } +.chat-row a:hover { background: #f0f0f0; } +.chat-row-name { font-weight: 600; } +.chat-row-snippet { font-size: 14px; } +.chat-row-meta { font-size: 12px; } .muted { color: #666; } .error { padding: 8px 12px; border: 1px solid #c33; background: #fdecea; diff --git a/chat/templates/base.html b/chat/templates/base.html index 6c86104..01d0abd 100644 --- a/chat/templates/base.html +++ b/chat/templates/base.html @@ -8,11 +8,6 @@ -
- chat -
-
- {% block content %}{% endblock %} -
+ {% block body %}{% endblock %} diff --git a/chat/templates/bot_form.html b/chat/templates/bot_form.html index e0d3331..6d44080 100644 --- a/chat/templates/bot_form.html +++ b/chat/templates/bot_form.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "layout.html" %} {% block title %}New bot - chat{% endblock %} {% block content %}

New bot

diff --git a/chat/templates/bot_list.html b/chat/templates/bot_list.html index f3b4562..7a2a65b 100644 --- a/chat/templates/bot_list.html +++ b/chat/templates/bot_list.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "layout.html" %} {% block title %}Bots - chat{% endblock %} {% block content %}