Basic source feed view based on Python version
This commit is contained in:
parent
fcea58148e
commit
ab58837b5d
75
web/html/feed.html
Normal file
75
web/html/feed.html
Normal file
@ -0,0 +1,75 @@
|
||||
{{ define "title" }}{{ if .Items }}({{ len .Items }}) {{ end }}Intake{{ end }}
|
||||
|
||||
{{ define "buttons" -}}
|
||||
<button class="item-button" title="Deactivate {{ .Source }}/{{ .Id }}">✕</button>
|
||||
<button class="item-button" title="Punt {{ .Source }}/{{ .Id }}">↷</button>
|
||||
{{- if .Link }}<a class="item-link" href="{{ .Link }}" target="_blank">⇗</a>
|
||||
{{ end -}}
|
||||
{{ end }}
|
||||
|
||||
{{ define "item-title" -}}
|
||||
<span class="item-title">{{ or .Title .Id | raw }}</span>
|
||||
{{- end }}
|
||||
|
||||
{{ define "content" -}}
|
||||
<article class="center">
|
||||
<span class="item-title">
|
||||
<a href="#">Home</a>
|
||||
[<a href="#">Active</a> | <a href="#">All</a>]
|
||||
</span>
|
||||
</article>
|
||||
|
||||
{{ if .Items }}
|
||||
{{ range .Items }}
|
||||
<article id="{{ .Source }}-{{ .Id }}">
|
||||
|
||||
{{/* The item title is a clickable <summary> if there is body content */}}
|
||||
{{ if .Body }}
|
||||
<details>
|
||||
<summary>
|
||||
{{ template "buttons" . }}
|
||||
{{ template "item-title" . }}
|
||||
</summary>
|
||||
{{ if .Body }}
|
||||
<p>{{ raw .Body }}</p>
|
||||
{{ end }}
|
||||
</details>
|
||||
{{ template "buttons" . }}
|
||||
{{ else }}
|
||||
{{ template "buttons" . }}
|
||||
{{ template "item-title" . }}<br>
|
||||
{{ end }}
|
||||
{{/* end if .Body */}}
|
||||
|
||||
{{/* author/time footer line */}}
|
||||
{{ if or .Author .Time }}
|
||||
<span class="item-info">
|
||||
{{ .Author }}
|
||||
{{ .Time | tsToDate }}
|
||||
</span><br>
|
||||
{{ end }}
|
||||
|
||||
{{/* source/id/created footer line */}}
|
||||
<span class="item-info">
|
||||
{{ .Source }}/{{ .Id }}
|
||||
{{ .Created | tsToDate }}
|
||||
</span>
|
||||
|
||||
</article>
|
||||
{{ end }}
|
||||
{{/* end range .Items */}}
|
||||
|
||||
<article class="center">
|
||||
<button>Deactivate All</button>
|
||||
</article>
|
||||
|
||||
{{/* if .Items */}}
|
||||
{{ else }}
|
||||
<article class="center">
|
||||
<span class="item-title">Feed is empty</span>
|
||||
</article>
|
||||
{{ end }}
|
||||
{{/* end if .Items */}}
|
||||
|
||||
{{ end }}
|
||||
{{/* end define "content" */}}
|
@ -4,8 +4,23 @@ import (
|
||||
"embed"
|
||||
"html/template"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
func rawHtml(str string) template.HTML {
|
||||
return template.HTML(str)
|
||||
}
|
||||
|
||||
func tsToDate(t int) string {
|
||||
tm := time.Unix(int64(t), 0).UTC()
|
||||
return tm.Format(time.DateTime)
|
||||
}
|
||||
|
||||
var funcs = template.FuncMap{
|
||||
"raw": rawHtml,
|
||||
"tsToDate": tsToDate,
|
||||
}
|
||||
|
||||
//go:embed intake.css
|
||||
var Stylesheet []byte
|
||||
|
||||
@ -13,7 +28,7 @@ var Stylesheet []byte
|
||||
var templates embed.FS
|
||||
|
||||
func load(file string) *template.Template {
|
||||
return template.Must(template.New("layout.html").ParseFS(templates, "layout.html", file))
|
||||
return template.Must(template.New("layout.html").Funcs(funcs).ParseFS(templates, "layout.html", file))
|
||||
}
|
||||
|
||||
var home = load("home.html")
|
||||
@ -21,3 +36,9 @@ var home = load("home.html")
|
||||
func Home(writer io.Writer, data any) error {
|
||||
return home.Execute(writer, data)
|
||||
}
|
||||
|
||||
var feed = load("feed.html")
|
||||
|
||||
func Feed(writer io.Writer, data any) error {
|
||||
return feed.Execute(writer, data)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ article {
|
||||
padding: 5px;
|
||||
margin-bottom: 20px;
|
||||
word-break: break-word;
|
||||
display: flow-root;
|
||||
}
|
||||
.item-title {
|
||||
font-size: 1.4em;
|
||||
@ -28,6 +29,15 @@ article {
|
||||
.item-info {
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
details[open] > summary > .item-button, details[open] > summary > .item-link {
|
||||
display: none;
|
||||
}
|
||||
details ~ .item-button, details ~ .item-link {
|
||||
display: none;
|
||||
}
|
||||
details[open] ~ .item-button, details[open] ~ .item-link {
|
||||
display: inline;
|
||||
}
|
||||
article img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
|
@ -29,6 +29,7 @@ func RunServer(db *core.DB, addr string, port string) {
|
||||
|
||||
handleFunc("/", env.rootHandler)
|
||||
handleFunc("/style.css", env.styleHandler)
|
||||
handleFunc("/source/", env.sourceHandler)
|
||||
|
||||
log.Fatal(http.ListenAndServe(bind, nil))
|
||||
}
|
||||
|
@ -31,5 +31,6 @@ func (env *Env) rootHandler(writer http.ResponseWriter, req *http.Request) {
|
||||
|
||||
func (env *Env) styleHandler(writer http.ResponseWriter, req *http.Request) {
|
||||
writer.Header()["Cache-Control"] = []string{"public, max-age=86400"}
|
||||
writer.Header()["Content-Type"] = []string{"text/css; charset=utf-8"}
|
||||
writer.Write(html.Stylesheet)
|
||||
}
|
||||
|
23
web/source.go
Normal file
23
web/source.go
Normal file
@ -0,0 +1,23 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Jaculabilis/intake/core"
|
||||
"github.com/Jaculabilis/intake/web/html"
|
||||
)
|
||||
|
||||
type FeedData struct {
|
||||
Items []core.Item
|
||||
}
|
||||
|
||||
func (env *Env) sourceHandler(writer http.ResponseWriter, req *http.Request) {
|
||||
source := req.URL.Path[len("/source/"):]
|
||||
// TODO this needs to properly error if the source doesn't exist instead of just returning []
|
||||
items, err := core.GetAllItemsForSource(env.db, source)
|
||||
if err != nil {
|
||||
http.NotFound(writer, req)
|
||||
return
|
||||
}
|
||||
html.Feed(writer, FeedData{items})
|
||||
}
|
Loading…
Reference in New Issue
Block a user