chore: add twt html formatting
This commit is contained in:
parent
ef65b115b7
commit
a7009dcb56
16
http-api.go
16
http-api.go
@ -194,16 +194,24 @@ func add(preamble lextwt.Comments, text string, v ...any) lextwt.Comments {
|
||||
}
|
||||
return append(preamble, lextwt.NewComment("# "+text))
|
||||
}
|
||||
func addKey(preamble lextwt.Comments, key, value string, v ...any) lextwt.Comments {
|
||||
if len(v) > 0 {
|
||||
value = fmt.Sprintf(value, v...)
|
||||
}
|
||||
comment := fmt.Sprintf("# %s = %s", key, value)
|
||||
return append(preamble, lextwt.NewCommentValue(comment, key, value))
|
||||
}
|
||||
|
||||
|
||||
func mkPreamble(hostname, uri, path string, limit int, length, offset, end int64) lextwt.Comments {
|
||||
uri += path
|
||||
preamble := add(mkPreambleDocs(hostname), "twt range = 1 %d", end)
|
||||
preamble = add(preamble, "self = %s%s", hostname, mkqry(uri, limit, offset))
|
||||
preamble := addKey(mkPreambleDocs(hostname), "twt range", "1 %d", end)
|
||||
preamble = addKey(preamble, "self", "%s%s", hostname, mkqry(uri, limit, offset))
|
||||
if next := offset + length; next < end {
|
||||
preamble = add(preamble, "next = %s%s", hostname, mkqry(uri, limit, next))
|
||||
preamble = addKey(preamble, "next", "%s%s", hostname, mkqry(uri, limit, next))
|
||||
}
|
||||
if prev := offset - int64(limit); prev > 0 {
|
||||
preamble = add(preamble, "prev = %s%s", hostname, mkqry(uri, limit, prev))
|
||||
preamble = addKey(preamble, "prev", "%s%s", hostname, mkqry(uri, limit, prev))
|
||||
}
|
||||
return preamble
|
||||
}
|
||||
|
160
http-html.go
160
http-html.go
@ -1,9 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.sour.is/xt/internal/otel"
|
||||
"go.yarn.social/lextwt"
|
||||
"go.yarn.social/types"
|
||||
)
|
||||
|
||||
type HTML struct {
|
||||
@ -21,10 +29,156 @@ func (a *HTML) healthcheck(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (a *HTML) home(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := otel.Span(r.Context())
|
||||
ctx, span := otel.Span(r.Context())
|
||||
defer span.End()
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Write([]byte("ok"))
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
|
||||
uri := r.URL.Query().Get("uri")
|
||||
|
||||
limit := 100
|
||||
if v, ok := strconv.Atoi(r.URL.Query().Get("limit")); ok == nil {
|
||||
limit = v
|
||||
}
|
||||
limit = min(100, max(1, limit))
|
||||
|
||||
var offset int64 = 0
|
||||
if v, ok := strconv.ParseInt(r.URL.Query().Get("offset"), 10, 64); ok == nil {
|
||||
offset = v
|
||||
}
|
||||
|
||||
twts, offset, end, err := fetchTwts(ctx, a.db, uri, limit, offset)
|
||||
span.RecordError(err)
|
||||
if err != nil {
|
||||
http.Error(w, "ERR", 500)
|
||||
return
|
||||
}
|
||||
|
||||
preamble := mkPreamble(a.hostname, uri, "", limit, int64(len(twts)), offset, end)
|
||||
|
||||
reg := &HTWriter{
|
||||
lextwt.NewTwtRegistry(preamble, twts),
|
||||
}
|
||||
|
||||
reg.WriteTo(w)
|
||||
}
|
||||
|
||||
type reg interface {
|
||||
Preamble() lextwt.Comments
|
||||
Twts() types.Twts
|
||||
}
|
||||
|
||||
type HTWriter struct {
|
||||
reg
|
||||
}
|
||||
|
||||
func (r *HTWriter) WriteTo(w io.Writer) (int64, error) {
|
||||
var output int64
|
||||
i, err := fmt.Fprintln(w, `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>The Watcher</title>
|
||||
<style>
|
||||
body { width: 70%; margin: auto; background: black; color: white; }
|
||||
a { color: cornflowerblue; text-decoration: none; }
|
||||
main { }
|
||||
pre.preamble { color: green; }
|
||||
article { border: 1px solid green; border-radius: 4px; padding: 4px; margin: 2px; }
|
||||
.h-card { columns: 2; }
|
||||
.h-card .author { display: flex; }
|
||||
.h-card .icon { width: 36px; margin: 4px; }
|
||||
.h-card .u-photo { width: 32px; }
|
||||
.h-card .date { text-align: right;}
|
||||
section { overflow: scroll; }
|
||||
</style
|
||||
</head>
|
||||
<body>
|
||||
<pre class='preamble'>
|
||||
`)
|
||||
output += int64(i)
|
||||
if err != nil {
|
||||
return output, err
|
||||
}
|
||||
|
||||
for _, c := range r.Preamble() {
|
||||
if key := c.Key(); key != "" {
|
||||
value := mkValue(c.Value())
|
||||
i, err = fmt.Fprintf(w, "# %s = %s\n", key, value)
|
||||
} else {
|
||||
i, err = fmt.Fprintln(w, c.Text())
|
||||
}
|
||||
|
||||
output += int64(i)
|
||||
if err != nil {
|
||||
return output, err
|
||||
}
|
||||
}
|
||||
|
||||
i, err = fmt.Fprintln(w, "</pre><main>")
|
||||
output += int64(i)
|
||||
|
||||
for _, twt := range r.Twts() {
|
||||
twter := twt.Twter()
|
||||
uri, err := url.Parse(twter.URI)
|
||||
if err != nil {
|
||||
uri = &url.URL{
|
||||
Scheme: "HTTPS",
|
||||
Host: "unknown.txt",
|
||||
}
|
||||
}
|
||||
i, err = fmt.Fprintf(w, `
|
||||
<article>
|
||||
<header class="u-author h-card">
|
||||
<div class="author">
|
||||
<div class="icon">
|
||||
<a href="%s" class="u-url">
|
||||
<img class="avatar u-photo" src="%s" alt="" loading="lazy">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="author-name">
|
||||
<div class="p-name">
|
||||
<a href="%s">%s</a>
|
||||
</div>
|
||||
|
||||
<div class="p-org">
|
||||
<a target="_blank" href="%s">%s</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="date">
|
||||
<div><a class="u-url" href="%s">%s</a></div>
|
||||
<div><small>%s</small></div>
|
||||
</div>
|
||||
</header>
|
||||
<section>
|
||||
<pre>%M</pre>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
`, "/?uri="+twter.URI, "https://txt.sour.is/user/xuu/avatar",
|
||||
"/?uri="+twter.URI, twter.Nick,
|
||||
twter.URI, uri.Host,
|
||||
"/conv/"+twt.Hash(), fmt.Sprintf("<time datetime='%s'>%s</time>", twt.Created().Format(time.RFC3339), twt.Created().Format(time.RFC822)),
|
||||
time.Since(twt.Created()).Round(time.Second).String(), twt,
|
||||
)
|
||||
output += int64(i)
|
||||
if err != nil {
|
||||
return output, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
i, err = fmt.Fprintln(w, "</main></body>")
|
||||
output += int64(i)
|
||||
|
||||
return output, err
|
||||
}
|
||||
|
||||
func mkValue(v string) string {
|
||||
if strings.HasPrefix(v, "http") {
|
||||
return fmt.Sprintf(`<a href="%s">%s</a>`, v, v)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user