Hook up the web to the db
This commit is contained in:
parent
d71334cda7
commit
f89d5f5d05
2
Makefile
2
Makefile
@ -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
|
||||
|
13
cmd/serve.go
13
cmd/serve.go
@ -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)
|
||||
}
|
||||
|
@ -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 }}
|
||||
|
@ -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
75
web/html/intake.css
Normal 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;
|
||||
}
|
@ -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
34
web/main.go
Normal 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))
|
||||
}
|
32
web/root.go
32
web/root.go
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user