Skip to content

Commit ea44926

Browse files
authored
Merge pull request #1683 from gethinode/templatev2
feat: add testimonials component with carousel functionality
2 parents 7c1e02e + 9571b93 commit ea44926

File tree

13 files changed

+524
-46
lines changed

13 files changed

+524
-46
lines changed

assets/js/testimonial.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function adjustCarouselHeight () {
2+
let max = 0
3+
document.querySelectorAll('.testimonials .carousel-item').forEach(container => {
4+
const clone = container.cloneNode(true)
5+
clone.style.display = 'block'
6+
clone.style.visibility = 'hidden'
7+
clone.style.height = 'auto'
8+
container.parentNode.appendChild(clone)
9+
if (clone.offsetHeight > max) max = clone.offsetHeight
10+
container.parentNode.removeChild(clone)
11+
})
12+
13+
document.querySelectorAll('.testimonials .carousel-item').forEach(container => {
14+
container.style.height = max + 'px'
15+
})
16+
}
17+
18+
window.addEventListener('load', () => { adjustCarouselHeight() })
19+
window.addEventListener('resize', () => { adjustCarouselHeight() })

component-library/bookshop.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@
1313
@import "modules/bookshop/components/releases/releases";
1414
@import "modules/bookshop/components/separator/separator";
1515
@import "modules/bookshop/components/team/team";
16+
@import "modules/bookshop/components/testimonials/testimonials";
1617
@import "modules/bookshop/components/video-message/video-message";
1718
@import "modules/bookshop/theme";
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Metadata about this component, to be used in the CMS
2+
spec:
3+
structures:
4+
- content_blocks
5+
label: Testimonials
6+
description: Testimonials section
7+
icon: build
8+
tags: []
9+
10+
# Defines the structure of this component, as well as the default values
11+
blueprint:
12+
background:
13+
color:
14+
subtle:
15+
card:
16+
color:
17+
subtle:
18+
testimonials:
19+
- logo:
20+
content:
21+
client:
22+
name:
23+
url:
24+
image:
25+
mode:
26+
link:
27+
carousel:
28+
cols:
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
{{/* Initialize arguments */}}
2+
{{ $args := partial "utilities/InitArgs.html" (dict "bookshop" "testimonials" "args" .)}}
3+
{{ if or $args.err $args.warnmsg }}
4+
{{ partial (cond $args.err "utilities/LogErr.html" "utilities/LogWarn.html") (dict
5+
"partial" "component-library/components/testimonials/testimonials.hugo.html"
6+
"warnid" "warn-invalid-arguments"
7+
"msg" "Invalid arguments"
8+
"details" ($args.errmsg | append $args.warnmsg)
9+
"file" page.File
10+
)}}
11+
{{ end }}
12+
13+
{{/* Initialize global arguments */}}
14+
{{- $style := partial "utilities/GetBackgroundStyle" (dict "background" .background) -}}
15+
{{- $breakpoint := partial "utilities/GetBreakpoint.html" -}}
16+
{{- $padding := partial "utilities/GetPadding.html" -}}
17+
18+
{{/* Main code */}}
19+
{{ if not $args.err }}
20+
{{ end }}
21+
22+
{{- $colGrid := "" -}}
23+
{{ $colGrid = printf "row-cols-%d" $args.cols }}
24+
{{- if eq $args.cols 1 }}
25+
{{ $colGrid = "row-cols-1" -}}
26+
{{- else if eq $args.cols 2 }}
27+
{{ $colGrid = printf "row-cols-1 row-cols-%s-2" $breakpoint.next }}
28+
{{- else if eq $args.cols 3 }}
29+
{{ $colGrid = printf "row-cols-1 row-cols-%s-3" $breakpoint.next }}
30+
{{- else if eq $args.cols 4 }}
31+
{{ $colGrid = printf "row-cols-1 row-cols-%s-2 row-cols-%s-4" $breakpoint.current $breakpoint.next }}
32+
{{- else if eq $args.cols 5 }}
33+
{{ $colGrid = printf "row-cols-1 row-cols-%s-3 row-cols-%s-5" $breakpoint.current $breakpoint.next }}
34+
{{ end -}}
35+
36+
{{ if and $args.carousel (gt (len $args.testimonials) 1) }}
37+
{{ $id := printf "testimonial-carousel-%s" (md5 (delimit (slice . now) "-")) }}
38+
<div id="{{ $id }}" class="carousel slide">
39+
<div class="carousel-indicators">
40+
{{ range $index, $item := .testimonials }}
41+
<button type="button"
42+
data-bs-target="#{{ $id }}"
43+
data-bs-slide-to="{{ $index }}"
44+
{{ if eq $index 0 }}class="active" aria-current="true"{{ end }}
45+
aria-label="Slide 1">
46+
</button>
47+
{{ end }}
48+
</div>
49+
<div class="carousel-inner">
50+
{{ range $index, $item := $args.testimonials }}
51+
<div class="carousel-item{{ if eq $index 0 }} active{{ end }}">
52+
{{ $cardStyle := partial "utilities/GetBackgroundStyle" (dict "background" $.card) }}
53+
{{ $cardStyle = print $cardStyle " testimonial-carousel-item" }}
54+
55+
{{ partial "assets/testimonial.html" (dict
56+
"page" page
57+
"content" $item.content
58+
"icon" $item.icon
59+
"logo" $item.logo
60+
"contact" (cond ($item.client | not | not) $item.client.contact "")
61+
"role" (cond ($item.client | not | not) $item.client.role "")
62+
"image" (cond ($item.client | not | not) $item.client.image "")
63+
"url" (cond ($item.client | not | not) $item.client.url "")
64+
"link" $item.link
65+
"show-controls" true
66+
"padding" $padding.x
67+
"class" $cardStyle
68+
)}}
69+
</div>
70+
{{ end}}
71+
</div>
72+
<button class="carousel-control-prev" type="button" data-bs-target="#{{ $id }}" data-bs-slide="prev">
73+
{{ partial "assets/icon.html" (dict "icon" "fas chevron-left fa-2xl") }}
74+
<span class="visually-hidden">{{ T "testimonialPrevious" }}</span>
75+
</button>
76+
<button class="carousel-control-next" type="button" data-bs-target="#{{ $id }}" data-bs-slide="next">
77+
{{ partial "assets/icon.html" (dict "icon" "fas chevron-right fa-2xl") }}
78+
<span class="visually-hidden">{{ T "testimonialNext" }}</span>
79+
</button>
80+
</div>
81+
{{ else }}
82+
<div class="container p-0">
83+
<div class="row {{ $colGrid }} g-3">
84+
{{ range .testimonials }}
85+
<div class="col">
86+
{{ partial "assets/testimonial.html" (dict
87+
"page" page
88+
"content" .content
89+
"icon" .icon
90+
"logo" .logo
91+
"contact" (cond (.client | not | not) .client.contact "")
92+
"role" (cond (.client | not | not) .client.role "")
93+
"image" (cond (.client | not | not) .client.image "")
94+
"url" (cond (.client | not | not) .client.url "")
95+
"link" .link
96+
"padding" $padding.x
97+
"class" (partial "utilities/GetBackgroundStyle" (dict "background" $.card))
98+
)}}
99+
</div>
100+
{{ end}}
101+
</div>
102+
</div>
103+
{{ end }}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
.testimonial-img {
2+
height: 10vw;
3+
width: 10vw;
4+
background-color: var(--#{$prefix}body-bg);
5+
}
6+
7+
.testimonial-logo {
8+
width: 20vw;
9+
}
10+
11+
@include media-breakpoint-up(md) {
12+
.testimonial-img {
13+
height: 5vw;
14+
width: 5vw;
15+
}
16+
17+
.testimonial-logo {
18+
width: 10vw;
19+
}
20+
}
21+
22+
section.testimonials {
23+
.carousel {
24+
width: 100%;
25+
}
26+
27+
.carousel-control-prev, .carousel-control-next {
28+
color: var(--bs-primary-text-emphasis);
29+
30+
&:hover,
31+
&:focus {
32+
color: var(--bs-primary);
33+
}
34+
}
35+
36+
.carousel-indicators button {
37+
background-color: $primary !important;
38+
}
39+
}

data/structures/testimonial.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
comment: Displays a single testimonial card.
2+
arguments:
3+
page:
4+
content:
5+
type: string
6+
optional: false
7+
comment: Quote to include in the testimonial.
8+
icon:
9+
logo:
10+
contact:
11+
role:
12+
image:
13+
url:
14+
padding:
15+
show-controls:
16+
type: bool
17+
optional: true
18+
default: false
19+
comment: ->
20+
Trigger to add margins for carousel controls. If set,
21+
the card includes a quote icon on the right-hand side too.
22+
class:
23+
link:
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
---
2+
_schema: default
3+
title: Testimonials
4+
description: Use the testimonials content block to display one or more client testimonials.
5+
icon: fa thumbs-up
6+
---
7+
8+
## Overview
9+
10+
The `testimonials` content block renders one or more client testimonials. You can render them as a carousel or as columns.
11+
12+
<!-- markdownlint-disable MD037 -->
13+
{{< example-bookshop lang="bookshop" >}}
14+
15+
```yml
16+
- _bookshop_name: testimonials
17+
card:
18+
color: primary
19+
subtle: true
20+
cols: 1
21+
carousel: true
22+
testimonials:
23+
- icon: fab linkedin
24+
content: >-
25+
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
26+
doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore
27+
veritatis et quasi architecto beatae vitae dicta sunt explicabo.
28+
client:
29+
contact: First Last
30+
role: CTO
31+
url: https://linkedin.com/
32+
image: /img/jake-nackos-IF9TK5Uy-KI-unsplash.png
33+
```
34+
35+
{{< /example-bookshop >}}
36+
<!-- markdownlint-enable MD037 -->
37+
38+
## Arguments
39+
40+
The content block supports the following arguments:
41+
42+
{{< args bookshop-testimonials >}}
43+
44+
## Examples
45+
46+
### Carousel
47+
48+
Set `carousel` to `true` to render a carousel of multiple testimonials.
49+
50+
<!-- markdownlint-disable MD037 -->
51+
{{< example-bookshop lang="bookshop" >}}
52+
53+
```yml
54+
- _bookshop_name: testimonials
55+
card:
56+
color: primary
57+
subtle: true
58+
cols: 1
59+
carousel: true
60+
testimonials:
61+
- icon: fab linkedin
62+
content: First testimonial.
63+
- icon: fab google
64+
content: Second testimonial.
65+
- icon: fab github
66+
content: Third testimonial.
67+
```
68+
69+
{{< /example-bookshop >}}
70+
<!-- markdownlint-enable MD037 -->
71+
72+
### Columns
73+
74+
Set `cols` to `3` to render three testimonials as columns.
75+
76+
<!-- markdownlint-disable MD037 -->
77+
{{< example-bookshop lang="bookshop" >}}
78+
79+
```yml
80+
- _bookshop_name: testimonials
81+
card:
82+
color: primary
83+
subtle: true
84+
cols: 3
85+
carousel: false
86+
testimonials:
87+
- icon: fab linkedin
88+
content: First testimonial.
89+
- icon: fab google
90+
content: Second testimonial.
91+
- icon: fab github
92+
content: Third testimonial.
93+
```
94+
95+
{{< /example-bookshop >}}
96+
<!-- markdownlint-enable MD037 -->

0 commit comments

Comments
 (0)