package ui
import (
"strconv"
"strings"
)
type DOM struct {
// metadata
Prefix string
Title string
WithComments bool
Classes []string
// elements
Header Element
Body Element
Footer Element
}
func (dom DOM) String() string {
classes := strings.Join(dom.Classes, " ")
output := ""
if classes != "" {
output += "" + "\n\n"
}
if dom.Title != "" {
output += H1(dom.Title).String(dom) + "\n"
}
if header := dom.Header.String(dom); header != "" {
if dom.WithComments {
output += ""
}
output += header + "\n"
if dom.WithComments {
output += ""
}
}
if body := dom.Body.String(dom); body != "" {
if dom.WithComments {
output += ""
}
output += body + "\n"
if dom.WithComments {
output += ""
}
}
if footer := dom.Footer.String(dom); footer != "" {
if dom.WithComments {
output += ""
}
output += footer + "\n"
if dom.WithComments {
output += ""
}
}
if classes != "" {
output += ""
}
// TODO: cleanup double new-lines.
return output
}
type Jumbotron []DomStringer
func (j Jumbotron) String(dom DOM) string {
output := `
` + "\n\n"
for _, elem := range j {
output += elem.String(dom) + "\n"
}
output += `
` + "\n"
return output
}
// XXX: rename Element to Div?
type Element []DomStringer
func (e *Element) Append(elems ...DomStringer) {
*e = append(*e, elems...)
}
func (e *Element) String(dom DOM) string {
output := ""
for _, elem := range *e {
output += elem.String(dom) + "\n"
}
return output
}
type Breadcrumb []DomStringer
func (b *Breadcrumb) Append(elems ...DomStringer) {
*b = append(*b, elems...)
}
func (b Breadcrumb) String(dom DOM) string {
output := ""
for idx, entry := range b {
if idx > 0 {
output += " / "
}
output += entry.String(dom)
}
return output
}
type Columns struct {
MaxWidth int
Columns []Element
}
func (c *Columns) Append(elems ...Element) {
c.Columns = append(c.Columns, elems...)
}
func (c Columns) String(dom DOM) string {
output := `` + "\n"
for _, entry := range c.Columns {
output += `
` + "\n\n"
output += entry.String(dom)
output += "
\n"
}
output += "
\n"
return output
}
type Link struct {
Text string
Path string
URL string
}
// TODO: image
// TODO: pager
func (l Link) String(dom DOM) string {
url := ""
switch {
case l.Path != "" && l.URL != "":
panic("a link should have a path or a URL, not both.")
case l.Path != "":
if l.Text == "" {
l.Text = l.Path
}
url = dom.Prefix + l.Path
case l.URL != "":
if l.Text == "" {
l.Text = l.URL
}
url = l.URL
}
return "[" + l.Text + "](" + url + ")"
}
type BulletList []DomStringer
func (bl BulletList) String(dom DOM) string {
output := ""
for _, entry := range bl {
output += "- " + entry.String(dom) + "\n"
}
return output
}
func Text(s string) DomStringer {
return Raw{Content: s}
}
type DomStringer interface {
String(dom DOM) string
}
type Raw struct {
Content string
}
func (r Raw) String(_ DOM) string {
return r.Content
}
type (
H1 string
H2 string
H3 string
H4 string
H5 string
H6 string
Bold string
Italic string
Code string
Paragraph string
Quote string
HR struct{}
)
func (text H1) String(_ DOM) string { return "# " + string(text) + "\n" }
func (text H2) String(_ DOM) string { return "## " + string(text) + "\n" }
func (text H3) String(_ DOM) string { return "### " + string(text) + "\n" }
func (text H4) String(_ DOM) string { return "#### " + string(text) + "\n" }
func (text H5) String(_ DOM) string { return "##### " + string(text) + "\n" }
func (text H6) String(_ DOM) string { return "###### " + string(text) + "\n" }
func (text Quote) String(_ DOM) string { return "> " + string(text) + "\n" }
func (text Bold) String(_ DOM) string { return "**" + string(text) + "**" }
func (text Italic) String(_ DOM) string { return "_" + string(text) + "_" }
func (text Paragraph) String(_ DOM) string { return "\n" + string(text) + "\n" }
func (_ HR) String(_ DOM) string { return "\n---\n" }
func (text Code) String(_ DOM) string {
// multiline
if strings.Contains(string(text), "\n") {
return "\n```\n" + string(text) + "\n```\n"
}
// single line
return "`" + string(text) + "`"
}