Redesign main page with minimalist "No" and move interactive UI to /playground

- Create elegant minimalist main page with centered "No"
- Add automatic dark mode support for main page
- Move original interactive API testing interface to /playground
- Add footer links to main page for navigation
- Update routing to serve both pages appropriately
- Update documentation to reflect new page structure

The main page now provides a clean, focused experience while the
playground remains available for API testing and exploration.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2025-09-27 16:47:29 +02:00
commit ebd0fcc448
3 changed files with 98 additions and 5 deletions

View file

@ -56,10 +56,13 @@ The entire application is contained in `src/main.rs` with ~372 lines of code. Th
### Key Components
1. **Embedded HTML Frontend**: The HTML/CSS/JavaScript frontend is embedded as a string constant (`HTML_FRONTEND`) directly in the source code, eliminating the need for static file serving.
1. **Embedded HTML Frontends**: Two HTML frontends are embedded as string constants:
- `SIMPLE_FRONTEND`: Minimalist main page with just "No" centered on screen
- `PLAYGROUND_FRONTEND`: Interactive API testing playground with buttons and examples
2. **Request Router**: The `route_request()` function handles all routing logic:
- `/` - Serves the embedded HTML frontend
- `/` - Serves the minimalist "No" page
- `/playground` - Serves the interactive API testing interface
- `/api/no` - API endpoint with format parameter support
- `/health` - Health check endpoint
- CORS headers are added to all responses

View file

@ -14,7 +14,8 @@ A lightweight, production-ready HTTP service that always says "no" in various fo
## API Endpoints
- `GET /` - Web frontend
- `GET /` - Minimalist web page displaying "No"
- `GET /playground` - Interactive API testing playground
- `GET /api/no` - Returns plain text "no"
- `GET /api/no?format=json` - Returns `{"answer": "no"}`
- `GET /api/no?format=bool` - Returns `false`

View file

@ -2,7 +2,95 @@ use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};
use std::thread;
const HTML_FRONTEND: &str = r#"<!DOCTYPE html>
const SIMPLE_FRONTEND: &str = r#"<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>No</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: #ffffff;
color: #000000;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.no {
font-size: clamp(3rem, 15vw, 12rem);
font-weight: 300;
letter-spacing: -0.02em;
user-select: none;
animation: subtle-fade 2s ease-out;
}
.footer {
position: absolute;
bottom: 2rem;
font-size: 0.875rem;
color: #666;
}
.footer a {
color: #666;
text-decoration: none;
padding: 0 0.5rem;
transition: color 0.2s ease;
}
.footer a:hover {
color: #000;
}
@keyframes subtle-fade {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (prefers-color-scheme: dark) {
body {
background: #000000;
color: #ffffff;
}
.footer {
color: #999;
}
.footer a {
color: #999;
}
.footer a:hover {
color: #fff;
}
}
</style>
</head>
<body>
<div class="no">No</div>
<div class="footer">
<a href="/playground">Playground</a>
<span>·</span>
<a href="/api/no">API</a>
</div>
</body>
</html>"#;
const PLAYGROUND_FRONTEND: &str = r#"<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
@ -315,7 +403,8 @@ fn route_request(request_line: &str) -> (&str, &str, String) {
}
match path {
"/" => ("200 OK", "text/html; charset=utf-8", HTML_FRONTEND.to_string()),
"/" => ("200 OK", "text/html; charset=utf-8", SIMPLE_FRONTEND.to_string()),
"/playground" => ("200 OK", "text/html; charset=utf-8", PLAYGROUND_FRONTEND.to_string()),
"/health" => ("200 OK", "text/plain", "OK".to_string()),
path if path.starts_with("/api/no") => handle_api_no(path),
_ => ("404 Not Found", "text/plain", "Not Found".to_string()),