pgenr.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. package pgenr
  2. import (
  3. "golang.org/x/net/html/atom"
  4. "html"
  5. "strings"
  6. )
  7. const (
  8. TextThemeSuccess = "success"
  9. TextThemeDanger = "danger"
  10. )
  11. type (
  12. TextOption func(t *Text)
  13. ButtonOption func(btn *Button)
  14. Text struct {
  15. Tag atom.Atom
  16. Content string
  17. Theme string
  18. Color string
  19. Style map[string]string
  20. }
  21. Button struct {
  22. Url string
  23. Text string
  24. Color string
  25. Style map[string]string
  26. }
  27. Entry struct {
  28. Title *Text
  29. Items map[string]*Text
  30. }
  31. Action struct {
  32. Instructions *Text
  33. Button *Button
  34. InviteCode string
  35. }
  36. Table struct {
  37. Title *Text
  38. Header []*Text
  39. Body [][]*Text
  40. }
  41. Page struct {
  42. Title string
  43. Head string
  44. Intros []*Text
  45. Entries []*Entry
  46. Actions []*Action
  47. Tables []*Table
  48. Outros []*Text
  49. Copyright string
  50. }
  51. )
  52. func (e *Entry) AddItem(label string, txt *Text) *Entry {
  53. if e.Items == nil {
  54. e.Items = make(map[string]*Text)
  55. }
  56. e.Items[label] = txt
  57. return e
  58. }
  59. func (page *Page) SetHead(s string) *Page {
  60. page.Head = s
  61. return page
  62. }
  63. func (page *Page) SetCopyright(s string) *Page {
  64. page.Copyright = s
  65. return page
  66. }
  67. func (page *Page) AddPlainIntro(s string) *Page {
  68. page.Intros = append(page.Intros, NewText(s, WithTextTag(atom.P)))
  69. return page
  70. }
  71. func (page *Page) AddIntro(t *Text) *Page {
  72. page.Intros = append(page.Intros, t)
  73. return page
  74. }
  75. func (page *Page) AddEntry(e *Entry) *Page {
  76. page.Entries = append(page.Entries, e)
  77. return page
  78. }
  79. func (page *Page) AddTable(t *Table) *Page {
  80. page.Tables = append(page.Tables, t)
  81. return page
  82. }
  83. func (page *Page) AddButtonAction(s string, btn *Button) *Page {
  84. page.Actions = append(page.Actions, &Action{Instructions: NewText(s, WithTextTag(atom.P)), Button: btn})
  85. return page
  86. }
  87. func (page *Page) AddInviteCodeAction(s string, code string) *Page {
  88. page.Actions = append(page.Actions, &Action{Instructions: NewText(s, WithTextTag(atom.P)), InviteCode: code})
  89. return page
  90. }
  91. func (page *Page) AddOutro(t *Text) *Page {
  92. page.Outros = append(page.Outros, t)
  93. return page
  94. }
  95. func (page *Page) AddPlainOutro(s string) *Page {
  96. page.Outros = append(page.Outros, NewText(s, WithTextTag(atom.P)))
  97. return page
  98. }
  99. func (page *Page) Escape() {
  100. page.Head = html.EscapeString(page.Head)
  101. page.Copyright = html.EscapeString(page.Copyright)
  102. }
  103. func NewPage(title string) *Page {
  104. return &Page{
  105. Title: title,
  106. Intros: make([]*Text, 0),
  107. Entries: make([]*Entry, 0),
  108. Actions: make([]*Action, 0),
  109. Outros: make([]*Text, 0),
  110. Tables: make([]*Table, 0),
  111. }
  112. }
  113. func NewEntry(title string) *Entry {
  114. return &Entry{
  115. Title: NewText(title, WithTextTag(atom.P)),
  116. Items: make(map[string]*Text),
  117. }
  118. }
  119. func WithTextTheme(s string) TextOption {
  120. return func(t *Text) {
  121. t.Theme = s
  122. }
  123. }
  124. func WithTextStyle(ms map[string]string) TextOption {
  125. return func(t *Text) {
  126. t.Style = ms
  127. }
  128. }
  129. func WithTextTag(tag atom.Atom) TextOption {
  130. return func(t *Text) {
  131. t.Tag = tag
  132. }
  133. }
  134. func WithTextColor(color string) TextOption {
  135. return func(t *Text) {
  136. t.Color = color
  137. }
  138. }
  139. func (button *Button) String() string {
  140. var (
  141. sb strings.Builder
  142. )
  143. if button.Style == nil {
  144. button.Style = make(map[string]string)
  145. }
  146. if button.Color != "" {
  147. button.Style["color"] = button.Color
  148. }
  149. sb.WriteString("<a class='button'")
  150. if button.Url != "" {
  151. sb.WriteString(" href='" + button.Url + "'")
  152. }
  153. if len(button.Style) > 0 {
  154. sb.WriteString(" style='")
  155. for k, v := range button.Style {
  156. sb.WriteString(k)
  157. sb.WriteString(":")
  158. sb.WriteString(v)
  159. sb.WriteString(";")
  160. }
  161. sb.WriteString("'")
  162. }
  163. sb.WriteString(">")
  164. sb.WriteString(html.EscapeString(button.Text))
  165. sb.WriteString("</a>")
  166. return sb.String()
  167. }
  168. func (table *Table) SetHead(header ...*Text) {
  169. table.Header = header
  170. }
  171. func (table *Table) AddCell(texts ...*Text) {
  172. if table.Body == nil {
  173. table.Body = make([][]*Text, 0)
  174. }
  175. table.Body = append(table.Body, texts)
  176. }
  177. func (table *Table) String() string {
  178. var (
  179. sb strings.Builder
  180. )
  181. sb.WriteString("<div class='table-wrapper'>")
  182. if table.Title != nil {
  183. sb.WriteString("<div class='table-title'>")
  184. sb.WriteString(table.Title.String())
  185. sb.WriteString("</div>")
  186. }
  187. sb.WriteString("<table class='table'>")
  188. if len(table.Header) > 0 {
  189. sb.WriteString("<thead><tr>")
  190. for _, text := range table.Header {
  191. sb.WriteString("<th>")
  192. sb.WriteString(text.String())
  193. sb.WriteString("</th>")
  194. }
  195. sb.WriteString("</tr></thead>")
  196. }
  197. if len(table.Body) > 0 {
  198. sb.WriteString("<tbody>")
  199. for _, cell := range table.Body {
  200. sb.WriteString("<tr>")
  201. for _, text := range cell {
  202. sb.WriteString("<td>")
  203. sb.WriteString(text.String())
  204. sb.WriteString("</td>")
  205. }
  206. sb.WriteString("</tr>")
  207. }
  208. sb.WriteString("</tbody>")
  209. }
  210. sb.WriteString("</table></div>")
  211. return sb.String()
  212. }
  213. func (text *Text) String() string {
  214. var (
  215. sb strings.Builder
  216. )
  217. if text.Style == nil {
  218. text.Style = make(map[string]string)
  219. }
  220. if text.Color != "" {
  221. text.Style["color"] = text.Color
  222. }
  223. if text.Tag == 0 {
  224. text.Tag = atom.Span
  225. }
  226. sb.WriteString("<")
  227. sb.WriteString(text.Tag.String())
  228. if text.Theme != "" {
  229. sb.WriteString(" class='text-")
  230. sb.WriteString(text.Theme)
  231. sb.WriteString("'")
  232. }
  233. if len(text.Style) > 0 {
  234. sb.WriteString(" style='")
  235. for k, v := range text.Style {
  236. sb.WriteString(k)
  237. sb.WriteString(":")
  238. sb.WriteString(v)
  239. sb.WriteString(";")
  240. }
  241. sb.WriteString("'")
  242. }
  243. sb.WriteString(">")
  244. sb.WriteString(html.EscapeString(text.Content))
  245. sb.WriteString("</")
  246. sb.WriteString(text.Tag.String())
  247. sb.WriteString(">")
  248. return sb.String()
  249. }
  250. func NewButton(label, link string, opts ...ButtonOption) *Button {
  251. btn := &Button{Text: label, Url: link}
  252. for _, cb := range opts {
  253. cb(btn)
  254. }
  255. return btn
  256. }
  257. func NewText(s string, opts ...TextOption) *Text {
  258. txt := &Text{Content: s, Tag: atom.Span}
  259. for _, cb := range opts {
  260. cb(txt)
  261. }
  262. return txt
  263. }
  264. func NewTable(title *Text) *Table {
  265. table := &Table{
  266. Title: title,
  267. Header: make([]*Text, 0),
  268. Body: make([][]*Text, 0),
  269. }
  270. return table
  271. }