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"
|
"embed"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"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
|
//go:embed intake.css
|
||||||
var Stylesheet []byte
|
var Stylesheet []byte
|
||||||
|
|
||||||
@ -13,7 +28,7 @@ var Stylesheet []byte
|
|||||||
var templates embed.FS
|
var templates embed.FS
|
||||||
|
|
||||||
func load(file string) *template.Template {
|
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")
|
var home = load("home.html")
|
||||||
@ -21,3 +36,9 @@ var home = load("home.html")
|
|||||||
func Home(writer io.Writer, data any) error {
|
func Home(writer io.Writer, data any) error {
|
||||||
return home.Execute(writer, data)
|
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;
|
padding: 5px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
|
display: flow-root;
|
||||||
}
|
}
|
||||||
.item-title {
|
.item-title {
|
||||||
font-size: 1.4em;
|
font-size: 1.4em;
|
||||||
@ -28,6 +29,15 @@ article {
|
|||||||
.item-info {
|
.item-info {
|
||||||
color: rgba(0, 0, 0, 0.7);
|
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 {
|
article img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
@ -29,6 +29,7 @@ func RunServer(db *core.DB, addr string, port string) {
|
|||||||
|
|
||||||
handleFunc("/", env.rootHandler)
|
handleFunc("/", env.rootHandler)
|
||||||
handleFunc("/style.css", env.styleHandler)
|
handleFunc("/style.css", env.styleHandler)
|
||||||
|
handleFunc("/source/", env.sourceHandler)
|
||||||
|
|
||||||
log.Fatal(http.ListenAndServe(bind, nil))
|
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) {
|
func (env *Env) styleHandler(writer http.ResponseWriter, req *http.Request) {
|
||||||
writer.Header()["Cache-Control"] = []string{"public, max-age=86400"}
|
writer.Header()["Cache-Control"] = []string{"public, max-age=86400"}
|
||||||
|
writer.Header()["Content-Type"] = []string{"text/css; charset=utf-8"}
|
||||||
writer.Write(html.Stylesheet)
|
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