appview/strings: add timeline page #509

merged
opened by oppi.li targeting master from push-wvywrqlppxqo
Changed files
+111 -5
appview
db
pages
templates
strings
strings
+11 -2
appview/db/strings.go
···
return err
}
-
func GetStrings(e Execer, filters ...filter) ([]String, error) {
+
func GetStrings(e Execer, limit int, filters ...filter) ([]String, error) {
var all []String
var conditions []string
···
whereClause = " where " + strings.Join(conditions, " and ")
}
+
limitClause := ""
+
if limit != 0 {
+
limitClause = fmt.Sprintf(" limit %d ", limit)
+
}
+
query := fmt.Sprintf(`select
did,
rkey,
···
content,
created,
edited
-
from strings %s`,
+
from strings
+
%s
+
order by created desc
+
%s`,
whereClause,
+
limitClause,
)
rows, err := e.Query(query, args...)
+9
appview/pages/pages.go
···
return p.execute("strings/dashboard", w, params)
+
type StringTimelineParams struct {
+
LoggedInUser *oauth.User
+
Strings []db.String
+
}
+
+
func (p *Pages) StringsTimeline(w io.Writer, params StringTimelineParams) error {
+
return p.execute("strings/timeline", w, params)
+
}
+
type SingleStringParams struct {
LoggedInUser *oauth.User
ShowRendered bool
+2 -1
appview/pages/templates/strings/fragments/form.html
···
name="content"
id="content-textarea"
wrap="off"
-
class="w-full dark:bg-gray-700 dark:text-white dark:border-gray-600 dark:placeholder-gray-400"
+
class="w-full dark:bg-gray-700 dark:text-white dark:border-gray-600 dark:placeholder-gray-400 font-mono"
rows="20"
+
spellcheck="false"
placeholder="Paste your string here!"
required>{{ .String.Contents }}</textarea>
<div class="flex justify-between items-center">
+1 -1
appview/pages/templates/strings/string.html
···
{{ end }}
</div>
</div>
-
<div class="overflow-auto relative">
+
<div class="overflow-x-auto overflow-y-hidden relative">
{{ if .ShowRendered }}
<div id="blob-contents" class="prose dark:prose-invert">{{ .RenderedContents }}</div>
{{ else }}
+65
appview/pages/templates/strings/timeline.html
···
+
{{ define "title" }} all strings {{ end }}
+
+
{{ define "topbar" }}
+
{{ template "layouts/topbar" $ }}
+
{{ end }}
+
+
{{ define "content" }}
+
{{ block "timeline" $ }}{{ end }}
+
{{ end }}
+
+
{{ define "timeline" }}
+
<div>
+
<div class="p-6">
+
<p class="text-xl font-bold dark:text-white">All strings</p>
+
</div>
+
+
<div class="flex flex-col gap-4">
+
{{ range $i, $s := .Strings }}
+
<div class="relative">
+
{{ if ne $i 0 }}
+
<div class="absolute left-8 -top-4 w-px h-4 bg-gray-300 dark:bg-gray-600"></div>
+
{{ end }}
+
<div class="flex flex-col divide-y divide-gray-200 dark:divide-gray-700 border border-gray-200 dark:border-gray-700 rounded-sm">
+
{{ template "stringCard" $s }}
+
</div>
+
</div>
+
{{ end }}
+
</div>
+
</div>
+
{{ end }}
+
+
{{ define "stringCard" }}
+
<div class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800">
+
<div class="font-medium dark:text-white flex gap-2 items-center">
+
<a href="/strings/{{ resolve .Did.String }}/{{ .Rkey }}">{{ .Filename }}</a>
+
</div>
+
{{ with .Description }}
+
<div class="text-gray-600 dark:text-gray-300 text-sm">
+
{{ . }}
+
</div>
+
{{ end }}
+
+
{{ template "stringCardInfo" . }}
+
</div>
+
{{ end }}
+
+
{{ define "stringCardInfo" }}
+
{{ $stat := .Stats }}
+
{{ $resolved := resolve .Did.String }}
+
<div class="text-gray-400 pt-4 text-sm font-mono inline-flex items-center gap-2 mt-auto">
+
<a href="/strings/{{ $resolved }}" class="flex items-center">
+
{{ template "user/fragments/picHandle" $resolved }}
+
</a>
+
<span class="select-none [&:before]:content-['·']"></span>
+
<span>{{ $stat.LineCount }} line{{if ne $stat.LineCount 1}}s{{end}}</span>
+
<span class="select-none [&:before]:content-['·']"></span>
+
{{ with .Edited }}
+
<span>edited {{ template "repo/fragments/shortTimeAgo" . }}</span>
+
{{ else }}
+
{{ template "repo/fragments/shortTimeAgo" .Created }}
+
{{ end }}
+
</div>
+
{{ end }}
+
+
+22
appview/strings/strings.go
···
func (s *Strings) Router(mw *middleware.Middleware) http.Handler {
r := chi.NewRouter()
+
r.
+
Get("/", s.timeline)
+
r.
With(mw.ResolveIdent()).
Route("/{user}", func(r chi.Router) {
···
return r
}
+
func (s *Strings) timeline(w http.ResponseWriter, r *http.Request) {
+
l := s.Logger.With("handler", "timeline")
+
+
strings, err := db.GetStrings(s.Db, 50)
+
if err != nil {
+
l.Error("failed to fetch string", "err", err)
+
w.WriteHeader(http.StatusInternalServerError)
+
return
+
}
+
+
s.Pages.StringsTimeline(w, pages.StringTimelineParams{
+
LoggedInUser: s.OAuth.GetUser(r),
+
Strings: strings,
+
})
+
}
+
func (s *Strings) contents(w http.ResponseWriter, r *http.Request) {
l := s.Logger.With("handler", "contents")
···
strings, err := db.GetStrings(
s.Db,
+
0,
db.FilterEq("did", id.DID),
db.FilterEq("rkey", rkey),
)
···
all, err := db.GetStrings(
s.Db,
+
0,
db.FilterEq("did", id.DID),
)
if err != nil {
···
// get the string currently being edited
all, err := db.GetStrings(
s.Db,
+
0,
db.FilterEq("did", id.DID),
db.FilterEq("rkey", rkey),
)
+1 -1
input.css
···
}
code {
-
@apply font-mono rounded bg-gray-100 dark:bg-gray-700;
+
@apply font-mono rounded bg-gray-100 dark:bg-gray-700 text-black dark:text-white;
}
}