updated templater library; added accordion component

This commit is contained in:
2026-02-14 01:29:28 -07:00
parent 95ef64ce18
commit 6838d13c7a
11 changed files with 382 additions and 199 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ replace github.com/angelbeltran/templater v0.2.3 => ../../github.com/angelbeltra
require github.com/jackc/pgx/v5 v5.8.0 require github.com/jackc/pgx/v5 v5.8.0
require ( require (
github.com/angelbeltran/templater v0.2.3 github.com/angelbeltran/templater v0.3.0
github.com/coreos/go-oidc/v3 v3.17.0 github.com/coreos/go-oidc/v3 v3.17.0
github.com/gin-gonic/gin v1.11.0 github.com/gin-gonic/gin v1.11.0
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
+2
View File
@@ -9,6 +9,8 @@ github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/angelbeltran/concurry v0.0.0-20260109231127-8e2678d8928c h1:BIa061RHaIVP9TjpIQf0PldVpQmeln/2U1Cf2w8ALNI= github.com/angelbeltran/concurry v0.0.0-20260109231127-8e2678d8928c h1:BIa061RHaIVP9TjpIQf0PldVpQmeln/2U1Cf2w8ALNI=
github.com/angelbeltran/concurry v0.0.0-20260109231127-8e2678d8928c/go.mod h1:Aii6F8lZCJb8Ns0d1FH35bDxNoyiuvwXd5BYJroJnks= github.com/angelbeltran/concurry v0.0.0-20260109231127-8e2678d8928c/go.mod h1:Aii6F8lZCJb8Ns0d1FH35bDxNoyiuvwXd5BYJroJnks=
github.com/angelbeltran/templater v0.3.0 h1:LUWYu/uGonb43xumPgdRnx9cD8Sk4ySSdq8ll2U8yzI=
github.com/angelbeltran/templater v0.3.0/go.mod h1:ZA0T/ZmXxPi3gFjgp+RwEkcY9Q+JGyMStGw0c1jvgqA=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
+122 -7
View File
@@ -9,6 +9,7 @@
"Courier New", monospace; "Courier New", monospace;
--color-black: #000; --color-black: #000;
--color-white: #fff; --color-white: #fff;
--spacing: 0.25rem;
--text-sm: 0.875rem; --text-sm: 0.875rem;
--text-sm--line-height: calc(1.25 / 0.875); --text-sm--line-height: calc(1.25 / 0.875);
--text-lg: 1.125rem; --text-lg: 1.125rem;
@@ -187,6 +188,44 @@
.static { .static {
position: static; position: static;
} }
.sticky {
position: sticky;
}
.top-0 {
top: calc(var(--spacing) * 0);
}
.bottom-0 {
bottom: calc(var(--spacing) * 0);
}
.bottom-1 {
bottom: calc(var(--spacing) * 1);
}
.bottom-\[-1px\] {
bottom: -1px;
}
.grid-table-6 {
&:is(table) {
display: grid;
grid-template-columns: repeat(6, auto);
& > :is(thead, tbody, tfoot) {
grid-column-start: 1;
grid-column-end: -1;
display: grid;
grid-template-columns: subgrid;
& > tr {
grid-column-start: 1;
grid-column-end: -1;
display: grid;
grid-template-columns: subgrid;
& > th, & > td {
grid-column: span 1;
align-content: center;
text-align: center;
}
}
}
}
}
.col-2 { .col-2 {
grid-column: 2; grid-column: 2;
} }
@@ -238,9 +277,6 @@
.my-\[0\.5em\] { .my-\[0\.5em\] {
margin-block: 0.5em; margin-block: 0.5em;
} }
.my-\[1em\] {
margin-block: 1em;
}
.my-\[1rem\] { .my-\[1rem\] {
margin-block: 1rem; margin-block: 1rem;
} }
@@ -298,6 +334,15 @@
.h-fit { .h-fit {
height: fit-content; height: fit-content;
} }
.max-h-\[10em\] {
max-height: 10em;
}
.max-h-\[50em\] {
max-height: 50em;
}
.max-h-\[50vh\] {
max-height: 50vh;
}
.max-h-\[80vh\] { .max-h-\[80vh\] {
max-height: 80vh; max-height: 80vh;
} }
@@ -471,14 +516,17 @@
.p-\[1em\] { .p-\[1em\] {
padding: 1em; padding: 1em;
} }
.px-\[1em\] {
padding-inline: 1em;
}
.px-\[2em\] { .px-\[2em\] {
padding-inline: 2em; padding-inline: 2em;
} }
.py-\[0\.5em\] { .py-\[0\.5em\] {
padding-block: 0.5em; padding-block: 0.5em;
} }
.py-\[2em\] { .py-\[1em\] {
padding-block: 2em; padding-block: 1em;
} }
.pt-\[1em\] { .pt-\[1em\] {
padding-top: 1em; padding-top: 1em;
@@ -533,6 +581,16 @@
.underline { .underline {
text-decoration-line: underline; text-decoration-line: underline;
} }
.opacity-\[0\.8\] {
opacity: 0.8;
}
.outline-1 {
outline-style: var(--tw-outline-style);
outline-width: 1px;
}
.outline-\(--table-tfoot\) {
outline-color: var(--table-tfoot);
}
.filter { .filter {
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
} }
@@ -546,8 +604,12 @@
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration)); transition-duration: var(--tw-duration, var(--default-transition-duration));
} }
.group-open\:mb-\[1em\] { .outline-solid {
&:is(:where(.group):is([open], :popover-open, :open) *) { --tw-outline-style: solid;
outline-style: solid;
}
.not-open\:mb-\[1em\] {
&:not(*:is([open], :popover-open, :open)) {
margin-bottom: 1em; margin-bottom: 1em;
} }
} }
@@ -577,6 +639,11 @@
display: flex; display: flex;
} }
} }
.details-content\:max-w-full {
&::details-content {
max-width: 100%;
}
}
.details-content\:transform-\[translate\(0px\,-2em\)\] { .details-content\:transform-\[translate\(0px\,-2em\)\] {
&::details-content { &::details-content {
transform: translate(0px,-2em); transform: translate(0px,-2em);
@@ -597,6 +664,16 @@
border-color: transparent; border-color: transparent;
} }
} }
.details-content\:p-\[1em\] {
&::details-content {
padding: 1em;
}
}
.details-content\:px-\[1em\] {
&::details-content {
padding-inline: 1em;
}
}
.details-content\:opacity-\[0\] { .details-content\:opacity-\[0\] {
&::details-content { &::details-content {
opacity: 0; opacity: 0;
@@ -614,6 +691,18 @@
transition-duration: var(--tw-duration, var(--default-transition-duration)); transition-duration: var(--tw-duration, var(--default-transition-duration));
} }
} }
.after\:absolute {
&::after {
content: var(--tw-content);
position: absolute;
}
}
.after\:right-\[0\.5em\] {
&::after {
content: var(--tw-content);
right: 0.5em;
}
}
.after\:float-right { .after\:float-right {
&::after { &::after {
content: var(--tw-content); content: var(--tw-content);
@@ -654,11 +743,24 @@
} }
} }
} }
.group-open\/sync-group\:after\:content-\[\'-\'\] {
&:is(:where(.group\/sync-group):is([open], :popover-open, :open) *) {
&::after {
--tw-content: '-';
content: var(--tw-content);
}
}
}
.open\:grid { .open\:grid {
&:is([open], :popover-open, :open) { &:is([open], :popover-open, :open) {
display: grid; display: grid;
} }
} }
.open\:bg-card {
&:is([open], :popover-open, :open) {
background-color: var(--card);
}
}
.open\:details-content\:transform-\[translate\(0px\,0px\)\] { .open\:details-content\:transform-\[translate\(0px\,0px\)\] {
&:is([open], :popover-open, :open) { &:is([open], :popover-open, :open) {
&::details-content { &::details-content {
@@ -719,6 +821,13 @@
} }
} }
} }
.open\:details-content\:p-\[1em\] {
&:is([open], :popover-open, :open) {
&::details-content {
padding: 1em;
}
}
}
.open\:details-content\:opacity-\[1\] { .open\:details-content\:opacity-\[1\] {
&:is([open], :popover-open, :open) { &:is([open], :popover-open, :open) {
&::details-content { &::details-content {
@@ -1097,6 +1206,11 @@
syntax: "*"; syntax: "*";
inherits: false; inherits: false;
} }
@property --tw-outline-style {
syntax: "*";
inherits: false;
initial-value: solid;
}
@property --tw-blur { @property --tw-blur {
syntax: "*"; syntax: "*";
inherits: false; inherits: false;
@@ -1204,6 +1318,7 @@
*, ::before, ::after, ::backdrop { *, ::before, ::after, ::backdrop {
--tw-border-style: solid; --tw-border-style: solid;
--tw-font-weight: initial; --tw-font-weight: initial;
--tw-outline-style: solid;
--tw-blur: initial; --tw-blur: initial;
--tw-brightness: initial; --tw-brightness: initial;
--tw-contrast: initial; --tw-contrast: initial;
+2
View File
@@ -15,3 +15,5 @@
@import "./svg.css"; @import "./svg.css";
@import "./accessibility.css"; @import "./accessibility.css";
@import "./components.css"; @import "./components.css";
@source inline("group-open/sync-group:after:content-['-']");
@source inline("not-open:mb-[1em]");
+26
View File
@@ -0,0 +1,26 @@
@utility grid-table-* {
&:is(table) {
display: grid;
grid-template-columns: repeat(--value(integer), auto);
& > :is(thead, tbody, tfoot) {
grid-column-start: 1;
grid-column-end: -1;
display: grid;
grid-template-columns: subgrid;
& > tr {
grid-column-start: 1;
grid-column-end: -1;
display: grid;
grid-template-columns: subgrid;
& > th, & > td {
grid-column: span 1;
align-content: center;
text-align: center;
}
}
}
}
}
+98
View File
@@ -0,0 +1,98 @@
{{/* Templates: */}}
{{/* details-header */}}
{{/* details-body */}}
{{/* Props: */}}
{{/*
Open: bool
GroupName: for doing 'open' css state styles
Class, Style,
SummaryClass, SummaryStyle
*/}}
{{/* TODO: find a way to not have to hardcode the tailwind classes for the group-open styles */}}
{{/* TODO: rename this component to 'accordion' */}}
{{- $groupSuffix := "" }}
{{- if .GroupName }}
{{- $groupSuffix = printf "/%s" .GroupName }}
{{- end }}
<details
class="
group{{$groupSuffix}}
flex
flex-col
items-stretch
rounded-lg
open:bg-card
details-content:flex
details-content:flex-col
details-content:items-center
details-content:px-[1em]
open:details-content:p-[1em]
details-content:opacity-[0]
open:details-content:opacity-[1]
details-content:transform-[translate(0px,-2em)]
open:details-content:transform-[translate(0px,0px)]
details-content:transition-[opacity_transform]
{{.Class}}
"
style="{{.Style}}"
{{if .Open}}open{{end}}
hx-preserve
>
{{/* TODO: old border style - delete when sure
details-content:border-transparent
open:details-content:border-dotted
open:details-content:border-x-[0px]
open:details-content:border-x-transparent
open:details-content:border-b-[0px]
open:details-content:border-b-transparent
open:details-content:border-t-background
open:details-content:border-t-[0.25rem]
details-content:outline-transparent
*/}}
<summary
class="
flex
items-center
justify-center
gap-[1em]
w-full
p-[1em]
bg-accent
rounded-lg
list-none
cursor-pointer
after:content-['+']
after:absolute
after:right-[0.5em]
after:font-bold
after:text-[2em]
after:leading-[1em]
group-open{{$groupSuffix}}:after:content-['-']
{{.SummaryClass}}
"
style="contain: layout; {{.SummaryStyle}}"
>
{{ slot "accordion-header" }}
</summary>
{{ slot "accordion-body" }}
</details>
@@ -7,7 +7,8 @@
"HXSwap" "none" "HXSwap" "none"
"HXSelect" "#accounts-acct-id-inventory-sync-groups-mock-draft-table" "HXSelect" "#accounts-acct-id-inventory-sync-groups-mock-draft-table"
"ID" "sync-groups-mock-draft-table-add-listing-button" "ID" "sync-groups-mock-draft-table-add-listing-button"
"Class" "mt-[1em] mb-[1em]" "Class" ""
"Style" ""
"Text" "Add Listing" "Text" "Add Listing"
"_" ` "_" `
on click on click
@@ -2,17 +2,23 @@
{{- $acctID := .PathParams.acctID }} {{- $acctID := .PathParams.acctID }}
{{- $listings := .Accounts.GetMockSyncGroupListingDrafts $acctID }}
<table <table
id="accounts-acct-id-inventory-sync-groups-mock-draft-table" id="accounts-acct-id-inventory-sync-groups-mock-draft-table"
class="max-w-full overflow-x-auto" class="
max-w-full overflow-x-auto
grid-table-6
max-h-[50vh]
"
hx-get="{{ printf "/ui/accounts/%d/inventory/sync-groups/mock/draft/table" $acctID }}" hx-get="{{ printf "/ui/accounts/%d/inventory/sync-groups/mock/draft/table" $acctID }}"
hx-trigger="sse:{{ printf "accounts_%d_inventory_sync-groups_mock_draft" $acctID }},sse:{{ printf "accounts_%d_inventory_sync-groups_mock_draft_listings" $acctID }}" hx-trigger="sse:{{ printf "accounts_%d_inventory_sync-groups_mock_draft" $acctID }},sse:{{ printf "accounts_%d_inventory_sync-groups_mock_draft_listings" $acctID }}"
hx-select="#accounts-acct-id-inventory-sync-groups-mock-draft-table" hx-select="#accounts-acct-id-inventory-sync-groups-mock-draft-table"
hx-swap="morph:outerHTML" hx-swap="morph:outerHTML"
> >
<thead> <thead class="sticky top-0">
<tr> <tr>
<th> <th>
Shop Shop
@@ -58,14 +64,14 @@
send setDisabled(disabled: not allRowsFilledOut or numRows < 2) to #create-mock-sync-group-button send setDisabled(disabled: not allRowsFilledOut or numRows < 2) to #create-mock-sync-group-button
" "
> >
{{- $listings := .Accounts.GetMockSyncGroupListingDrafts $acctID }}
{{- range $listing := $listings }} {{- range $listing := $listings }}
{{- component (printf "accounts/%d/inventory/sync-groups/mock/draft/listings/%d" $acctID $listing.OrderIndex) {{- component (printf "accounts/%d/inventory/sync-groups/mock/draft/listings/%d" $acctID $listing.OrderIndex)
"Listings" $listings "Listings" $listings
}} }}
{{- end }} {{- end }}
</tbody> </tbody>
<tfoot> {{- if gt (len $listings) 5 }}
<tfoot class="sticky bottom-0 outline-1 outline-(--table-tfoot)">
<tr> <tr>
<th> <th>
Shop Shop
@@ -87,6 +93,7 @@
</th> </th>
</tr> </tr>
</tfoot> </tfoot>
{{- end }}
</table> </table>
{{/* {{/*
@@ -18,8 +18,9 @@
{{ component "button" {{ component "button"
"ID" "create-mock-sync-group-button" "ID" "create-mock-sync-group-button"
"Class" "mt-[1em] mb-[1em]"
"Text" "Save Sync Group" "Text" "Save Sync Group"
"Class" ""
"Style" ""
"Disabled" (or (not $enoughListings) (not $allCompleted)) "Disabled" (or (not $enoughListings) (not $allCompleted))
"_" ` "_" `
on setDisabled(disabled) on setDisabled(disabled)
+1 -1
View File
@@ -14,7 +14,7 @@
disabled:bg-accent-secondary disabled:bg-accent-secondary
disabled:cursor-not-allowed disabled:cursor-not-allowed
disabled:no-underline disabled:no-underline
{{.Class}} {{if .Class}}{{.Class}}{{end}}
" "
{{- if .ID }} {{- if .ID }}
id="{{.ID}}" id="{{.ID}}"
@@ -6,66 +6,14 @@
{{- define "title" }} Manage Mock Inventory &sdot; Inventory++ {{ end }} {{- define "title" }} Manage Mock Inventory &sdot; Inventory++ {{ end }}
{{- define "header-accordion-header" }}
<section
id="new-mock-sync-group"
class="py-[2em] flex flex-col items-center"
hx-swap-oob="true"
>
<details
class="
group
flex
flex-col
items-center
{{/* TODO: make custom class for all this */}}
details-content:opacity-[0]
open:details-content:opacity-[1]
details-content:transform-[translate(0px,-2em)]
open:details-content:transform-[translate(0px,0px)]
details-content:border-transparent
open:details-content:border-dotted
open:details-content:border-x-[0px]
open:details-content:border-x-transparent
open:details-content:border-b-[0px]
open:details-content:border-b-transparent
open:details-content:border-t-background
open:details-content:border-t-[0.25rem]
details-content:outline-transparent
details-content:transition-[opacity_transform]
"
hx-preserve
>
<summary
class="
flex
items-center
gap-[1em]
list-none
p-[1em]
mb-[1em]
cursor-pointer
bg-accent
rounded-lg
after:content-['+']
group-open:after:content-['-']
after:font-bold
after:text-[2em]
after:leading-[1em]
"
>
<h2 class="inline-block"> <h2 class="inline-block">
New Sync Group New Sync Group
</h2> </h2>
</summary> {{- end }}
{{- define "header-accordion-body" }}
{{- $acctID := .Identity.Account.AccountID }}
{{ component (printf "accounts/%d/inventory/sync-groups/mock/draft/table" $acctID) }} {{ component (printf "accounts/%d/inventory/sync-groups/mock/draft/table" $acctID) }}
<form <form
@@ -82,86 +30,22 @@
/> />
</label> </label>
<div class="flex justify-center gap-[0.5em]"> <div class="flex justify-center gap-[0.5em] mt-[1em]">
{{ component (printf "accounts/%d/inventory/sync-groups/mock/draft/table/add-listing-button" $acctID) }} {{ component (printf "accounts/%d/inventory/sync-groups/mock/draft/table/add-listing-button" $acctID) }}
{{ component (printf "accounts/%d/inventory/sync-groups/mock/draft/table/save-sync-group-button" $acctID) }} {{ component (printf "accounts/%d/inventory/sync-groups/mock/draft/table/save-sync-group-button" $acctID) }}
</div> </div>
</form> </form>
</details> {{- end }}
{{- define "sync-group-accordion-header" }}
{{- $dot := . }} <h3 class="text-center">
<ul {{ .Group.Name }}
id="existing-mock-sync-groups-list"
class="my-[1em] flex flex-col gap-[1em]"
hx-get="{{ printf "/ui/accounts/%d/inventory/mock" $acctID }}"
hx-select="#existing-mock-sync-groups-list"
hx-swap="morph"
hx-trigger="{{ printf "sse:accounts_%d_inventory_sync-groups_mock,sse:accounts_%d_inventory_mock" $acctID }}"
>
{{- range $grp := .Accounts.ListMockSyncGroups $acctID }}
<li
id="sync-group-{{$grp.SyncGroupID}}"
class="bg-card rounded-lg mx-[1em] p-[1em]"
>
<details
class="
group
flex
flex-col
items-center
details-content:flex
details-content:flex-col
details-content:items-center
{{/* TODO: make custom class for all this */}}
details-content:opacity-[0]
open:details-content:opacity-[1]
details-content:transform-[translate(0px,-2em)]
open:details-content:transform-[translate(0px,0px)]
details-content:border-transparent
open:details-content:border-dotted
open:details-content:border-x-[0px]
open:details-content:border-x-transparent
open:details-content:border-b-[0px]
open:details-content:border-b-transparent
open:details-content:border-t-background
open:details-content:border-t-[0.25rem]
details-content:outline-transparent
details-content:transition-[opacity_transform]
"
>
<summary
class="
flex
items-center
gap-[1em]
list-none
p-[1em]
group-open:mb-[1em]
cursor-pointer
bg-accent
rounded-lg
after:content-['+']
group-open:after:content-['-']
after:font-bold
after:text-[2em]
after:leading-[1em]
"
>
<h3>
Name: {{ $grp.Name }}
</h3> </h3>
</summary> {{- end }}
<table class="mt-[1em]"> {{- define "sync-group-accordion-body" }}
{{- $acctID := .Identity.Account.AccountID }}
<table>
<thead> <thead>
<tr> <tr>
<th> <th>
@@ -179,7 +63,8 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{{- range $listing := $grp.Listings }} {{- $dot := . }}
{{- range $listing := .Group.Listings }}
<tr> <tr>
{{- $val := $dot.Accounts.GetMockListing $acctID $listing.Platform $listing.ShopID $listing.ListingID }} {{- $val := $dot.Accounts.GetMockListing $acctID $listing.Platform $listing.ShopID $listing.ListingID }}
<td> <td>
@@ -202,11 +87,57 @@
{{- component "button" {{- component "button"
"Class" "mt-[1em]" "Class" "mt-[1em]"
"Text" "Delete Group" "Text" "Delete Group"
"HXDelete" (printf "/api/accounts/%d/inventory/sync-groups/mock/%d" $acctID $grp.SyncGroupID) "HXDelete" (printf "/api/accounts/%d/inventory/sync-groups/mock/%d" $acctID .Group.SyncGroupID)
"HXSwap" "none" "HXSwap" "none"
}} }}
</details> {{- end }}
<section
id="new-mock-sync-group"
class="
flex flex-col items-stretch
py-[1em]
"
hx-swap-oob="true"
>
{{ component "accordion"
"Open" true
"Class" `
mx-[1em]
mb-[1em]
`
"#accordion-header" "header-accordion-header"
"#accordion-body" "header-accordion-body"
}}
<ul
id="existing-mock-sync-groups-list"
class="flex flex-col gap-[1em]"
hx-get="{{ printf "/ui/accounts/%d/inventory/mock" $acctID }}"
hx-select="#existing-mock-sync-groups-list"
hx-swap="morph"
hx-trigger="{{ printf "sse:accounts_%d_inventory_sync-groups_mock,sse:accounts_%d_inventory_mock" $acctID $acctID }}"
>
{{- range $grp := .Accounts.ListMockSyncGroups $acctID }}
<li
id="sync-group-{{$grp.SyncGroupID}}"
class="
mx-[1em]
"
>
{{ component "accordion"
"GroupName" "sync-group"
"Group" $grp
"#accordion-header" "sync-group-accordion-header"
"#accordion-body" "sync-group-accordion-body"
}}
</li> </li>
{{- end }} {{- end }}
</ul> </ul>
</section> </section>