chore: add twt html formatting

This commit is contained in:
xuu 2025-04-02 10:47:30 -06:00
parent ef65b115b7
commit a7009dcb56
Signed by: xuu
GPG Key ID: 8B3B0604F164E04F
2 changed files with 169 additions and 7 deletions

View File

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

View File

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