Basic source feed view based on Python version

This commit is contained in:
Tim Van Baak 2025-01-24 21:27:26 -08:00
parent fcea58148e
commit ab58837b5d
6 changed files with 132 additions and 1 deletions

75
web/html/feed.html Normal file
View File

@ -0,0 +1,75 @@
{{ define "title" }}{{ if .Items }}({{ len .Items }}) {{ end }}Intake{{ end }}
{{ define "buttons" -}}
<button class="item-button" title="Deactivate {{ .Source }}/{{ .Id }}">&#10005;</button>
<button class="item-button" title="Punt {{ .Source }}/{{ .Id }}">&#8631;</button>
{{- if .Link }}<a class="item-link" href="{{ .Link }}" target="_blank">&#8663;</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" */}}

View File

@ -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)
}

View File

@ -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;

View File

@ -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))
}

View File

@ -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
View 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})
}