wip
This commit is contained in:
129
web/pages/document.go
Normal file
129
web/pages/document.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
g "maragu.dev/gomponents"
|
||||
h "maragu.dev/gomponents/html"
|
||||
"reichard.io/antholume/pkg/formatters"
|
||||
"reichard.io/antholume/pkg/ptr"
|
||||
"reichard.io/antholume/pkg/utils"
|
||||
"reichard.io/antholume/web/assets"
|
||||
"reichard.io/antholume/web/components/document"
|
||||
"reichard.io/antholume/web/components/ui"
|
||||
"reichard.io/antholume/web/models"
|
||||
)
|
||||
|
||||
var _ Page = (*Document)(nil)
|
||||
|
||||
type Document struct {
|
||||
Data models.Document
|
||||
Search *models.DocumentMetadata
|
||||
}
|
||||
|
||||
func (Document) Route() PageRoute { return DocumentPage }
|
||||
|
||||
func (p Document) Render() g.Node {
|
||||
return h.Div(
|
||||
h.Class("h-full w-full overflow-scroll bg-white shadow-lg dark:bg-gray-700 rounded dark:text-white p-4"),
|
||||
document.Actions(p.Data),
|
||||
|
||||
// Details
|
||||
h.Div(
|
||||
h.Class("grid sm:grid-cols-2 justify-between gap-3 pb-3"),
|
||||
|
||||
editableKeyValue(
|
||||
p.Data.ID,
|
||||
"Title",
|
||||
p.Data.Title,
|
||||
"title",
|
||||
),
|
||||
editableKeyValue(
|
||||
p.Data.ID,
|
||||
"Author",
|
||||
p.Data.Author,
|
||||
"author",
|
||||
),
|
||||
popoverKeyValue(
|
||||
"Time Read",
|
||||
formatters.FormatDuration(p.Data.TotalTimeRead),
|
||||
"info",
|
||||
p.detailsPopover(),
|
||||
),
|
||||
|
||||
ui.KeyValue(
|
||||
g.Text("Progress"),
|
||||
g.Text(fmt.Sprintf("%.2f%%", p.Data.Percentage)),
|
||||
),
|
||||
ui.KeyValue(
|
||||
g.Text("ISBN-10"),
|
||||
g.Text(utils.FirstNonZero(p.Data.ISBN10, "N/A")),
|
||||
),
|
||||
ui.KeyValue(
|
||||
g.Text("ISBN-13"),
|
||||
g.Text(utils.FirstNonZero(p.Data.ISBN13, "N/A")),
|
||||
),
|
||||
),
|
||||
|
||||
editableKeyValue(
|
||||
p.Data.ID,
|
||||
"Description",
|
||||
p.Data.Description,
|
||||
"description",
|
||||
ui.PopoverConfig{Classes: "w-full"},
|
||||
),
|
||||
|
||||
document.IdentifyPopover(p.Data.ID, p.Search),
|
||||
)
|
||||
}
|
||||
|
||||
func (p *Document) detailsPopover() g.Node {
|
||||
totalTimeLeft := time.Duration((100.0 - p.Data.Percentage) * float64(p.Data.TimePerPercent))
|
||||
percentPerHour := 1.0 / p.Data.TimePerPercent.Hours()
|
||||
return h.Div(
|
||||
statKV("WPM", fmt.Sprint(p.Data.WPM)),
|
||||
statKV("Words", formatters.FormatNumber(ptr.Deref(p.Data.Words))),
|
||||
statKV("Hourly Rate", fmt.Sprintf("%.1f%%", percentPerHour)),
|
||||
statKV("Time Remaining", formatters.FormatDuration(totalTimeLeft)),
|
||||
)
|
||||
}
|
||||
|
||||
func popoverKeyValue(title, value, icon string, popover g.Node, popoverCfg ...ui.PopoverConfig) g.Node {
|
||||
return ui.KeyValue(
|
||||
ui.AnchoredPopover(
|
||||
h.Div(
|
||||
h.Class("inline-flex gap-2 items-center"),
|
||||
h.P(g.Text(title)),
|
||||
ui.SpanButton(assets.Icon(icon, 18), ui.ButtonConfig{Variant: ui.ButtonVariantGhost}),
|
||||
),
|
||||
popover,
|
||||
popoverCfg...,
|
||||
),
|
||||
g.Text(value),
|
||||
)
|
||||
}
|
||||
|
||||
func editableKeyValue(id, title, currentValue, formKey string, popoverCfg ...ui.PopoverConfig) g.Node {
|
||||
currentValue = utils.FirstNonZero(currentValue, "N/A")
|
||||
editPopover := h.Form(
|
||||
h.Class("flex flex-col gap-2"),
|
||||
h.Action(fmt.Sprintf("./%s/edit", id)),
|
||||
h.Method("POST"),
|
||||
h.Textarea(
|
||||
h.ID(formKey),
|
||||
h.Name(formKey),
|
||||
h.Class("p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white"),
|
||||
g.Text(currentValue),
|
||||
),
|
||||
ui.FormButton(g.Text("Save"), ""),
|
||||
)
|
||||
return popoverKeyValue(title, currentValue, "edit", editPopover, popoverCfg...)
|
||||
}
|
||||
|
||||
func statKV(title, val string) g.Node {
|
||||
return ui.HKeyValue(
|
||||
h.P(h.Class("text-xs w-24 text-gray-400"), g.Text(title)),
|
||||
h.P(h.Class("text-xs text-nowrap"), g.Text(val)),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user