Skip to content

Instantly share code, notes, and snippets.

@fathonyfath
Created January 28, 2023 03:10
Show Gist options
  • Save fathonyfath/a9ebbc0ac02d131febfd73e93e7fead8 to your computer and use it in GitHub Desktop.
Save fathonyfath/a9ebbc0ac02d131febfd73e93e7fead8 to your computer and use it in GitHub Desktop.
Hugo template to create complex table. Has `caption`, `tfoot`, and `colgroup` HTML feature.

{{< create-table src="my-table" >}}

<!-- Collect all params and initialize variables -->
{{ $data := .Site.Data }}
{{ $src := .Get "src" }}
{{ $pathComponents := split $src "/" }}
<!-- Iterate through the .Site.Data since it is actually a dict -->
{{ range $component := $pathComponents }}
{{ if ne $data nil }}
{{ $data = index $data $component }}
{{ end }}
{{ end }}
<!--
Function to create <col /><col /><col />...
Make sure to only receive Slice
-->
{{ define "create-col" }}
{{ $items := . }}
{{ if not (reflect.IsSlice $items )}}
{{ errorf "Invalid `col` format." }}
{{ end }}
{{ range $col := $items }}
<col {{ range $attr, $value := $col }} {{$attr}}="{{$value}}" {{ end }} />
{{ end }}
{{ end }}
<!--
Function to create <th>a</th><th>b</th><th>c</th>...
Make sure to only receive Slice
-->
{{ define "create-th" }}
{{ $items := . }}
{{ if not (reflect.IsSlice $items )}}
{{ errorf "Invalid `th` format." }}
{{ end }}
{{ range $value := $items }}
<th>{{ $value }}</th>
{{ end }}
{{ end }}
<!--
Function to create <td>a</td><td>b</td><td>c</td>...
Make sure to only receive Slice
-->
{{ define "create-td" }}
{{ $items := . }}
{{ if not (reflect.IsSlice $items )}}
{{ errorf "Invalid `td` format." }}
{{ end }}
{{ range $value := $items }}
<td>{{ $value }}</td>
{{ end }}
{{ end }}
<!--
Process `head` element, breakdown map of slice into slice
-->
{{ define "process-head" }}
{{ $rows := . }}
{{ range $key, $value := $rows }}
{{ if and (not (reflect.IsMap $value)) (not (reflect.IsSlice $value)) }}
{{ errorf "Invalid `head` format." }}
{{ end }}
{{ if reflect.IsSlice $value }}
<tr>{{ template "create-th" $value }}</tr>
{{ else if reflect.IsMap $value }}
{{ template "process-head" $value }}
{{ end }}
{{ end }}
{{ end }}
<!--
Process `body` element, breakdown map of slice into slice
-->
{{ define "process-body" }}
{{ $rows := . }}
{{ range $key, $value := $rows }}
{{ if and (not (reflect.IsMap $value)) (not (reflect.IsSlice $value)) }}
{{ errorf "Invalid `body` format." }}
{{ end }}
{{ if reflect.IsSlice $value }}
<tr>{{ template "create-td" $value }}</tr>
{{ else if reflect.IsMap $value }}
{{ template "process-body" $value }}
{{ end }}
{{ end }}
{{ end }}
<!--
Process `foot` element, breakdown map of slice into slice
-->
{{ define "process-foot" }}
{{ $rows := . }}
{{ range $key, $value := $rows }}
{{ if and (not (reflect.IsMap $value)) (not (reflect.IsSlice $value)) }}
{{ errorf "Invalid `foot` format." }}
{{ end }}
{{ if reflect.IsSlice $value }}
<tr>{{ template "create-th" $value }}</tr>
{{ else if reflect.IsMap $value }}
{{ template "process-foot" $value }}
{{ end }}
{{ end }}
{{ end }}
<!--
Function to build table, populate mandatory element of table first
and then render later
-->
{{ define "build-table" }}
{{ $table := . }}
{{ $caption := "" }}
{{ $head := slice }}
{{ $body := slice }}
{{ $foot := slice }}
{{ $colGroup := slice }}
{{ range $key, $value := $table }}
{{ if eq $key "head" }}
{{ $head = $head | append $value }}
{{ else if eq $key "body" }}
{{ $body = $body | append $value }}
{{ else if eq $key "foot" }}
{{ $foot = $foot | append $value }}
{{ else if eq $key "colgroup" }}
{{ if not (reflect.IsSlice $value) }}
{{ errorf "Invalid `colgroup` format. Must be an array." }}
{{ end }}
{{ $colGroup = $value }}
{{ else if eq $key "caption" }}
{{ if gt (len $value) 0 }}
{{ if eq (printf "%T" $value) "string" }}
{{ $caption = $value }}
{{ else }}
{{ errorf "`caption` must be plain string." }}
{{ end }}
{{ end }}
{{ else }}
{{ errorf "Undefined table format. Key: %q" $key }}
{{ end }}
{{ end }}
{{ if gt (len $caption) 0 }}
<caption>{{ $caption }}</caption>
{{ end }}
{{ if gt (len $colGroup) 0 }}
<colgroup>{{ template "create-col" $colGroup }}</colgroup>
{{ end }}
{{ if gt (len $head) 0 }}
<thead>{{ template "process-head" $head }}</thead>
{{ end }}
{{ if gt (len $body) 0 }}
<tbody>{{ template "process-body" $body }}</tbody>
{{ end }}
{{ if gt (len $foot) 0 }}
<tfoot>{{ template "process-foot" $foot }}</tfoot>
{{ end }}
{{ end }}
<table>
{{- template "build-table" $data -}}
</table>
caption = "Table Caption"
[[head]]
row = ["Table Heading 1", "Table Heading 2", "Table Heading 3", "Table Heading 4", "Table Heading 5"]
[[body]]
row = ["Table Cell 1", "Table Cell 2", "Table Cell 3", "Table Cell 4", "Table Cell 5"]
row2 = ["Table Cell 1", "Table Cell 2", "Table Cell 3", "Table Cell 4", "Table Cell 5"]
[[body]]
row = ["Table Cell 1", "Table Cell 2", "Table Cell 3", "Table Cell 4", "Table Cell 5"]
[[body]]
row = ["Table Cell 1", "Table Cell 2", "Table Cell 3", "Table Cell 4", "Table Cell 5"]
[[foot]]
row = ["Table Footer 1", "Table Footer 2", "Table Footer 3", "Table Footer 4", "Table Footer 5"]
# [[colgroup]]
# span = 1
# class = "first-group"
# [[colgroup]]
# span = 2
# class = "second-group"
# [[colgroup]]
# span = 2
# class = "third-group"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment