feat: Replace TestaController with UiController for minimal llm chat UI using TailwindCSS

This commit is contained in:
Tristan D. 2025-03-17 22:45:12 +01:00
parent b2bd8bbaae
commit 259fac7c58
Signed by: tristan
SSH key fingerprint: SHA256:9oFM1J63hYWJjCnLG6C0fxBS15rwNcWwdQNMOHYKJ/4

View file

@ -25,12 +25,12 @@ mod html_elements {
}
}
struct TestaController {}
struct UiController {}
#[controller(
state = AppState
)]
impl TestaController {
impl UiController {
#[route(GET "/")]
async fn index(State(_): State<AppState>) -> impl IntoResponse {
maud! {
@ -39,61 +39,51 @@ impl TestaController {
meta charset="UTF-8";
meta name="viewport" content="width=device-width, initial-scale=1.0";
title {
"My Website"
"LLM Chat App"
}
script type="module" src="/dist/datastar.min.js" {}
link rel="stylesheet" href="/dist/styles.min.css";
link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css";
link rel="icon" href="/dist/favicon.ico";
}
body {
main {
h1 {
"Welcome to My Website"
body class="bg-gray-100" {
div class="container mx-auto p-4" {
h1 class="text-2xl font-bold mb-4" {
"LLM Chat App"
}
div."m-1" {
"div"
}
div."m1" {
"div"
}
div ."m1" {
"m1"
}
div ."m2" {
"m2"
}
div ."m3" {
"m3"
div class="bg-white p-6 rounded-lg shadow-md" {
div id="chat" class="mb-4" {
// Chat messages will appear here
}
form id="chat-form" {
textarea id="user-input" class="w-full p-2 border rounded-lg mb-2" placeholder="Type your message..." {}
button type="submit" class="bg-blue-500 text-white p-2 rounded-lg" {
"Send"
}
}
}
}
script {
"
document.getElementById('chat-form').addEventListener('submit', function(event) {
event.preventDefault();
const userInput = document.getElementById('user-input').value;
const chatContainer = document.getElementById('chat');
chatContainer.innerHTML += `<div class='mb-2'><strong>You:</strong> ${userInput}</div>`;
document.getElementById('user-input').value = '';
// Mock response from LLM
setTimeout(() => {
chatContainer.innerHTML += `<div class='mb-2'><strong>LLM:</strong> This is a mock response.</div>`;
}, 1000);
});
"
}
}
}
}
.render()
}
#[allow(unused)]
#[route(GET "/item/:id?amount&offset")]
async fn item_handler(
id: u32,
amount: Option<u32>,
offset: Option<u32>,
State(state): State<AppState>,
// Json(json): Json<u32>,
) -> impl IntoResponse {
// todo!("handle request")
maud! {
h1 { "Item" }
div {
}
p {
(format!("{id:?} {amount:?} {offset:?} {state:?}"))
}
}
.render()
}
}
struct DistController;
@ -205,7 +195,7 @@ async fn main() {
let listener = tokio::net::TcpListener::bind("0.0.0.0:8000").await.unwrap();
let router: axum::Router = axum::Router::new()
.merge(TestaController::into_router(app_state.clone()))
.merge(UiController::into_router(app_state.clone()))
.merge(DistController::into_router(app_state.clone()))
.fallback_service(get(handle_404))
.method_not_allowed_fallback(handle_405)