AnthoLume/web/pages/documents.go
2025-08-17 17:04:54 -04:00

122 lines
3.6 KiB
Go

package pages
import (
"fmt"
g "maragu.dev/gomponents"
h "maragu.dev/gomponents/html"
"reichard.io/antholume/web/assets"
"reichard.io/antholume/web/components/document"
"reichard.io/antholume/web/components/ui"
"reichard.io/antholume/web/models"
)
var _ Page = (*Documents)(nil)
type Documents struct {
Data []models.Document
Previous int
Next int
Limit int
}
func (Documents) Route() PageRoute { return DocumentsPage }
func (p Documents) Render() g.Node {
return g.Group([]g.Node{
searchBar(),
documentGrid(p.Data),
pagination(p.Previous, p.Next, p.Limit),
uploadFAB(),
})
}
func searchBar() g.Node {
return h.Div(
h.Class("flex flex-col gap-2 grow p-4 mb-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"),
h.Form(
h.Action("./documents"),
h.Method("GET"),
h.Class("flex gap-4 flex-col lg:flex-row"),
h.Div(
h.Class("flex flex-col w-full grow"),
h.Div(
h.Class("flex relative"),
h.Span(
h.Class("inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"),
assets.Icon("search2", 15),
),
h.Input(
h.Type("text"),
h.ID("search"),
h.Name("search"),
h.Class("flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-2 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"),
h.Placeholder("Search Author / Title"),
),
),
),
h.Div(
h.Class("lg:w-60"),
ui.FormButton(g.Text("Search"), "", ui.ButtonConfig{Variant: ui.ButtonVariantSecondary}),
),
),
)
}
func documentGrid(docs []models.Document) g.Node {
return h.Div(
h.Class("grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3"),
g.Map(docs, func(d models.Document) g.Node { return document.Card(d) }),
)
}
func pagination(prev, next int, limit int) g.Node {
link := func(page int, label string) g.Node {
return h.A(
h.Href(fmt.Sprintf("./documents?page=%d&limit=%d", page, limit)),
h.Class("bg-white shadow-lg dark:bg-gray-600 hover:bg-gray-400 font-medium rounded text-sm text-center p-2 w-24 dark:hover:bg-gray-700 focus:outline-none"),
g.Text(label),
)
}
return h.Div(
h.Class("w-full flex gap-4 justify-center mt-4 text-black dark:text-white"),
g.If(prev > 0, link(prev, "◄")),
g.If(next > 0, link(next, "►")),
)
}
func uploadFAB() g.Node {
return h.Div(
h.Class("fixed bottom-6 right-6 rounded-full flex items-center justify-center"),
h.Input(h.Type("checkbox"), h.ID("upload-file-button"), h.Class("hidden css-button")),
h.Div(
h.Class("absolute right-0 z-10 bottom-0 rounded p-4 bg-gray-800 dark:bg-gray-200 text-white dark:text-black w-72 text-sm flex flex-col gap-2"),
h.Form(
h.Method("POST"),
g.Attr("enctype", "multipart/form-data"),
h.Action("./documents"),
h.Class("flex flex-col gap-2"),
h.Input(
h.Type("file"),
h.Accept(".epub"),
h.ID("document_file"),
h.Name("document_file"),
),
ui.FormButton(g.Text("Upload File"), ""),
),
h.Label(
h.For("upload-file-button"),
h.Div(
h.Class("w-full text-center cursor-pointer font-medium mt-2 px-2 py-1 text-gray-800 bg-gray-500 dark:text-white hover:bg-gray-100 dark:hover:bg-gray-800"),
g.Text("Cancel Upload"),
),
),
),
h.Label(
h.For("upload-file-button"),
h.Class("w-16 h-16 bg-gray-800 dark:bg-gray-200 rounded-full flex items-center justify-center opacity-30 hover:opacity-100 transition-all duration-200 cursor-pointer"),
assets.Icon("upload", 34),
),
)
}