Hook up the web to the db

This commit is contained in:
Tim Van Baak 2025-01-24 07:15:54 -08:00
parent d71334cda7
commit f89d5f5d05
8 changed files with 175 additions and 12 deletions

View File

@ -4,4 +4,4 @@ help: ## display this help
@awk 'BEGIN{FS = ":.*##"; printf "\033[1m\nUsage\n \033[1;92m make\033[0;36m <target>\033[0m\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } ' $(MAKEFILE_LIST)
serve: ## Run "intake serve" with live reload
@air -build.cmd "go build -o scratch/intake" -build.bin scratch/intake -build.args_bin serve -build.exclude_dir scratch
@air -build.cmd "go build -o tmp/intake" -build.bin tmp/intake -build.args_bin serve,--db,tmp/db.sqlite

View File

@ -11,10 +11,21 @@ var serveCmd = &cobra.Command{
Long: `Serve the intake web interface.
`,
Run: func(cmd *cobra.Command, args []string) {
web.RunServer()
serve()
},
}
var serveAddr string
var servePort string
func init() {
rootCmd.AddCommand(serveCmd)
serveCmd.Flags().StringVarP(&serveAddr, "addr", "a", "localhost", "Address to bind to")
serveCmd.Flags().StringVarP(&servePort, "port", "p", "8081", "Port to bind to")
}
func serve() {
db := openAndMigrateDb()
web.RunServer(db, serveAddr, servePort)
}

View File

@ -1 +1,20 @@
{{ define "content" }}<h1>Hello {{ . }}</h1>{{ end }}
{{ define "title" }}Intake{{ end }}
{{ define "content" -}}
<article>
<details>
<summary><span class="item-title">Sources</span></summary>
{{ if .Sources }}
<table class="intake-sources">
{{ range .Sources }}
<tr>
<td><a href="#">{{ .Name }}</a></td>
</tr>
{{ end }}
</table>
{{ else }}
<p>No sources found.</p>
{{ end }}
</details>
</article>
{{- end }}

View File

@ -6,6 +6,9 @@ import (
"io"
)
//go:embed intake.css
var Stylesheet []byte
//go:embed *.html
var templates embed.FS

75
web/html/intake.css Normal file
View File

@ -0,0 +1,75 @@
main {
max-width: 700px;
margin: 0 auto;
}
article {
border: 1px solid black; border-radius: 6px;
padding: 5px;
margin-bottom: 20px;
word-break: break-word;
}
.item-title {
font-size: 1.4em;
}
.item-button {
font-size: 1em;
float:right;
margin-left: 2px;
}
.item-link {
text-decoration: none;
float:right;
font-size: 1em;
padding: 2px 7px;
border: 1px solid;
border-radius: 2px;
}
.item-info {
color: rgba(0, 0, 0, 0.7);
}
article img {
max-width: 100%;
height: auto;
}
button, summary {
cursor: pointer;
}
summary {
display: block;
}
summary:focus {
outline: 1px dotted gray;
}
.strikethru span, .strikethru p {
text-decoration: line-through;
}
.wide {
width: 100%;
resize: vertical;
}
.fade span, .fade p {
color: rgba(0, 0, 0, 0.2);
}
pre {
white-space: pre-wrap;
}
table.feed-control td {
font-family: monospace; padding: 5px 10px;
}
.intake-sources td {
padding-block: 0.4em;
}
.intake-sources form {
margin: 0
}
article.center {
text-align: center;
}
article textarea {
width: 100%;
resize: vertical;
}
span.error-message {
color: red;
}

View File

@ -1,8 +1,13 @@
<html>
<head>
<title>Intake</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ block "title" . }}Intake{{ end }}</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABh0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMS41ZEdYUgAAAGFJREFUOE+lkFEKwDAIxXrzXXB3ckMm9EnAV/YRCxFCcUXEL3Jc77NDjpDA/VGL3RFWYEICfeGC8oQc9IPuCAnQDcoRVmBCAn3hgvKEHPSD7ggJ0A3KEVZgQgJ94YLSJ9YDUzNGDXGZ/JEAAAAASUVORK5CYII=">
<link rel="stylesheet" href="/style.css">
</head>
<body>
<main>
{{ template "content" . }}
</main>
</body>
</html>

34
web/main.go Normal file
View File

@ -0,0 +1,34 @@
package web
import (
"log"
"net"
"net/http"
"github.com/Jaculabilis/intake/core"
)
type Env struct {
db *core.DB
}
func logged(handler http.HandlerFunc) http.HandlerFunc {
return func(writer http.ResponseWriter, req *http.Request) {
log.Printf("%s %s", req.Method, req.URL.Path)
handler(writer, req)
}
}
func handleFunc(pattern string, handler http.HandlerFunc) {
http.HandleFunc(pattern, logged(handler))
}
func RunServer(db *core.DB, addr string, port string) {
env := &Env{db}
bind := net.JoinHostPort(addr, port)
handleFunc("/", env.rootHandler)
handleFunc("/style.css", env.styleHandler)
log.Fatal(http.ListenAndServe(bind, nil))
}

View File

@ -1,19 +1,35 @@
package web
import (
"log"
"net/http"
"github.com/Jaculabilis/intake/core"
"github.com/Jaculabilis/intake/web/html"
)
func rootHandler(writer http.ResponseWriter, req *http.Request) {
log.Printf("%s %s", req.Method, req.URL.Path)
html.Home(writer, "world")
type SourceData struct {
Name string
}
func RunServer() {
http.HandleFunc("/", rootHandler)
log.Fatal(http.ListenAndServe("localhost:8081", nil))
type HomeData struct {
Sources []SourceData
}
func (env *Env) rootHandler(writer http.ResponseWriter, req *http.Request) {
names, err := core.GetSources(env.db)
if err != nil {
writer.Write([]byte(err.Error()))
}
var sources []SourceData
for _, name := range names {
sources = append(sources, SourceData{name})
}
data := HomeData{sources}
html.Home(writer, data)
}
func (env *Env) styleHandler(writer http.ResponseWriter, req *http.Request) {
writer.Header()["Cache-Control"] = []string{"public, max-age=86400"}
writer.Write(html.Stylesheet)
}