Skip to main content

Implementation

Atomic components​

Main title​

product/title.hbs

<h2 class="product-title">{{text}}</h2>

This component will come with below css style. This block of code should be included in default.css

.product-title {
font-size: 90pt;
font-weight: 500;
margin: 0;
text-transform: uppercase;
font-family: "D-DINCondensed";
}

Product code​

product/code-title.hbs

<h3 class="product-code-title">{{text}}</h3>

CSS styles:

.product-code-title {
font-size: 30pt;
color: #58a1be;
line-height: 1.2;
margin: 0;
font-weight: 500;
font-family: "D-DIN-Bold";
}

Product description​

product/description.hbs

<div class="product-description">{{text}}</div>

CSS styles:

.product-description {
width: 100%;
font-family: "RobotoLight";
font-size: 30pt;
line-height: 45pt;
}

Pillow image​

image/basic.hbs

<div class="image-basic">
<img class="image-basic__image"
src="{{> image/replacement text fallback=(either fallback './images/ROBO-000-0003.png')}}"
alt="pillow 1"
>
</div>

CSS styles:

.image-basic {
width: 600pt;
height: 600pt;
display: flex;
justify-content: center;
align-items: center;
}

.image-basic__image {
width: 600pt;
image-rendering: pixelated;
}

This component has default fallback value is ./images/ROBO-000-0003.png. You can change it by putting another value when use this component: E.g.

{{> image/basic text=image1 fallback='./images/ROBO-000-0004.png'}}

Image replacement​

image/replacement.hbs

{{when
(matches this "^https?:.*")
(proxyUrl this)
(when (contains this ".") this fallback)
}}

In this helper, it will check input string

  • If the string contains http or https, we will use proxyUrl helper to process the image url.
  • Else if string contains ., just return it as it is
  • Else use the fallback

Product info in trapezium sharp​

product/info-trapezium.hbs

<div class="product-info-trapezium">
<h1 class="product-info-trapezium__title">{{title}}</h1>
<div class="product-info-trapezium__description">
{{description}}
</div>
</div>

CSS styles:

.product-info-trapezium {
position: relative;
width: 50%;
height: 100%;
padding-left: 84pt;
}

.product-info-trapezium::before {
content: "";
position: absolute;
top: 0;
left: -50pt; /* adjust for skew width */
width: 100%;
height: 100%;
background-color: #58a1be;
transform: skewX(-20deg); /* fake the polygon shape */
transform-origin: top left;
z-index: -1;
}

.product-info-trapezium__title {
font-family: "D-DINCondensed";
text-transform: uppercase;
font-size: 90pt;
margin-bottom: 0;
padding-top: 12pt;
color: white;
}

.product-info-trapezium__description {
font-family: "D-DIN-Bold";
font-size: 32pt;
margin-top: 36pt;
line-height: 54pt;
text-align: left;
color: white;
width: 520pt;
}

Extract data helper​

item/content.hbs

{{#each this.item}}{{#if (eq key ../key)}}{{content}}{{/if}}{{/each}}

This helper will read the input data and find the matched item by using input key.

Page level components​

Page 1​

pillow/one-detail.hbs

<div class="pillow-one-detail">
<div class="pillow-one-detail__image">
{{> image/basic text=image1}}
</div>
<div class="pillow-one-detail__content">
{{> product/title text=titleText}}
{{> product/code-title text=codeText}}
<div class="pillow-one-detail__descriptionWrapper">
{{> product/description text=descriptionText}}
</div>
</div>
</div>

CSS styles:

.pillow-one-detail {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
padding-right: 50pt;
padding-left: 10pt;
}

.pillow-one-detail__image {
width: 600pt;
height: 600pt;
}

.pillow-one-detail__content {
display: flex;
flex-direction: column;
align-items: center;
gap: 10pt;
}

.pillow-one-detail__descriptionWrapper {
position: relative;
width: 620pt;
text-align: center;
}

Page 2​

pillow/two-detail.hbs

<div class="pillow-two-detail">
<div class="pillow-two-detail__content">
{{> product/title text=titleText}}
{{> product/code-title text=codeText}}
<div class="pillow-two-detail__descriptionWrapper">
{{> product/description text=descriptionText}}
</div>
</div>
<div class="pillow-two-detail__image">
<div class="pillow-two-detail__imageWrapper">
{{> image/basic text=image1}}
</div>
</div>
</div>

CSS styles:

.pillow-two-detail {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
padding: 0 50pt;
}

.pillow-two-detail__image {
width: 600pt;
height: 600pt;
}

.pillow-two-detail__imageWrapper {
width: 600pt;
height: 600pt;
display: flex;
justify-content: center;
align-items: center;
transform: rotate(-12deg) translateX(-37.5pt) translateY(157.5pt) scale(1.25);
}

.pillow-two-detail__content {
display: flex;
flex-direction: column;
align-items: flex-start;
padding-left: 40pt;
gap: 20pt;
}

.pillow-two-detail__descriptionWrapper {
position: relative;
width: 620pt;
}

Page 3​

pillow/three-detail.hbs

<div class="pillow-three-detail">
{{> product/info-trapezium title=title description=description}}
<div class="pillow-three-detail__imageWrapper">
<div class="pillow-three-detail__imageCaption">
<div class="pillow-three-detail__imageCaptionText">
{{imageCaption}}
</div>
<div class="pillow-three-detail__imageArrow">
<div class="pillow-three-detail__arrowLine"></div>
<div class="pillow-three-detail__arrowDot"></div>
</div>
</div>
<div class="pillow-three-detail__image">
{{> image/basic text=(imageReplacement image './assets/images/ROBO-000-0004.png')}}
</div>
</div>
</div>

CSS styles:

.pillow-three-detail {
display: flex;
position: relative;
width: 100%;
justify-content: space-between;
}

.pillow-three-detail__imageWrapper {
display: flex;
position: relative;
}

.pillow-three-detail__imageCaption {
position: absolute;
bottom: 75pt;
left: -215pt;
display: flex;
}

.pillow-three-detail__imageCaptionText {
font-family: "D-DIN";
text-transform: capitalize;
font-size: 30pt;
line-height: 52.5pt;
width: 190pt;
}

.pillow-three-detail__imageArrow {
display: flex;
align-items: center;
}

.pillow-three-detail__arrowLine {
width: 7rem;
border: 1.5pt solid black;
}

.pillow-three-detail__arrowDot {
width: 11.25pt;
height: 11.25pt;
border-radius: 50%;
background-color: black;
}

Page 4​

pillow/four-detail.hbs

<div class="pillow-four-detail">
<div class="pillow-four-detail__backgroundWrapper">
<img class="pillow-four-detail__backgroundImage" src="./assets/images/Lifestyle_4.jpg" alt="pillow-four-detail-background">
</div>
<div class="pillow-four-detail__overlay"></div>
<div class="pillow-four-detail__content">
{{> product/title text=title}}
{{> product/description text=description}}
</div>
<div class="pillow-four-detail__imageSection">
<div class="pillow-four-detail__imageCircleWrapper">
<div class="pillow-four-detail__imageContainer">
<img class="pillow-four-detail__image" src="{{imageReplacement image './assets/images/ROBO-000-0004.png'}}" alt="pillow-four-detail-image">
</div>
<div class="pillow-four-detail__imageCaption">
{{> product/code-title text=code}}
</div>
</div>
</div>
</div>

In this component, we use CSS styles in page component to overwrite default style of product-description component to match with page design.

CSS styles:

.pillow-four-detail {
display: flex;
position: relative;
width: 100%;
justify-content: space-between;
align-items: center;
}

.pillow-four-detail__backgroundWrapper {
width: 100%;
height: 100%;
position: absolute;
}

.pillow-four-detail__backgroundImage {
object-fit: cover;
width: 100%;
height: 100%;
}

.pillow-four-detail__overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(
0,
0,
0,
0.75
); /* dark overlay simulates brightness(25%) */
}

.pillow-four-detail__content {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
gap: 5pt;
padding-left: 90pt;
position: relative;
width: 60%;
color: #ffffff;
z-index: 2;
}

/* Overwrite CSS of product-description component */
.pillow-four-detail__content > .product-description {
font-family: "D-DIN-Bold";
font-size: 35pt;
margin-top: 36pt;
line-height: 54pt;
text-align: left;
color: white;
}

.pillow-four-detail__imageSection {
display: flex;
position: relative;
width: 420pt;
height: 420pt;
margin-right: 60pt;
z-index: 2;
}

.pillow-four-detail__imageCircleWrapper {
position: relative;
width: 420pt;
height: 420pt;
background-color: white;
border-radius: 50%;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

.pillow-four-detail__imageContainer {
display: flex;
justify-content: center;
align-items: center;
width: 70%;
height: 70%;
}

.pillow-four-detail__image {
object-fit: contain;
width: 100%;
height: 100%;
}

.pillow-four-detail__imageCaption {
display: flex;
justify-content: center;
align-items: center;
}

Page 5​

pillow/five-detail.hbs

<div class="pillow-five-detail">
<div class="pillow-five-detail__content">
<div class="pillow-five-detail__titleWrapper">
{{> product/title text=title}}
</div>
<div class="pillow-five-detail__descriptionWrapper">
{{> product/description text=description}}
</div>
</div>
<div class="pillow-five-detail__image">
{{> image/basic text=image}}
</div>
</div>

CSS styles:

.pillow-five-detail {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 50pt;
width: 100%;
}

.pillow-five-detail__content {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 10pt;
padding-left: 40pt;
}

.pillow-five-detail__titleWrapper {
width: 600pt;
}

.pillow-five-detail__descriptionWrapper {
width: 660pt;
}

.pillow-five-detail__image {
display: flex;
position: relative;
}

Page 6​

pillow/six-detail.hbs

<div class="pillow-six-detail">
{{> product/description text=description}}
</div>

In this component, we use CSS styles in page component to overwrite default style of product-description component to match with page design.

CSS styles:

.pillow-six-detail {
display: flex;
width: 100%;
align-items: flex-start;
font-family: "D-DIN-Bold";
}

/* Overwrite CSS of product-description component */
.pillow-six-detail > .product-description {
padding: 90pt;
background-color: #58a1be;
font-family: "D-DIN-Bold";
font-size: 30pt;
line-height: 42pt;
text-align: left;
color: white;
}

Main entry file​

default.hbs

<html lang="{{lang}}">
<head>
<title>My Pillows</title>
<meta name="author" content="John Smith"/>
<meta name="subject" content="An interesting book about pillow"/>
<meta name="description" content="A book about pillow"/>
<meta name="keywords" content="cushion, sleeping, relaxing"/>
<meta name="date" content="{{now format="yyyy'-'MM'-'dd" }}"/>
<meta name="dcterms.created" content="{{created}}"/>
</head>
<body>
{{#each item}}
{{#if (eq @index 0)}}
<div class="product-container">
{{> pillow/one-detail
titleText=(itemContent this.item "text1")
codeText=(itemContent this.item "text2")
descriptionText=(itemContent this.item "text3")
image1=(itemContent this.item "image1")
}}
</div>
{{/if}}
{{#if (eq @index 1)}}
<div class="product-container">
{{> pillow/two-detail
titleText=(itemContent this.item "text1")
codeText=(itemContent this.item "text2")
descriptionText=(itemContent this.item "text3")
image1=(itemContent this.item "image1")
}}
</div>
{{/if}}
{{#if (eq @index 2)}}
<div class="product-container">
{{> pillow/three-detail
title=(itemContent this.item "text1")
description=(itemContent this.item "text2")
imageCaption=(itemContent this.item "text3")
image1=(itemContent this.item "image1")
}}
</div>
{{/if}}
{{#if (eq @index 3)}}
<div class="product-container">
{{> pillow/four-detail
title=(itemContent this.item "text1")
description=(itemContent this.item "text3")
image=(itemContent this.item "image1")
code=(itemContent this.item "text2")
}}
</div>
{{/if}}
{{#if (eq @index 4)}}
<div class="product-container">
{{> pillow/five-detail
title=(itemContent this.item "text1")
description=(itemContent this.item "text2")
image=(itemContent this.item "image1")
}}
</div>
{{/if}}
{{#if (eq @index 5)}}
<div class="product-container">
{{> pillow/six-detail
description=(itemContent this.item "text1")
}}
</div>
{{/if}}
{{/each}}
</body>
</html>

In this conponent we can include global styles, fonts registering, pageCSS, etc.

CSS styles:

@font-face {
font-family: "D-DINCondensed";
src: url("./fonts/D-DINCondensed-Bold.otf") format("opentype");
font-weight: bold;
}
@font-face {
font-family: "D-DIN-Bold";
src: url("./fonts/D-DIN-Bold.otf") format("opentype");
font-weight: bold;
}
@font-face {
font-family: "D-DIN";
src: url("./fonts/D-DIN.otf") format("opentype");
font-weight: normal;
}
@font-face {
font-family: "Poppins";
src: url("./fonts/Poppins-SemiBold.ttf") format("truetype");
}
@font-face {
font-family: "Roboto";
src: url("./fonts/Roboto-Regular.ttf") format("truetype");
font-weight: normal;
}

@font-face {
font-family: "RobotoLight";
src: url("./fonts/Roboto-Light.ttf") format("truetype");
}

@page {
size: 1464pt 600pt;
margin: 0;
}

@media print {
body {
margin: 0;
padding: 0;
}
.product-container {
margin: 0;
padding: 0;
page-break-after: always;
}
}

.product-container {
display: flex;
width: 1464pt;
height: 600pt;
}

Final output​

To finalize our template, we collect all the *.hbs files and also merge all css styles of components into one file default.css.

This is list of output file we should have:

└── template/
├── image/
│ ├── basic.hbs
│ └── replacement.hbs
├── item/
│ └── content.hbs
├── product/
│ ├── title.hbs
│ ├── code-title.hbs
│ ├── description.hbs
│ └── info-trapezium.hbs
├── pillow/
│ ├── one-detail.hbs
│ ├── two-detail.hbs
│ ├── three-detail.hbs
│ ├── four-detail.hbs
│ ├── five-detail.hbs
│ └── six-detail.hbs
├── default.hbs
└── default.css