1package ui
2
3import (
4 "strconv"
5 "strings"
6)
7
8type DOM struct {
9 // metadata
10 Prefix string
11 Title string
12 WithComments bool
13 Classes []string
14
15 // elements
16 Header Element
17 Body Element
18 Footer Element
19}
20
21func (dom DOM) String() string {
22 classes := strings.Join(dom.Classes, " ")
23
24 output := ""
25
26 if classes != "" {
27 output += "<main class='" + classes + "'>" + "\n\n"
28 }
29
30 if dom.Title != "" {
31 output += H1(dom.Title).String(dom) + "\n"
32 }
33
34 if header := dom.Header.String(dom); header != "" {
35 if dom.WithComments {
36 output += "<!-- header -->"
37 }
38 output += header + "\n"
39 if dom.WithComments {
40 output += "<!-- /header -->"
41 }
42 }
43
44 if body := dom.Body.String(dom); body != "" {
45 if dom.WithComments {
46 output += "<!-- body -->"
47 }
48 output += body + "\n"
49 if dom.WithComments {
50 output += "<!-- /body -->"
51 }
52 }
53
54 if footer := dom.Footer.String(dom); footer != "" {
55 if dom.WithComments {
56 output += "<!-- footer -->"
57 }
58 output += footer + "\n"
59 if dom.WithComments {
60 output += "<!-- /footer -->"
61 }
62 }
63
64 if classes != "" {
65 output += "</main>"
66 }
67
68 // TODO: cleanup double new-lines.
69
70 return output
71}
72
73type Jumbotron []DomStringer
74
75func (j Jumbotron) String(dom DOM) string {
76 output := `<div class="jumbotron">` + "\n\n"
77 for _, elem := range j {
78 output += elem.String(dom) + "\n"
79 }
80 output += `</div><!-- /jumbotron -->` + "\n"
81 return output
82}
83
84// XXX: rename Element to Div?
85type Element []DomStringer
86
87func (e *Element) Append(elems ...DomStringer) {
88 *e = append(*e, elems...)
89}
90
91func (e *Element) String(dom DOM) string {
92 output := ""
93 for _, elem := range *e {
94 output += elem.String(dom) + "\n"
95 }
96 return output
97}
98
99type Breadcrumb []DomStringer
100
101func (b *Breadcrumb) Append(elems ...DomStringer) {
102 *b = append(*b, elems...)
103}
104
105func (b Breadcrumb) String(dom DOM) string {
106 output := ""
107 for idx, entry := range b {
108 if idx > 0 {
109 output += " / "
110 }
111 output += entry.String(dom)
112 }
113 return output
114}
115
116type Columns struct {
117 MaxWidth int
118 Columns []Element
119}
120
121func (c *Columns) Append(elems ...Element) {
122 c.Columns = append(c.Columns, elems...)
123}
124
125func (c Columns) String(dom DOM) string {
126 output := `<div class="columns-` + strconv.Itoa(c.MaxWidth) + `">` + "\n"
127 for _, entry := range c.Columns {
128 output += `<div class="column">` + "\n\n"
129 output += entry.String(dom)
130 output += "</div><!-- /column-->\n"
131 }
132 output += "</div><!-- /columns-" + strconv.Itoa(c.MaxWidth) + " -->\n"
133 return output
134}
135
136type Link struct {
137 Text string
138 Path string
139 URL string
140}
141
142// TODO: image
143
144// TODO: pager
145
146func (l Link) String(dom DOM) string {
147 url := ""
148 switch {
149 case l.Path != "" && l.URL != "":
150 panic("a link should have a path or a URL, not both.")
151 case l.Path != "":
152 if l.Text == "" {
153 l.Text = l.Path
154 }
155 url = dom.Prefix + l.Path
156 case l.URL != "":
157 if l.Text == "" {
158 l.Text = l.URL
159 }
160 url = l.URL
161 }
162
163 return "[" + l.Text + "](" + url + ")"
164}
165
166type BulletList []DomStringer
167
168func (bl BulletList) String(dom DOM) string {
169 output := ""
170
171 for _, entry := range bl {
172 output += "- " + entry.String(dom) + "\n"
173 }
174
175 return output
176}
177
178func Text(s string) DomStringer {
179 return Raw{Content: s}
180}
181
182type DomStringer interface {
183 String(dom DOM) string
184}
185
186type Raw struct {
187 Content string
188}
189
190func (r Raw) String(_ DOM) string {
191 return r.Content
192}
193
194type (
195 H1 string
196 H2 string
197 H3 string
198 H4 string
199 H5 string
200 H6 string
201 Bold string
202 Italic string
203 Code string
204 Paragraph string
205 Quote string
206 HR struct{}
207)
208
209func (text H1) String(_ DOM) string { return "# " + string(text) + "\n" }
210func (text H2) String(_ DOM) string { return "## " + string(text) + "\n" }
211func (text H3) String(_ DOM) string { return "### " + string(text) + "\n" }
212func (text H4) String(_ DOM) string { return "#### " + string(text) + "\n" }
213func (text H5) String(_ DOM) string { return "##### " + string(text) + "\n" }
214func (text H6) String(_ DOM) string { return "###### " + string(text) + "\n" }
215func (text Quote) String(_ DOM) string { return "> " + string(text) + "\n" }
216func (text Bold) String(_ DOM) string { return "**" + string(text) + "**" }
217func (text Italic) String(_ DOM) string { return "_" + string(text) + "_" }
218func (text Paragraph) String(_ DOM) string { return "\n" + string(text) + "\n" }
219func (_ HR) String(_ DOM) string { return "\n---\n" }
220
221func (text Code) String(_ DOM) string {
222 // multiline
223 if strings.Contains(string(text), "\n") {
224 return "\n```\n" + string(text) + "\n```\n"
225 }
226
227 // single line
228 return "`" + string(text) + "`"
229}
ui.gno
4.54 Kb ยท 229 lines