dmitriyzhuk / store-framework Goto Github PK
View Code? Open in Web Editor NEWHome Page: https://lab.github.com/vtex-trainings/store-framework
Home Page: https://lab.github.com/vtex-trainings/store-framework
In addition to css, which we looked at previously, Store Framework offers another type of design customization, based on style.json
.
Every Store Framework block benefit from the same semantic styles definitions, based on Tachyons.
In practice, it means that instead of having to change all button backgrounds to use color that you want, you just need to redefine the color of an action-primary
background
. Customizations using style.json
tend a very big impact through css, since the store's visual identity across every page is usually maintained that way, without requiring a lot of changes. Therefore, use this tool whenever possible, thus avoiding unnecessary css overhead.
style.json
styles/configs/style.json
can be confusing at first, because it contains all the style definitions that every Store Framework visual block uses. However, inspecting browser elements is usually a good way to identify which styles to change. For example, right mouse click on any store button and select inspect.
Looking at the side bar that opened in Chrome, we notice a couple of definitions, one of them being the button background color (#0f3e99):
In addition, if you inspect while hovering, you'll notice the hover color (#072c75):
If we search the occurrences of both colors in style.json
, we uncover that the colors we inspected are actually used as action-primary
for the hover-background
and background
, for example. This gives us a better idea of where this definition may appear again.
The process to discovering text semantics with editable fields is the same as the above, we can search for attributes such as font size, weight and family. When inspecting a level 1 heading for example, we notice that its size is 3 rem.
style.json
, replace every color occurrence that you find, substituting:The expected result is as it follows:
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
The Slider Layout, just as the Flex Layout, is a flexible way of creating a new block based on other blocks, using children
. It allows slider from other blocks to be created, such as info-card
and even flex-layout
, for example.
Let's use the Slider Layout to transform a couple of info-cards into a slide.
Looking at the documentation, we notice that we can use any block array as children
, just as with Flex Layout.
Below, you have an implementation example of a slider-layout with two info-card
:
"slider-layout#home": {
"children": ["info-card#1", "info-card#2"],
"props": {
"autoplay": {
"timeout": 5000,
"stopOnHover": false
}
}
},
"info-card#1": {
"props": {
"imageUrl": "https://images.unsplash.com/photo-1524185962737-ea7c028a12cd?ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
"isFullModeStyle": true,
"headline": "Black Friday",
"callToActionText": "Subscribe",
"textPosition": "center"
}
},
"info-card#2": {
"props": {
"imageUrl": "https://images.unsplash.com/photo-1524185962737-ea7c028a12cd?ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
"isFullModeStyle": true,
"headline": "Black Friday",
"callToActionText": "Subscribe",
"textPosition": "center"
}
}
In this activity, we will create a brand slider for our site:
In home.jsonc
, declare the slider-layout#home
block to the store.home
template.
Create a file called slider-layout.jsonc
in the /store/blocks
folder;
In this file, based on the above-mentioned code, replace the declared info-card
as slider-layout#home
's children and add 6 image
image components as children. As format, use image#brand1
, image#brand2
(...) image#brand6
to declare the components;
Declare a specific src
prop for each defined image#brand
. Use the URLs below for each:
https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square1.png
https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square2.png
https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square3.png
https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square4.png
https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square5.png
https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square6.png
Lastly, you have to use the autoplay
property in the slider-layout#home
block. Make the slider occur automatically every 7 seconds and also make it stop when the user hovers over the slide.
ℹ️ Remember to go through the Slider Layout and Image documentation if you have any questions during the activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
Having already configured and implemented the header, let's now add it to the Menu. Configuring the Menu is an important step in building your theme, since it's the block that's responsible for the user's navigation in your store. Because of its function and relevance, the Menu possesses a complex hierarchical structure, which involves menu items, submenus and, based on the latter, any Store Framework block (such as other Menus e Menu Items). Below we can see an image highlighting the Menu block's structure in practice:
When compared to some of the other blocks, the Menu's configuration may seem more difficult due to its structure of menus, menu items and submenus. However the Menu does not necessarily need to be configured according to the most complex scenario. Below, we can check a basic implementation example for the block, containing just the following 3 Menu Items:
{
"[email protected]:menu#categories": {
"children": [
"menu-item#major-appliances",
"menu-item#small-appliances",
"menu-item#electronics"
],
"props":{
"orientation": "horizontal"
}
}
},
This activity will help us understand more about configuring the Menu, in addition to its existing hierarchy based on building Menu Items and Submenus.
In header.jsonc
, add header-row#menu
as the last item on the header-layout.desktop
block's child list (configured during the previous activity), so that the Menu can be rendered by the store's Header;
Copy and paste the code below to declare the header-row#menu
block:
"header-row#menu": {
"children": [
"header-spacer",
"[email protected]:menu#categories",
"header-spacer"
]
},
We also need to deal with the layout Menu for other devices, such as mobile. Therefore, add the drawer
as the header-row#main-mobile
block's first child;
Copy the code in the menu.jsonc
code to horizontally render the 3 main Menu items:
{
"[email protected]:menu#categories": {
"children": [
"menu-item#major-appliances",
"menu-item#small-appliances",
"menu-item#electronics"
],
"props":{
"orientation": "horizontal"
}
},
As we've seen in the introduction, a Menu Item can allow the configuration of a Submenu which in turn can have another Menu with its own Menu Items. Therefore, create a Submenu for Major Appliances, still in menu.jsonc
, according to the example below:
"[email protected]:submenu#major":{
"children":[
"[email protected]:menu#major"
]
},
Following the format established by the [email protected]:menu#categories\
block, build a secondary Major Appliances Menu, declared in the last step in menu.jsonc
. You must set the orientation
prop value to vertical
and configure the following Menu Items in the block's children list: menu-item#refrigerators
, menu-item#ovens
and menu-item#washers
;
In addition, create a Small Appliances submenu:
"[email protected]:submenu#small":{
"children":[
"[email protected]:menu#small"
]
},
Now build the Small Appliances secondary menu in menu.jsonc
. As with the Major Appliances, you must set the orientation
prop value to vertical
and configure the following Menu Items in the block children list: menu-item#mixers
, menu-item#toasters
and menu-item#coffee
;
Based on the previous steps, do the same with Electronics: create your Submenu ([email protected]:submenu#electronics
) and secondary Menu. Thereafter, build the latter with the same prop value (vertical
) and configure the following Menu Items in the block's children list: menu-item#cameras
, menu-item#laptops
and menu-item#tvs
.
Expected result:
ℹ️ Remember to access the Menu's documentation if your have any questions during the activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
Tab Layout is layout structuring paradigm created in Store Framework to allow the creation of layouts with tabs.
We have the following two containers in this paradigm: tab-list
and tab-content
. Each of these containers contains the items that it's comprised of. In tab-list
, we have tab-list.item
, whereas in tab-content
, we have tab-content.item
, respectively.
We'll look at a tab layout implementation example below.
First, you need to declare the tab-layout
block in the desired template:
{
"store.custom#about-us": {
"blocks": [
...
"tab-layout"
]
}
}
Then, you need to declare a tab-list
and a tab-content
as tab-layout
's children:
...
"tab-layout": {
"children": [
"tab-list",
"tab-content"
]
}
Having done this, these two containers are components of our tab-layout
. The next step is to declare tab-list.item
and tab-content.item
as tab-list
's and tab-content
's children:
...
"tab-list": {
"children": [
"tab-list.item#1",
"tab-list.item#2"
]
}
...
"tab-content": {
"children": [
"tab-content.item#1",
"tab-content.item#2"
]
}
In the next step, we'll declare the tab-list.item
properties. The code below creates a tab interface similar to the image below:
The tabId
property is very important as it's the key that connect a tab-list.item
button with a tab-content.item
.
...
"tab-list.item#1": {
"props": {
"tabId": "majorAppliances",
"label": "Major Appliances",
"defaultActiveTab": true
}
},
"tab-list.item#2": {
"props": {
"tabId": "electronics",
"label": "Electronics"
}
}
Now, let's declare the children and props pertaining to tab-content.item
.
In the child array, you can include several blocks such as rich-text
, info-card
, image
, flex-layout
and etc.
In the tabId
prop, you need to include the same ids that were declared in tab-list.item
for the link between the tab and content to function properly.
...
"tab-content.item#1": {
"children": [
"rich-text#1"
],
"props": {
"tabId": "majorAppliances"
}
},
"tab-content.item#2": {
"children": [
"rich-text#2"
],
"props": {
"tabId": "electronics"
}
}
Lastly, you must declare your content's proprieties. In our example, we just placed a rich-text
in each tab-content.item
:
"rich-text#1": {
"props": {
"text": "Texto para Major Appliances",
"textPosition": "CENTER",
"font": "t-heading-3"
}
},
"rich-text#2": {
"props": {
"text": "Texto para Electronics",
"textPosition": "CENTER",
"font": "t-heading-3"
}
}
In this activity, we will create the simple structure of a tab layout, as shown below. Thereafter, we will add some content to give our page a custom style.
In the previously created about-us.jsonc
, add a tab-layout#home
to the store.custom#about-us
template;
Declare the tab-layout#home
block and add tab-list#home
and tab-content#home
as its children;
Declare tab-list#home
and add tab-list.item#home1
and tab-list.item#home2
as its children;
Declare the props pertaining to tab-list.item#home1
so that the interface displays "Major Appliances". (Tip: Do not forget to include tabId
= "majorAppliances"
as well as the property defaultActiveTab
= true
to the props);
Declare tab-list.item#home2
's props so that the interface displays "Electronics". (Tip: Don't forget to include tabId
= "electronics"
to the props);
Now, let's move on to the content. Declare tab-content#home
in your theme and add tab-content.item#home1
and tab-content.item#home2
as children;
For each tab-content.item
, declare just one rich-text
as child (for example, rich-text#home1
and rich-text#home2
);
Thereafter, include a tabId
prop for each tab-content.item
to create a link between the previously created tab-list
and tab-content
;
Lastly, add the rich-text
and declare its props according to the code below:
"rich-text#home1": {
"props": {
"text": "Área do conteúdo da tab-list.item com tabId = majorAppliances",
"textPosition": "CENTER",
"font": "t-heading-3"
}
},
"rich-text#home2": {
"props": {
"text": "Área do conteúdo da tab-list.item com tabId = electronics",
"textPosition": "CENTER",
"font": "t-heading-3"
}
}
ℹ️ Remember to access the Tab Layout and Rich Text documentation for any questions during the activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
In this step, we will learn how to create a component that is commonly seen as unimportant, but which is critical to providing a good user experience: the footer.
Few users scroll until the footer. However, the ones that do make it that far may be looking for information that is usually housed in this block, such as links to social media and payment methods accepted by the store. It can also house customized pages that direct to the company's recruitment site, customer support and category menus.
FOTO Footer
The Footer block, just as the Header, is responsive, meaning that it can be configured to adapt to different devices, such as desktop and mobile.
Below, we can see an Footer implementation example for desktop:
{
"footer": {
"blocks": ["footer-layout.desktop"]
},
"footer-layout.desktop": {
"children": [
"flex-layout.row#footer-1-desktop"
]
}
}
We are now going to configure a footer for the store's main page, considering the above-mentioned example code for desktop and mobile.
We will not implement the menu during this activity, since it's already be dealt with during the Header context. We will instead look at accepted payment methods and the store's social media networks.
In the footer.jsonc
file, copy the code above and to use in your theme;
Thereafter, declare the following block:
"flex-layout.row#footer-1-desktop": {
"children": [
"flex-layout.col#footer-left-desktop",
"flex-layout.col#footer-right-desktop"
],
"props": {
"blockClass": "footer-row",
"paddingTop": 7,
"paddingBottom": 7
}
}
Based on the block above, build the flex-layout.col#footer-left-desktop
, having the following children: accepted-payment-methods
;
Then, build the accepted-payment-methods
block with the following payment methods: MasterCard
, Visa
and Diners Club
. And just to gain a bit more knowledge, find out how to display payment methods in color in this documentation;
In this step, we will use the social-networks
block to display our store's social media networks. Check the documentation for more on this, and then implement as the social media networks as children of the flex-layout.col#footer-right-desktop
block. We want to display Facebook
, Instagram
and Twitter
.
Lastly, make the social media network logos appear in color. Read the footer's documentation for more on this.
ℹ️ Remember to access the footer's documentation in case you have any questions during the activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
This is the last step of the Store Framework course, you did really well and we hope you've learned a lot until this moment. Congratulations!
If you want to continue learning more about how to develop using VTEX IO, we encourage you to start our next course, which focus on teaching how to develop custom blocks for VTEX Store Framework. You can find it in the Store Block Course on Learning Lab.
In the previous step, we looked at creating a custom template. In scenarios involving promotions and commemorative dates, it's quite common to create special landing pages.
We saw that the search deduces what is needed from the given context. On a custom page however, the context doesn't exist and you need to state which query should be performed to get the results. All this is made possible by the search-result-layout.customQuery
.
The query schema is one of the custom query search result props that allows you to control the search that the landing page should run. To know more the query schema's possibilities, read through its documentation.
Define a new path (store.custom#landing
) in routes.json
;
"store.custom#landing": {
"path": "/landing"
}
Create a new file called search-landing.jsonc
in the blocks folder;
Create a new custom template entitled store.custom#landing
;
Define the image
block as one of this template's blocks. This block must have minWidth
props of 100% and an image of your choosing.
Repeat the same with search-result-layout.customQuery
:
{
"store.custom#landing": {
"blocks": [
"image#landingbanner",
"search-result-layout.customQuery"
]
}
}
Define the search-result-layout.customQuery
block as the querySchema prop that:
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
An Iframe is a HTML element that allows the incorporation of another HTML page to the current one. Therefore, using the Iframe block, you can embed content from other URLs and display them on your page. It's important to remember that URLs rendered by Iframe have their own context, with independent session history and DOMs.
WARNING: Iframes are only allowed on custom page templates.
The iframe
block has very simple properties:
src
: shows which URL should be rendered by the iframewidth
: pixel width of the iframe elementheight
: height of the iframe elementBelow, we can see an implementation example of the iframe
block:
"store.custom#about-us": {
"blocks": [
"flex-layout.row#about-us",
"iframe"
]
},
"iframe": {
"props": {
"src": "http://someURL.com/resource",
"width": 100,
"height": 200
}
}
Let's display an Instagram post on your store page:
rich-text
and include an iframe
block;iframe
props, display the following link content in a 800px-wide by 1000px-high container: https://www.instagram.com/p/B973Qp8BacC/embed
ℹ️ Remember to access the Iframe documentation if you have any questions during this activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
The next block that we'll use is the Shelf, on which we display a product collection. This session will show you how to render and configure this shelf on your store's homepage.
After a closer look at the Shelf documentation, we see that it's possible to configure which product collection we want to have displayed using either category
, specificationFilters
or collection
props, according to the products added in the catalog.
Other props help to configure how the items are displayed. It's important to remember that the shelf
component always requests that product-summary
type blocks be part of its composition. Check out the product-summary block's documentation for more info on how it functions.
Below, we have a Shelf implementation example:
{
"store.home": {
"blocks": [
...
"shelf"
]
},
...
"shelf": {
"blocks": ["product-summary.shelf"],
"props": {
"category": 1,
"orderBy": "OrderByTopSaleDESC",
"paginationDotsVisibility": "desktopOnly",
"productList": {
"maxItems": 10,
"itemsPerPage": 5,
"minItemsPerPage": 1,
"scroll": "BY_PAGE",
"arrows": true,
"titleText": "Top sellers"
}
}
},
"product-summary.shelf": {
"children": [
"product-summary-image",
"product-summary-add-to-list-button",
"product-summary-name",
"product-rating-inline",
"product-summary-space",
"product-summary-price",
"product-identifier.summary",
"product-summary-buy-button"
]
}
}
home.jsonc
, declare a shelf
component is the store.home
template;shelf.jsonc
file;shelf.jsonc
, define the shelf
block with all the props given in the example above;8
4
Note: It's important to remember that the product-summary.shelf
block is already declared in default.jsonc
. Therefore, it wasn't necessary to declare it during this activity.
ℹ️ Remember to access the Shelf's documentation if you have any questions during this activity.
The end result should be similar to the one below:
In case you're using your own VTEX account, make sure that the category 1
is functional and active in your environment.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
Before getting down to business there are some important, frequently occurring concepts you need to familiarize yourself with.
Store Framework is a commerce low-code tool used for building unique and custom storefronts.
The building flow starts with a custom theme, which can be worked on in different workspaces, without impacting the production environment.
A theme is essentially an arrangement of blocks and their position. In a theme, you can define every customization, position and style for every block that theme encompasses. You can also declare new pages in a theme, pages that in the future may represent about us or promotional landing pages (such as mother's day, black Friday, cyber Monday pages). The theme's end result consists of the content it's comprised of, in addition to the storefront.
Blocks are the minimal abstraction in Store Framework. They declare small pieces that make up a store's layout. Although they may look simple at first, blocks are imbued with a high customization power, allowing us to achieve complex designs. There are a total of four block customization levels:
Secure work environments that show a very close copy of what is running in production, allowing themes to be developed further without affecting the store.
We begin our journey with the classic "Hello, World!". In order to create something similar, we need to understand the Store Framework blocks and use one that allows us to create texts. This block is aptly called Rich Text.
The Rich Text is only one of the dozens of blocks available in Store Framework. It's a block that seems simple, but that allows a series of customizations meant to create texts. To start, any text written in Rich Text supports Markdown, making text styling much easier.
Looking at the block's documentation, we can find a technical specification. One of the sessions present is that of the Blocks API, in which we can see the list of all Rich Text properties (props). These properties are the main customization points of a block, which give a block its distinct visual and behavior, depending on how its been configured.
We'll start by customizing the home page. In your theme's /store/blocks
folder, you'll find a file called home.jsonc
. This file determines how the blocks you intend to use are organized. The language used in the layout composition is simple and based on JSON.
In home.jsonc
, you'll notice a block which is default in all themes, namely store.home
. This block determines which child blocks will be displayed on the home page.
{
"store.home": {
"blocks": []
}
...
}
Let's use Rich Text in its body:
{
"store.home": {
"blocks": [
"rich-text"
]
}
...
}
Thus, store.home
now knows that it needs to render a Rich Text. However, we're haven't yet specified which visual this Rich Text should adopt. For that, we'll need to define the block.
Defining a block must always be performed apart from any other block, at thee source level of the JSON file.
{
"store.home": {
"blocks": [
"rich-text" <----- Here the block is used within another
]
},
"rich-text": { <----- Here it's at source level
}
}
In the block's definition, you can set its behavior and visual. Customization points have to be used to achieve this, so we'll start off using the Rich Text props
:
{
"store.home": {
"blocks": [
"rich-text"
]
},
"rich-text": {
"props": {
}
}
}
Read through the Rich Text documentation one more time and let's define the props we'll use to customize the block.
We want to achieve a simple "Hello, World!", and looking at the props we notice one called: text
(Text written in markdown language to be displayed). This is the prop that determines which text will be displayed.
Including this prop, we now have the following:
{
"store.home": {
"blocks": [
"rich-text"
]
},
"rich-text": {
"props": {
"text": "Hello, World!"
}
}
}
Reading through the Markdown documentation, we learn that in order for a text to appear in italic, we just need to place that text between *
:
{
"store.home": {
"blocks": [
"rich-text"
]
},
"rich-text": {
"props": {
"text": "*Hello, World!*"
}
}
}
To center align the text, we can add the textPosition
prop and give it the CENTER
value:
{
"store.home": {
"blocks": [
"rich-text"
]
},
"rich-text": {
"props": {
"text": "*Hello, World!*",
"textPosition": "CENTER"
}
}
}
Define a Rich Text on your home page and create a bold "Hello, World!" that's right aligned.
ℹ️ Remember to access the Rich Text documentation if you have any questions during the activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
An e-commerce's homepage is always the client's first contact with the brand. Therefore, it's common for retailers to want to establish direct communication with their users at this strategic point in time during navigation.
Several components in Store Framework serve this scenario, such as the Info Card, which we looked at previously, and the Rich Text.
As we have seen during step three, the Rich Text is responsible for transforming texts into HTML elements, having the big advantage of reading Markdown. This give the component the flexibility to accept various text structures, allowing retailers to build their communication in more direct and clear way.
Just as with its functionality, the Rich Text configuration is also simple.
The same way that "Hello, world!" was created, we can create a block implementation example using written text in markdown format. For example:
"rich-text": {
"props": {
"text": "# Your Coffee, Your Way \n ### New Coffee Makers Collection",
"textPosition": "CENTER",
"textAlignment": "CENTER"
}
},
As previously stated, using Markdown allows for more component flexibility. However, it may also lead to your alteration in your rendering, according to the device used by the user.
For example: the above sentence ( # Your Coffee, Your Way \n ### New Coffee Makers Collection
) can be use a markdown that's suitable for desktop, but not necessarily for mobile as well (whose screen size is smaller).
To resolve this scenario and make the behavior more adaptable to other devices, we should use the Responsive Layout.
First, we must declare the blocks in the store.home
template:
"responsive-layout.desktop#desktop", "responsive-layout.mobile#mobile"
Then, we must declare these blocks as follows:
...
"responsive-layout.desktop#desktop": {
"children": ["rich-text#desktop"]
},
"responsive-layout.mobile#mobile": {
"children": ["rich-text#mobile"]
},
"rich-text#desktop": {
"props": {
"text": "# Your Coffee, Your Way \n ### New Coffee Makers Collection",
"textPosition": "CENTER",
"textAlignment": "CENTER"
}
},
"rich-text#mobile": {
"props": {
"text": "# Your Coffee, Your Way \n ### New Coffee Makers Collection",
"textPosition": "CENTER",
"textAlignment": "CENTER"
}
}
As we interpret the code above, we can notice two Rich Text configurations, built based on responsive-layout.desktop#desktop
and responsive-layout.mobile#mobile
.
During this activity, we will play around a little with the Rich Text markdown and learn how to use it with the Image component. All the while using Responsive Layout, of course!
Add the code given above to home.jsonc
and declare the responsive-layout
block in the store.home
template;
In rich-text#mobile
, alter the markdown of the first sentence to h3
and of the second to h4
;
If you do not remember how is the Markdown syntax, you can check it in the Markdown Documentation.
Add image#desktop
as a child of responsive-layout.desktop#desktop
. Repeat the process with image#mobile
and responsive-layout.mobile#mobile
;
Declare the following Image blocks:
"image#desktop": {
"props": {
"src": "https://appliancetheme.vteximg.com.br/arquivos/Responsive-Image-Desktop.jpg?q=1",
"link": {
"url": "/small-appliances/coffee-makers"
} ,
"alt": "Coffee Makers Collection"
}
},
"image#mobile": {
"props": {
"src": "https://appliancetheme.vteximg.com.br/arquivos/Responsive-Image-Mobile.jpg?q=1",
"link": {
"url": "/small-appliances/coffee-makers"
} ,
"alt": "Coffee Makers Collection"
}
},
When analyzing the Image component props, set the two images' max width to 100%
.
ℹ️ Remember to access the Responsive Layout documentation if you have any question during your activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
A store needs a good home page to engage users, increasing session time and therefore conversion chances. To achieve this, several elements need to be used, such as promotional banners, shelves with highlights, about us material, etc.
We have created the next block on the home page using a call to action. In Store Framework, we have a block designed for this purpose, called Info Card.
Using the Info Card, you can create images which have links and buttons (top or side of the block) that direct the user's flow (Call to action).
Looking at the documentation, we can see that:
isFullModeStyle
defines whether the Call to Action (CTA) is set above the banner;textPosition
defines the position of the text;textAlignment
defines the text's alignment;imageUrl
defines which image will be used as banner;headline
determines which text will be used as headline;callToActionMode
allows to choose the CTA mode as either a link or a button;callToActionText
defines the CTA text;callToActionUrl
determines the URL to which it redirects;We therefore have the following props:
{
"store.home": {
"blocks": [
"rich-text",
"info-card"
]
},
"rich-text": {
"props": {
"text": "*Hello, World!*",
"textPosition": "RIGHT"
}
},
"info-card": {
"props": {
"isFullModeStyle": false,
"textPosition": "right",
"imageUrl": "https://appliancetheme.vteximg.com.br/arquivos/cozinha-rosa-min.png",
"headline": "Vintage Pink",
"subhead": "Give your kitchen a boho style adding vintage apparels.<br>Available until January 2020.",
"callToActionMode": "button",
"callToActionText": "Explore",
"callToActionUrl": "/sale/d",
"textAlignment": "center"
}
}
}
You may have asked yourself:
"What if I wanted to have two different Info Cards?"
It's possible through block instancing.
All block have pre-established names, but you can create block instances and define different ways in which the block types appear. After each block has been defined, simply place an '#' with an arbitrary name that makes, for example:
{
"store.home": {
"blocks": [
"rich-text",
"info-card#button-right"
]
},
...
"info-card#button-right": {
"props": {
"isFullModeStyle": false,
"textPosition": "right",
"imageUrl": "https://appliancetheme.vteximg.com.br/arquivos/cozinha-rosa-min.png",
"headline": "Vintage Pink",
"subhead": "Give your kitchen a boho style adding vintage apparels.<br>Available until January 2020.",
"callToActionMode": "button",
"callToActionText": "Explore",
"callToActionUrl": "/sale/d",
"textAlignment": "center"
}
}
}
WARNING: Throughout the course, you will notice several
...
, which you should not copy as it represents the progress achieved during previous steps.
In the home.jsonc
file, based on the code above, create the info-card#button-left
right under the infocard: info-card#button-right
. This new infocard must implement the following:
Shining chrome
Go to Collection
https://appliancetheme.vteximg.com.br/arquivos/cozinha-cinza-min.png
Give your kitchen a cool style adding warm metallic finishes.<br>Available until January 2020.
textPosition
).The expected result will look similar to this:
ℹ️ Remember to access the Info Card documentation if you have any questions regarding the activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
In this step we'll finish setting up our product page. We've learned how to stack blocks using Stack Layout, and we've also learned how to suggest similar product and better customize the SKU Selector for products with SKU images.
Use the following product URL to test this step: /3-colors-retro-stand-mixer/p
.
stack-layout
is a type of layout that allows blocks to stack on top of others. It comes in handy when you want to a badge on top of an image or product. It's also useful when placing rich text onto images (using a rich-text
and an image
).
(In the image, a shelf is stacked on top a carrossel 👆)
In this step, we'll use stack-layout
to place the brand on top of product images.
Develop the product page by adding the step below to product.jsonc
:
Declare a shelf.relatedProducts
under the product's main line
"store.product": {
"children": [
"breadcrumb",
"flex-layout.row#main",
"shelf.relatedProducts"
]
}
/3-colors-retro-stand-mixer/p
product.
From the left column, change product-images
with a stack-layout
declaration;
"flex-layout.col#left": {
"children": [
"stack-layout#brand"
]
}
Define stack-layout
and set product-images
and product-brand
as children;
"stack-layout#brand": {
"children": [
"product-images",
"product-brand"
]
}
Consult the documentation to change the way in which product-brand
is displayed. You should make the logo appear with a height of 30 and include the displayMode: "logo"
prop.
Review the documentation to make the sku-selector
do the following:
image
, as it's shown in the documentation mentioned before;ℹ️ Remember to read through the Stack Layout documentation if you have any questions during the activity.
ℹ️ Remember to use the /3-colors-retro-stand-mixer/p
product to test this step.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
As we've seen in the last step, a Submenu accepts any Store Framework block as child.
With this in mind, we can improve the previous activity's Menu configuration, adding to its content by using Flex Layout.
According to what we did in the last activity and what was learned about Flex Layout, let's apply Flex Layout to the Major Appliances submenu.
In the menu.jsonc
file, remove the block of code in which you define [email protected]:submenu#major
and also its children. This code block will be declared in a new file soon:
"[email protected]:submenu#major": {
"children":[ "[email protected]:menu#major" ]
},
"[email protected]:menu#major": {
"children": [
"menu-item#refrigerators",
"menu-item#ovens",
"menu-item#washers"
],
"props": {
"orientation": "vertical"
}
},
Create the menu-flex.jsonc
file, the code block that is declared above needs to be in this file; flex-layout.row#major
will be in the children list pertaining to the [email protected]:submenu#major
block and it's defined as:
{
...
"flex-layout.row#major": {
"children": [
"flex-layout.col#menu",
"flex-layout.col#img"
]
},
...
}
Now, let's declare the blocks defined in flex-layout.row#major
. To start, declare the flex-layout.col#menu
block, having [email protected]:menu#major
as child;
Do the same for the flex-layout.col#img
block, declaring image#menu
and rich-text#header
as its children, in addition to the following props:
...
"props":{
"paddingRight": 4,
"horizontalAlign": "right"
}
...
Lastly, let's declare the former image#menu
as child in this last step, using the code below:
...
"image#menu": {
"props": {
"src": "https://appliancetheme.vteximg.com.br/arquivos/menu-washer.jpg",
"link": {
"url": "/small-appliances/coffee-makers"
},
"alt": "Coffee Makers Collection",
"maxWidth": "200px"
}
}
ℹ️ Remember to access the documentation of both Flex Layout and Menu if you have any questions during the activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
Stores are made up of several different pages, each with a specific content and layout. When creating a store from scratch in VTEX IO, some default pages with preset URLs are already available. Below, we have a list of some of these default pages:
store.home
�(Home page)store.product
(Product page)store.search
(Search Results page)store.account
(Client Account page)store.login
(Login page)store.orderplaced
(Order Placed page)But it's also possible for you to create a custom landing page. In this case, you should create a new URL and specific content to display to users that access this path.
Just a few steps are needed to create a custom landing page:
A template defines the page layout. However, if you want to create a custom page, you will also need to create a new template in your theme.
Let's imagine that you want to create a simple page containing information about your store. Inside the blocks
folder, you can create a file that would contain the following code, declaring a new template for a custom page,
{
"store.custom#{templatename}": {
"blocks": [
]
}
}
where {templateName}
must be replaced with the template's identifying name.
Then, you should fill in the code with the components needed to create the layout. Below we have an example of such implementation:
{
"store.custom#{templatename}": {
"blocks": [
"flex-layout.row#about-us"
]
},
"flex-layout.row#about-us": {
"children": [
"image#about-us",
"flex-layout.col#text-about-us"
]
},
"flex-layout.col#text-about-us": {
"children": [
"rich-text#about-title",
"rich-text#about-content"
],
"props": {
"preventVerticalStretch": true
}
},
"rich-text#about-title": {
"props": {
"text":
"# About FlatFlat"
}
},
"rich-text#about-content": {
"props": {
"text":
" FlatFlat is an electronics store with a long standing tradition for creating modern and vintage items. Out objective is to create home appliances that make your house stand out, no matter your style. Merely 2 months old, we're already the store with the most beautiful products among all VTEX stores. We are currently building our site with the aim of giving our customers an unforgetable experience with our brand!"
}
},
"image#about-us": {
"props": {
"src": "https://appliancetheme.vteximg.com.br/arquivos/cozinha-about-us.png",
"maxHeight": "600px"
}
}
}
Now that a new template with the page layout has been defined in the store theme's code, the next step is to establish the page's page that would lead to this layout.
We must create a routes.json
file in your theme's store
folder. Afterwards, insert the code below,
{
"store.custom#about-us": {
"path": "/{URL}"
}
}
where {URL}
is the name of the desired path.
Let's create a page containing information about your store, as in the example below:
blocks
folder, create a file called about-us.jsonc
;store.custom#about-us
template in this file;flex-layout.row
, use the code in example given above to complete the page layout;store
folder, create a file called routes.json
;/about-us
path;{workspace}--appliancetheme.myvtex.com/about-us
to see your new landing page.Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
We've just implemented our product page and are moving on to the search page. Both are similar in the sense that both have blocks that are unique in this context. We will explore this block in a disorderly fashion for now, just to get an idea of its behavior. Then, we'll look at improving the layout.
Same as other templates, store.search
can also be flexible. To build a unique layout you'll need to use a block called search-result-layout
.
{
"store.search": {
"blocks": ["search-result-layout"]
}
}
The search-result-layout
, in turn, must receive 3 other blocks:
search-result-layout.desktop
search-result-layout.mobile
search-not-found-layout
As you've already notice, the first two define which layout will be displayed on desktop and mobile respectively, while the third defines the layout of the no results found search page.
{
"store.search": {
"blocks": ["search-result-layout"]
},
"search-result-layout": {
"blocks": [
"search-result-layout.desktop",
"search-result-layout.mobile",
"search-not-found-layout"
]
}
}
In the course, we'll focus on desktop layout implementation.
The search results documentation offers a good reference for blocks that can be use in a search context. This step will focus on highlighting the main ones:
breadcrumb.search
);search-title.v2
);total-products.v2
);order-by.v2
);search-fetch-more
);search-fetch-previous
);filter-navigator.v3
);search-content
)Although quite many, all these blocks are relatively simple and work very well without an express need to configure their props
.
Copy the code above in search.jsonc
and define a search-result-layout.desktop
having the following, in the order mentioned below:
breadcrumb.search
;search-title.v2
;total-products.v2
;order-by.v2
;search-fetch-previous
;search-content
;filter-navigator.v3
;search-fetch-more
.ℹ️ Remember to go through the Search Result documentation if you have any questions during the activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
In the last step, we've looked at the search page and its main components. We also learned that the search layout works like any other block, with the added benefit of having all the flexibility it can muster. In this step, we'll create some lines and columns to improve the appearance of the created search.
In the search.jsonc
file, remove total-products.v2
and order-by.v2
from search-result-layout.desktop
.
Replace both with a line that includes the removed blocks:
...
"flex-layout.row#top": {
"children": [
"total-products.v2",
"order-by.v2"
]
}
...
Remove search-content
and filter-navigator.v3
from search-result-layout.desktop
and create a results line;
Place two columns in the results line:
{
...
"search-result-layout.desktop": {
"children": [
"breadcrumb.search",
"search-title.v2",
"flex-layout.row#top",
"search-fetch-previous",
"flex-layout.row#results",
"search-fetch-more"
]
},
"flex-layout.row#results": {
"children": [
"flex-layout.col#filter",
"flex-layout.col#search"
]
},
...
}
Set the filter
column's width
prop to 20%
.
In the left column, include filter-navigator.v3
again and, in the right, include search-content
.
To finish, we'll use the same product summary (product-summary
) that we used to display search results on the shelf.
Define your search-content
with the gallery
and not-found
blocks:
{
...
"search-content": {
"blocks": ["gallery", "not-found"]
}
...
}
Use product-summary.shelf
in the Gallery's props:
{
...
"search-content": {
"blocks": ["gallery", "not-found"]
},
"gallery": {
"blocks": ["product-summary.shelf"]
}
...
}
In the product-summary.shelf
block, found in default.jsonc
, include product-summary-sku-selector
above product-summary-buy-button
.
ℹ️ Remember to access the Flex Layout documentation if you have any questions during the activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
For your Mac setup video, click here
Before getting your hands dirty and learning more about VTEX IO's Store Framework, you'll need to set up a few basic configurations, such as:
Have a look at the step-by-step below for each of these configurations:
Install Git on your computer by clicking on the link below and selecting your operating system (Windows, MAC or Linux):
Toolbelt is a VTEX command line tool. It allows you to perform any activity on the platform, such as creating a new development workspace, logging into a VTEX account, developing new apps, or managing already existing ones, etc.
Since it's Toolbelt that establishes the communication between the developer and the platform, you'll need it in order to perform all the activities put forward during the Store Framework course.
npm i -g vtex
in your terminal if you're using Windows or yarn global add vtex
if you're using MAC;Your can run vtex-v
(Windows) or vtex
(MAC) to confirm whether the Toolbelt installation was as expected.
Once successfully installed, your next step is to log into a VTEX account.
Run vtex login VTEXaccount
in your terminal, replacing VTEXaccount
with the name of the account in which you want to work. For example, vtex login appliancetheme
.
After logging in, run vtex whoami
to confirm the account and workspace in which you find currently are.
Workspaces are nothing other than what the namesake suggests. On VTEX IO, accounts have three main workspace types, namely master, production and development.
The next step is to create a development workspace, which will allow you to play with the configurations throughout the course without altering the store's final public version.
vtex use workspace-name
, replacing workspace-name
with the desired name. For example, vtex use devworkspace
.After creating the workspace, you'll be able to access it at this link: https://{workspace}--{account}.myvtex.com
, replacing {workspace}
and {conta}
with the name of the previously created workspace and account. For example, https://devworkspace--appliancetheme.myvtex.com
After setting up the basic configurations, you're ready to start the course!
It's important to establish that is not an expository course. Its objective is to teach participants about the VTEX IO Store Framework based on practical applications/activities. Therefore, in order to advance, you'll need to invest some time and dedication into it.
At the beginning of the course, you'll receive a repository containing a minimum amount of code our wish is that, upon completing all the tasks laid before you, you would have transformed that code into a fully functional store.
The course is divided into chapters. As each chapter begins, you'll receive initial instructions, just as you've already received for this and previous chapters. You should read through all of the presented content and perform the minor task set out at the end of the chapter.
For your answers to be sent, follow these steps:
git clone
https://github.com/dmitriyzhuk/store-framework
Open
on the notification that appears in the lower right cornerstore-framework
;dmitriyzhuk/store-framework
and then on Install.After reading the entire content and performing the wanted task, you should send your answer according to the steps below:
Source Control
, in the VSCode side menu;+
in the CHANGES section;✓
(Commit);+ Create new branch...
;Once you complete this flow, our bot will let you know whether your answers were correct or not. If yes, the reply will look like this:
Thereafter, you'll receive another reply highlighting the next steps:
If you're familiar with git, this entire flow is equivalent to creating a branch with a predefined name, committing changes and then executing a push.
Throughout the course, you may run into difficulty and not manage to correctly complete the activity on your first try. When this happens, you'll receive a feedback message that will let you know where you failed:
You can submit as many answers and you want by simply retrying the entire process explained in the previous section.
You may see your course progress at any time by going back to the main page. There, you'll see every step, what you've already completed, along with a button that takes you back to where you last stopped:
Anytime you open the VSCode terminal, you can run a vtex link
to monitor the evolution of your project in https://{workspace}--{account}.myvtex.com
. Make sure that the solution is visually comparable to what was presented and that no link errors occurred.
Do not create issues and PRs during the course flow, since this can interfere with its functioning.
Taking a quick look at your online store, you'll notice that components have similar styles, even without applying any customization.
All of them, including the recently configured Info Card, share pre-established values for font, background color, main color, button format, etc.
This is due to the style.json
, the file responsible for declaring generic customization values for every Store Framework store.
To create a unique identity for your store's components, you can overwrite these values using CSS customizations.
Analyzing the recipe employed to customize stores using CSS, we can notice that several steps will be needed in order to apply your own style, such as:
Create a new file in the CSS
folder, naming it vtex.{AppName}.css
Use the CSS Handle of the component that will be customized in this file in the following format:
.{CSSHandle} {
{PropriedadeDeCSS}: {ValorDesejado};
{PropriedadeDeCSS}: {ValorDesejado};
}
Lacking CSS Handles, apply permitted CSS Selectors, such as :global(vtex-{componentName})
.
To apply CSS to a specific block and not to every block of that type, use the blockClass resource, which appears next to the CSS Handles when inspecting your code. The blockClass must be declared as a prop in the block in question, and thus be referenced in the style file as shown below:
.{CSSHandle}--{blockClass} {
{CSSProperty}: {desiredValue};
{CSSProperty}: {desiredValue};
}
To uncover a component's CSS Handles, such as the Info Card, simply access your documentation's Customization
section.
According to the description of CSS Handles and to the store customization recipe using CSS, we can implement a customized Info Card example, editing its title and call-to-action button configurations by adding the following code to the vtex.store-components.css
file, found in /styles/css
:
.infoCardHeadline {
font-family: serif;
font-size: 2.25rem;
font-weight: normal;
color: gray;
border: 2px solid black;
padding: 24px;
}
.infoCardCallActionContainer :global(.vtex-button) {
color: white;
background-color: gray;
border: transparent;
}
.infoCardCallActionContainer :global(.vtex-button):hover {
color: gray;
background-color: blue;
border: transparent;
}
You can check the effect of these changes by running the vtex link
command.
Next, we'll add a specific style to the vintage info card. To begin, add the blockClass
prop to info-card#button-right
, as shown below:
"info-card#button-right": {
"props": {
"isFullModeStyle": false,
"textPosition": "right",
"imageUrl": "https://appliancetheme.vteximg.com.br/arquivos/cozinha-rosa-min.png",
"headline": "Vintage Pink",
"subhead": "Give your kitchen a boho style adding vintage apparels.<br>Available until January 2020.",
"callToActionMode": "button",
"callToActionText": "Explore",
"callToActionUrl": "/sale/d",
"textAlignment": "center",
"blockClass": "vintage" // <------------
}
}
Thereafter, declare a background-color
for this specific info card in your CSS file:
.infoCardContainer--vintage {
background-color: #edcfd1
}
Check out the result by linking your app.
vtex.store-components.css
file, copy the above-mentioned code and use it in your theme's CSS file, according to the recipe on store customizations using CSS;max-width
) of 1260px
for all info cards, a margin of 0 auto
and a padding of 0
.black
;bold
;white
;vintage
blockClass, apply a new block class called metal
to the info card info-card#button-left
and apply the #e1e1e1
background color to it.Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
During the last step we learned how to create a simple product page with a minimum amount of products, but we know that the result is far from an ideal product page, so we'll add other elements that frequently appear on product pages from various stores.
Our documentation contains more than 30 product-related blocks. At the beginning of the course we looked at the Shelf and its related blocks, in addition to the 4 blocks we looked at during our last session. We'll explore 4 more in this step:
It's important that by the end of the course you take some time to fully explore our components, in addition to the customization possibilities that accompany each component.
Develop the product page by adding the 4 blocks listed above toproduct.jsonc
as follows:
Define a breadcrumb
right before the product's main line;
"store.product": {
"children": [
"breadcrumb",
"flex-layout.row#main"
]
}
Define the product-identifier.product
right under the product-name
;
Create a line right under the price, having sku-selector
and product-quantity
as children;
{
...
"children": [
"product-price",
"flex-layout.row#qty-sku"
]
},
"flex-layout.row#qty-sku": {
"children": [
"sku-selector",
"product-quantity"
]
},
...
}
Define shipping-simulator
right under the line containing the SKU Selector and Product Quantity
ℹ️ Remember to access the Breadcrumb, Product Identifier, Product Quantity and SKU Selector documentation if you have any questions during the activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
As we've seen, Markdown is a user friendly language that can be easily converted to HTML. In this lesson, we'll see how it's possible to use this language in our Rich Text block to create interesting texts.
To include texts in the rich-text
block, you need to use the text
prop:
"rich-text#home1": {
"props": {
"text": "My text",
"textPosition": "LEFT",
"textAlignment": "LEFT"
}
The text
prop accepts markdown format. However, if you want to write your text using this language, your code must be similar to the following:
```json
"rich-text#home1": {
"props": {
"text": "# My title h1 \n Insert a paragraph here \n ## My title h2 \n Insert the second paragraph here \n Include a list here \n - Item 1 \n - Item 2 \n - Item3",
"textPosition": "LEFT",
"textAlignment": "LEFT"
}
TIP: Always use the \n
command to skip lines when using markdown in the text
prop
Other properties of the rich-text
component can be found in the Store Framework official documentation
In about-us.jsonc
, change the text in tab-list.item#home1
so that an "About" appears in the first tab;
In the rich-text
content linked to this tab, use the text below:
# Our history \n ### We were born from an internal VTEX hackathon! \n That's right. VTEX's first Hackatheme (store theme hackathon) had 3 finalists. One of them was FlatFlat, the store that you're accessing now. FlatFlat was created by the engineers Afonso Praça and Sávio Muniz, together with designers Lucas Falcão and Augusto Barbosa, and new business director Maurício Baum. As the store was created by profissionals having the most diverse backgrounds, the result was an obvious one: they became the finalists with coolest layout among participants.
Insert the title and subtitle in bold.
ℹ️ Remember to access the Rich Text documentation if you have any questions during the activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
In this step, we'll learn how to configure the store's first component: the Header.
The Header plays a very important role on the store's main page, being responsible for housing other blocks that are crucial to user browsing, such as the search bar and the menu.
The Header block is responsivo, meaning that it can be configured to adapt to different devices, be it desktop or mobile.
Below, we can see an implementation example:
{
"header": {
"blocks": [
"header-layout.desktop",
"header-layout.mobile"
]
},
"header.full": {
"blocks": [
"header-layout.desktop",
"header-layout.mobile"
]
},
"header-layout.desktop": {
"children": [
"header-row#notification",
"header-row#main"
]
},
"header-layout.mobile": {
"children": [
"header-row#notification",
"header-row#main-mobile",
"header-row#search"
]
},
}
We will now configure a Header for your store's main page from scratch, with a notification and search bar, logo, cart and login. We will not configure the menu for now, since we'll look at it in depth during our next activity.
To implement a Header containing all these blocks, we'll start out from the code mentioned above and thus be able to build a responsive header, adaptable to desktop and mobile users alike.
Unlike the behavior found in other blocks, the Header doesn't need to be declared in one your theme's templates, since it will rendered on every store page anyway. In this exercise, we will declare the header
block in the header.jsonc
file, which must be created in the store/blocks
folder.
Thereafter, declare the following block:
"header-row#notification": {
"children": [
"header-spacer",
"rich-text#header",
"header-spacer"
]
},
Based on the block above, build the header-row#main
, giving it the following children: logo
, header-spacer
, search-bar
, minicart
and login
;
Still in the header-row#main
block, declare the inverted
, sticky
and fullWidth
props with the following values: true
, true
and false
, respectively;
Copy and paste the code below to configure the header block for mobile, in the same way that we did for desktop before:
"header-row#main-mobile": {
"children": [
"logo",
"header-spacer",
"minicart",
"login"
],
"props": {
"sticky": true,
"inverted":true
}
},
"header-row#search": {
"children": [
"search-bar"
],
"props": {
"sticky": true
}
},
Declare the block responsible for defining the store's login and logo, using the code displayed below, which will be used by the Header of the two devices;
"login":{
"props": {
"showIconProfile": true,
"iconLabel": "Login"
}
},
"logo":{
"props": {
"url": "https://appliancetheme.vteximg.com.br/assets/vtex.file-manager-graphql/images/flatflat___6081e50402943bcb11bc45a8e613aa72.png"
}
},
Lastly, we need to declare the notification Header line's main component ("header-row#notification"
): the Rich Text;
"rich-text#header": {
"props": {
"text": "**Free Shipping on orders over $50**",
"textPosition": "CENTER"
}
}
Following the recipe on customizing store icons, replace the default icon used in the search bar and in the cart with the examples below.
New search bar:
<path fill="currentColor" d="M4,13H1c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h3V13z"></path> <path fill="currentColor" d="M15,3H1C0.448,3,0,2.552,0,2v0c0-0.552,0.448-1,1-1h14c0.552,0,1,0.448,1,1v0C16,2.552,15.552,3,15,3z"></path> <path fill="currentColor" d="M4,8H1C0.448,8,0,7.552,0,7v0c0-0.552,0.448-1,1-1h3V8z"></path> <path fill="currentColor" d="M15.707,13.293l-2.274-2.274C13.785,10.424,14,9.74,14,9c0-2.206-1.794-4-4-4S6,6.794,6,9 s1.794,4,4,4c0.74,0,1.424-0.215,2.019-0.567l2.274,2.274L15.707,13.293z M10,11c-1.103,0-2-0.897-2-2s0.897-2,2-2s2,0.897,2,2 S11.103,11,10,11z"></path>
New cart icon:
<path fill="currentColor" d="M15,6h-1.4l-2.7-5.4C10.6,0.1,10-0.1,9.6,0.1C9.1,0.4,8.9,1,9.1,1.4L11.4,6H4.6l2.3-4.6 c0.2-0.5,0-1.1-0.4-1.3C6-0.1,5.4,0.1,5.1,0.6L2.4,6H1c-1.1,0-1.1,1-0.9,1.4l3,8C3.2,15.7,3.6,16,4,16h8c0.4,0,0.8-0.3,0.9-0.6l3-8 C16.1,7,16,6,15,6z"></path>
After completing step 8, the new search bar and cart icon should be rendered on your store page as follows:
ℹ️ Remember to access the header documentation if you have any questions during the activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
The Flex Layout is a layout structuring paradigm created in Store Framework to allow the construction of complex layouts. This paradigm uses the concepts of lines and columns to define the desired block structure and positioning on a certain page.
There are two basic building blocks for each Flex Layout:
flex-layout.row
flex-layout.col
If you are already familiar with the Flexbox used in CSS, the Flex Layout should be easy to understand, since Flexbox is already used "under the hood" by flex-layout.row and flex-layout.col.
With the help of Flex Layout, you can create customized layouts, using the Flexbox structure of lines and columns.
Analyzing the block's documentation, we see that you can use any block array as Flex Layout's children
. In addition, you should always use flex-layout.row
and flex-layout.col
, and NEVER flex-layout
alone.
Below, we have an example of a flex layout comprised of a flex-layout.row
with two children: an info-card
and a rich-text
:
"flex-layout.row":{
"children": [
"info-card#rethink",
"rich-text#delete"
]
},
"info-card#rethink": {
"props": {
"imageUrl": "https://appliancetheme.vteximg.com.br/arquivos/utensilios-cozinha-min.png",
"isFullModeStyle": true,
"headline": "Time to rethink your kitchen",
"callToActionText": "Discover",
"textPosition": "center"
}
},
"rich-text#delete": {
"props": {
"text": "I'll be deleted soon"
}
}
Declare the flex-layout.row
in the store.home
's template blocks
and then declare the blocks mentioned above in your home.jsonc
file.
Edit the flex-layout.row
children, substituting the rich-text
block with a flex-layout.col
column.
Delete the above-mentioned rich-text
block from your theme.
Declare the flex-layout.col
block in your home.jsonc
file with two image components as children: image#electronics
and image#major-appliance
, in this order.
Define the image
blocks with the following props:
...
"image#electronics": {
"props": {
"src": "https://appliancetheme.vteximg.com.br/assets/vtex.file-manager-graphql/images/electronics_banner___25d69b49f8224b369375e68513b4d593.png",
"maxWidth": "100%"
}
},
"image#major-appliance": {
"props": {
"src": "https://appliancetheme.vteximg.com.br/assets/vtex.file-manager-graphql/images/major_appliance_banner___bb10093866a127345ddfbcca3efa5022.png",
"maxWidth": "100%"
}
}
The result should be similar to this:
ℹ️ Remember to access the Flex Layout documentation in case you have any questions during the activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
Once the store's homepage is done, we can start working on a new store template: the product page. Product pages are probably the templates with the most blocks, which makes them extremely flexible and customizable.
Let's build a minimal product page, with only the bare essentials:
Most product blocks, unlike content blocks, are inserted into a certain context, making them a little bit "plug-n-play": placing product-images
on the product page will automatically lead to images being rendered on that page, the same being valid for price and name.
This doesn't mean that these blocks are less customizable, quite the opposite actually, as we'll soon see.
Build a product page using the following blocks in product.jsonc
and declare it in the store/blocks
folder: product-images
, product-price
, product-name
and buy-button
. We expect the structure to contain the following:
A line in store.product
;
{
"store.product": {
"children": [
"flex-layout.row#main"
]
}
}
That line should have two columns;
"flex-layout.row#main": {
"props": {
"marginTop": 6
},
"children": [
"flex-layout.col#left",
"flex-layout.col#right"
]
}
The left column must contain a product-images
;
"flex-layout.col#left": {
"children": [
"product-images"
]
}
The right column must contain the product-name
, product-price
and buy-button
;
In addition, we want:
verticalAlign
and preventVerticalStretch
props in the Flex Layout Column documentation)product-price
to show the total savings and list price (showSavings
and showListPrice
)ℹ️ Remember to access the product-images
, product-price
, product-name
e buy-button
documentation in case you have any questions during your activity.
Is there any problem with this step? What about sending us a feedback? 🙏
If you're still unsure as to how to send your answers, click here.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.