Skip to content

Commit ade3e16

Browse files
bricefclaude
andcommitted
Add landing page at / with links to dashboard, API, and GitHub
Static HTML embedded in the binary. Shows project name, tagline, and links to the dashboard, OpenAPI spec, health check, and GitHub repo. No auth required. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 4291511 commit ade3e16

2 files changed

Lines changed: 96 additions & 0 deletions

File tree

internal/http/landing.html

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<title>TaskFlow</title>
7+
<style>
8+
* { margin: 0; padding: 0; box-sizing: border-box; }
9+
body {
10+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
11+
background: #0d1117;
12+
color: #e6edf3;
13+
display: flex;
14+
justify-content: center;
15+
align-items: center;
16+
min-height: 100vh;
17+
padding: 2rem;
18+
}
19+
.container {
20+
max-width: 600px;
21+
text-align: center;
22+
}
23+
h1 {
24+
font-size: 2.5rem;
25+
font-weight: 700;
26+
margin-bottom: 0.5rem;
27+
}
28+
.tagline {
29+
color: #8b949e;
30+
font-size: 1.1rem;
31+
margin-bottom: 2rem;
32+
}
33+
.links {
34+
display: flex;
35+
flex-wrap: wrap;
36+
gap: 0.75rem;
37+
justify-content: center;
38+
margin-bottom: 2rem;
39+
}
40+
a {
41+
display: inline-block;
42+
padding: 0.6rem 1.2rem;
43+
border-radius: 6px;
44+
text-decoration: none;
45+
font-size: 0.95rem;
46+
font-weight: 500;
47+
transition: background 0.15s;
48+
}
49+
.primary {
50+
background: #238636;
51+
color: #fff;
52+
}
53+
.primary:hover { background: #2ea043; }
54+
.secondary {
55+
background: #21262d;
56+
color: #e6edf3;
57+
border: 1px solid #30363d;
58+
}
59+
.secondary:hover { background: #30363d; }
60+
.status {
61+
color: #8b949e;
62+
font-size: 0.85rem;
63+
}
64+
.status a {
65+
color: #58a6ff;
66+
padding: 0;
67+
background: none;
68+
border: none;
69+
font-size: inherit;
70+
}
71+
</style>
72+
</head>
73+
<body>
74+
<div class="container">
75+
<h1>TaskFlow</h1>
76+
<p class="tagline">Kanban boards with workflow state machines, built for human + AI collaboration.</p>
77+
<div class="links">
78+
<a class="primary" href="/dashboard">Dashboard</a>
79+
<a class="secondary" href="/openapi.json">API Spec</a>
80+
<a class="secondary" href="/health">Health</a>
81+
<a class="secondary" href="https://github.com/bricef/taskflow">GitHub</a>
82+
</div>
83+
<p class="status">Server is running. See the <a href="https://github.com/bricef/taskflow">README</a> for CLI, TUI, and MCP setup.</p>
84+
</div>
85+
</body>
86+
</html>

internal/http/routes.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package http
22

33
import (
4+
_ "embed"
45
"encoding/json"
56
"io/fs"
67
"net/http"
@@ -14,6 +15,9 @@ import (
1415
"github.com/bricef/taskflow/internal/transport"
1516
)
1617

18+
//go:embed landing.html
19+
var landingPage []byte
20+
1721
// Route is the HTTP-layer representation of a domain resource or operation.
1822
type Route struct {
1923
Name string
@@ -181,6 +185,12 @@ func (s *Server) registerRoutes() {
181185
r.Use(httprate.Limit(30, time.Minute, httprate.WithKeyFuncs(httprate.KeyByRealIP)))
182186
}
183187

188+
// Landing page — no auth.
189+
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
190+
w.Header().Set("Content-Type", "text/html; charset=utf-8")
191+
w.Write(landingPage)
192+
})
193+
184194
// Dashboard — static HTML, no auth (uses API key from client-side JS).
185195
dashFS, _ := fs.Sub(dashboard.FS, ".")
186196
r.Get("/dashboard", func(w http.ResponseWriter, r *http.Request) {

0 commit comments

Comments
 (0)