Code Monkey home page Code Monkey logo

store-framework's Introduction

store-framework-template

The template repository for the Store Framework course on Learning Lab.

store-framework's People

Contributors

klzns avatar victorhmp avatar vtexgithubbot avatar

Watchers

 avatar

store-framework's Issues

Building a custom search landing page

Building a custom search landing page

Branch: landing

Introduction

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.

Custom searches

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.

Query schema

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.

Activity

image

  1. Define a new path (store.custom#landing) in routes.json;

    "store.custom#landing": {
      "path": "/landing"
    }
  2. Create a new file called search-landing.jsonc in the blocks folder;

  3. Create a new custom template entitled store.custom#landing;

  4. 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.

  5. Repeat the same with search-result-layout.customQuery:

    {
      "store.custom#landing": { 
        "blocks": [
          "image#landingbanner", 
          "search-result-layout.customQuery"
        ]
      }
    }
  6. Define the search-result-layout.customQuery block as the querySchema prop that:

  • Sorts by latest release date;
  • Hides unavailable items;
  • Displays a max of 8 items per page;
  • Uses "Camera" as query.
  1. At this point, you're probably not seeing the block on the landing page. This is due to the fact that we have not add a block to the search-result-layout.customQuery yet. You can do that by adding the following lines:
    // store/blocks/search-landing.jsonc
    {
        ...
        "search-result-layout.customQuery": {
            "props": {
                "querySchema": {
                    "orderByField": "OrderByReleaseDateDESC",
                    "hideUnavailableItems": true,
                    "maxItemsPerPage": 8,
                    "queryField": "Camera",
                    "mapField": "ft",
                    "skusFilter": "ALL_AVAILABLE"
                }
            },
    +       "blocks": [
    +         "search-result-layout.desktop"
    +       ]
        }
    }

🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Flex Layout: create layouts using the power of Flexbox

Flex Layout: create layouts using the power of Flexbox

Branch: flexlayout

Introduction

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.

Flex Layout

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"
    }
  }

Activity

  1. Declare the flex-layout.row in the store.home's template blocks and then declare the blocks mentioned above in your home.jsonc file.

  2. Edit the flex-layout.row children, substituting the rich-text block with a flex-layout.col column.

  3. Delete the above-mentioned rich-text block from your theme.

  4. 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.

  5. 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:

image

ℹ️ Remember to access the Flex Layout documentation in case you have any questions during the activity.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Product shelf

Product shelf

Branch: shelf

Introduction

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.

Shelf

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"
    ]
  }
}

Activity

  1. In home.jsonc, declare a shelf component is the store.home template;
  2. Inside the blocks folder, create a shelf.jsonc file;
  3. In shelf.jsonc, define the shelf block with all the props given in the example above;
  4. Change the maximum number of displayed items to 8
  5. Change the number of items per page to 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:
image

Troubleshoot

In case you're using your own VTEX account, make sure that the category 1 is functional and active in your environment.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Hello, World!

Hello, World!

Branch: helloworld

Introduction

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.

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.

Starting out

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 blocks

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"
    }
  }
}

Activity

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.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Inserting an Iframe on our about us page

Inserting an Iframe on our about us page

Branch: iframe

Introduction

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 iframe
  • width: pixel width of the iframe element
  • height: height of the iframe element

Below, 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
  }
}

Activity

Let's display an Instagram post on your store page:

  1. Change the label of the "Electronics" tab to "Instagram";
  2. In the Instagram tab's content, delete the rich-text and include an iframe block;
  3. In the 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.

Expected result:


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Global styles

Global Styles

Branch: styles

Introduction

In addition to css, which we looked at previously, Store Framework offers another type of design customization, based on style.json.

Semantic styling

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.

Investigating style.json

Colors

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): image

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.

Typography

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.

image image

Activity

  1. In style.json, replace every color occurrence that you find, substituting:
  • #072c75 with #45a6a3
  • #0F3E99 with #52BAB7
  1. Change the font size for a level 1 heading so that its height is now 2.5 rem.

The expected result is as it follows:


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Making your content responsive

Making your content responsive

Branch: responsive

Introduction

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.

Configuring the Rich Text

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.

Activity

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!

Desktop:

image

Mobile:

image

  1. Add the code given above to home.jsonc and declare the responsive-layout block in the store.home template;

  2. 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.

  3. Add image#desktop as a child of responsive-layout.desktop#desktop. Repeat the process with image#mobile and responsive-layout.mobile#mobile;

  4. 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"
      }
    },
  5. 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.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Tab layout

Tab layout

Branch: tab-layout

Introduction

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"
  }
}

Activity

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.

  1. In the previously created about-us.jsonc, add a tab-layout#home to the store.custom#about-us template;

  2. Declare the tab-layout#home block and add tab-list#home and tab-content#home as its children;

  3. Declare tab-list#home and add tab-list.item#home1 and tab-list.item#home2 as its children;

  4. 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);

  5. Declare tab-list.item#home2's props so that the interface displays "Electronics". (Tip: Don't forget to include tabId = "electronics" to the props);

  6. 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;

  7. For each tab-content.item, declare just one rich-text as child (for example, rich-text#home1 and rich-text#home2);

  8. Thereafter, include a tabId prop for each tab-content.item to create a link between the previously created tab-list and tab-content;

  9. 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.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Creating custom templates

Creating custom templates

Branch: custom-template

Introduction

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.

Creating a Landing Page

Just a few steps are needed to create a custom landing page:

  1. Create a new template in your store's theme
  2. Create a new path to access this template

Template

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"
   }
 }
}

Path

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.

Activity

Let's create a page containing information about your store, as in the example below:

  1. In the blocks folder, create a file called about-us.jsonc;
  2. Declare a store.custom#about-us template in this file;
  3. Include a "flex-layout.row#about-us" block in this template;
  4. After declaring flex-layout.row, use the code in example given above to complete the page layout;
  5. In the store folder, create a file called routes.json;
  6. In this file, declare an /about-us path;
  7. Once the code is linked, access {workspace}--appliancetheme.myvtex.com/about-us to see your new landing page.

🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Product page

Product page

Branch: pdp

Introduction

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.

MVP

Let's build a minimal product page, with only the bare essentials:

  • images;
  • prices;
  • names;
  • buy button

image

Product blocks

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.

Activity

Click on a product to go to the product page. Build the 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:

  1. A line in store.product;

    {
    "store.product": {
        "children": [
          "flex-layout.row#main"
        ]
      }
    }
  2. That line should have two columns;

    "flex-layout.row#main": { 
      "props": { 
        "marginTop": 6
      },
      "children": [
        "flex-layout.col#left",
        "flex-layout.col#right"
      ]
    }
  3. The left column must contain a product-images;

    "flex-layout.col#left": {
      "children": [
        "product-images"
      ]
    }
  4. The right column must contain the product-name, product-price and buy-button;

In addition, we want:

  1. the right column to be vertically aligned to the center (see the verticalAlign and preventVerticalStretch props in the Flex Layout Column documentation)
  2. the 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.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Menu

Menu

Branch: menu

Introduction

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:

menu

Configuring the Menu

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"
    }
  }
},

Activity

This activity will help us understand more about configuring the Menu, in addition to its existing hierarchy based on building Menu Items and Submenus.

  1. 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;

  2. 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"
      ]
    },
  3. 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;

  4. 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"
        }
    },
  5. 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"
      ]
    },
  6. 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;

  7. In addition, create a Small Appliances submenu:

    "[email protected]:submenu#small":{
      "children":[
        "[email protected]:menu#small"
      ]
    },
  8. 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;

  9. 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.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Basic configurations

Basic configurations

IMAGE ALT TEXT HERE

For your Mac setup video, click here

Introduction

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:

  • Installing Git;
  • Installing Toolbelt;
  • Logging into a VTEX account;
  • Creating a development workspace;
  • Linking your local files to the platform.

Have a look at the step-by-step below for each of these configurations:

Installing Git

Install Git on your computer by clicking on the link below and selecting your operating system (Windows, MAC or Linux):

https://git-scm.com/downloads

Installing Toolbelt

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.

  1. Install Node.js. If you are using a MAC, also install Yarn;
  2. Run 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.

Logging in

  1. 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.

  2. 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.

Creating a development workspace

  1. Run vtex use workspace-name, replacing workspace-name with the desired name. For example, vtex use devworkspace.

Accessing your workspace

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!

Click on Close Issue to continue

Store Framework 101

Store Framework 101

Before getting down to business there are some important, frequently occurring concepts you need to familiarize yourself with.

Introduction

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.

Theme

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

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:

  • semantic style (styles);
  • properties (props);
  • css classes (handles);
  • children (children)

image

Workspaces

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.


Click on Close issue to continue

Course functioning

Course functioning

IMAGE ALT TEXT HERE

Objective

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.

Intro

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:

  1. Open a new window in VSCode
  2. Execute CTRL + Shift + P or Cmd + Shift + P
  3. Run git clone

image

  1. Type in the repository's name, such as https://github.com/santosluiz000/store-framework
  2. Confirm and select where you want to clone the repository
  3. Click on Open on the notification that appears in the lower right corner

image

  1. Open our test bot installation page and click on Configure;
    • ⚠️ Note that this bot differs from the GitHub Learning Lab bot. It's responsible for analyzing the answers coming from each course stage.
  2. Select the Only selected repositories option, then click on Select repositories and type in store-framework;
  3. Click on santosluiz000/store-framework and then on Install.

Submitting your answers

After reading the entire content and performing the wanted task, you should send your answer according to the steps below:

  1. Click on Source Control, in the VSCode side menu;

  1. Click on the + in the CHANGES section;

image

  1. Compose a message that describes your change. For example:

image

  1. Click on (Commit);

image

  1. Click on the lower left corner;

  1. When a new window appears, fill it in with the Branch name that was given at the beginning of the text and click on + Create new branch...;

  1. Lastly, click on the cloud icon in the lower left corner:

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.

Retries

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.
⚠️ In item 6 above, you won't need to retry everything, once the step's branch has been created. In item 7, instead of a cloud icon, you'll see several arrows, just click on them to resend:

image

Course progress

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:

image

Don't forget to link

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.

⚠️ Warning ⚠️

Do not create issues and PRs during the course flow, since this can interfere with its functioning.


To continue, click on Close issue

Info Card: Store Framework's call to action

Info Card: Store Framework's call to action

Branch: infocard

Introduction

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.

Info Card

image

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"
      }
    }
  }

Instancing blocks

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.

Activity

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:

  1. The title must be Shining chrome
  2. A link type call-to-action with the following text instead of a button: Go to Collection
  3. The following image https://appliancetheme.vteximg.com.br/arquivos/cozinha-cinza-min.png
  4. The following subtitle Give your kitchen a cool style adding warm metallic finishes.<br>Available until January 2020.
  5. Text to the left of the image (textPosition).

The expected result will look similar to this:

image

ℹ️ Remember to access the Info Card documentation if you have any questions regarding the activity.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Evolving your product page (pdp)

Evolving your product page (pdp)

Branch: pdp2

Introduction

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.

image

Over 30 product blocks

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.

Activity

Develop the product page by adding the 4 blocks listed above toproduct.jsonc as follows:

  1. Define a breadcrumb right before the product's main line;

    "store.product": {
      "children": [
        "breadcrumb",
        "flex-layout.row#main"
      ]
    }
  2. Define the product-identifier.product right under the product-name;

  3. 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"
        ]
      },
      ...
    }
  4. 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.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Search page

Search page

Branch: search

Introduction

image

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.

Search 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.

Search blocks

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:

  • Search breadcrumb (breadcrumb.search);
  • Search title (search-title.v2);
  • Total products found (total-products.v2);
  • Product ordering (order-by.v2);
  • Show more results button (search-fetch-more);
  • Show previous results button (search-fetch-previous);
  • Navigation filter (filter-navigator.v3);
  • Search results (search-content)

Although quite many, all these blocks are relatively simple and work very well without an express need to configure their props.

Activity

image

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.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Blocks carousel

Blocks Carousel

Branch: slider

Introduction

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.

Slider Layout

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"
    }
  }

Activity

In this activity, we will create a brand slider for our site:

  1. In home.jsonc, declare the slider-layout#home block to the store.home template.

  2. Create a file called slider-layout.jsonc in the /store/blocks folder;

  3. 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;

  4. Declare a specific src prop for each defined image#brand. Use the URLs below for each:

    1. https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square1.png
    2. https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square2.png
    3. https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square3.png
    4. https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square4.png
    5. https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square5.png
    6. https://appliancetheme.vteximg.com.br/arquivos/flatflat-brand-logo-square6.png
  5. 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.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

CSS Handles and the power of customizing blocks

CSS Handles and the power of customizing blocks

Branch: csshandles

Introduction

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.

style

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:

  1. Create a new file in the CSS folder, naming it vtex.{AppName}.css

  2. Use the CSS Handle of the component that will be customized in this file in the following format:

    .{CSSHandle} {
        {PropriedadeDeCSS}: {ValorDesejado};
        {PropriedadeDeCSS}: {ValorDesejado};
    }
  3. Lacking CSS Handles, apply permitted CSS Selectors, such as :global(vtex-{componentName}).

  4. 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};
    }

Customizing the Info Card

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.

image

Next, we'll add a specific style to the vintage info card. To begin, add the blockClassprop 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.

image

Activity

  1. In the 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;
  2. Based on the Info Card Handles, define a maximum width (max-width) of 1260px for all info cards, a margin of 0 auto and a padding of 0.
  3. Change the component's title color to black;
  4. Put the title in bold;
  5. Change the call-to-action buttons background color during hover to white;
  6. In parallel to the 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.

image


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Header

Header

Branch: header

Introduction

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.

Desktop Header:
image

Mobile Header:
image

Configuring the Header

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"
    ]
  },
}

Activity

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.

  1. 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.

  2. Thereafter, declare the following block:

    "header-row#notification": {
      "children": [
        "header-spacer",
        "rich-text#header",
        "header-spacer"
      ]
    },
  3. Based on the block above, build the header-row#main, giving it the following children: logo, header-spacer, search-bar, minicart and login;

  4. Still in the header-row#main block, declare the inverted, sticky and fullWidth props with the following values: true, true and false, respectively;

  5. 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
      }
    },
    
  6. 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"
      }
    },
  7. 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"
      }
    }
  8. 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:

new-store-icons

ℹ️ Remember to access the header documentation if you have any questions during the activity.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Exploring the power behind rich text

Exploring the power behind rich text

Branch: richtextmarkdown

Introduction

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.

Rich Text with Markdown

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

Activity

  1. In about-us.jsonc, change the text in tab-list.item#home1 so that an "About" appears in the first tab;

  2. 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.
    
  3. Insert the title and subtitle in bold.

Expected result:

ℹ️ Remember to access the Rich Text documentation if you have any questions during the activity.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Finishing your pdp

Finishing your pdp

Branch: pdp3

Introduction

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.

image

Stack Layout

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).

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.

Activity

Develop the product page by adding the step below to product.jsonc:

  1. Declare a shelf.relatedProducts under the product's main line

    "store.product": {
      "children": [
        "breadcrumb",
        "flex-layout.row#main",
        "shelf.relatedProducts"
      ]
    }

⚠️ Remember, this product shelf is only displayed for the /3-colors-retro-stand-mixer/p product.

  1. From the left column, change product-images with a stack-layout declaration;

    "flex-layout.col#left": {
      "children": [
        "stack-layout#brand"
      ]
    }
  2. Define stack-layout and set product-images and product-brand as children;

    "stack-layout#brand": {
      "children": [
        "product-images",
        "product-brand"
      ]
    }
  3. 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.

  4. Review the documentation to make the sku-selector do the following:

  • start without any selected SKU;
  • show the name by SKU variation, using property value as image, as it's shown in the documentation mentioned before;
  • display an error message if no SKU variation was selected.

ℹ️ 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.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Adjusting the search page's layout

Adjusting the search page's layout

Branch: search2

Introduction

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.

Activity

image

  1. In the search.jsonc file, remove total-products.v2 and order-by.v2 from search-result-layout.desktop.

  2. Replace both with a line that includes the removed blocks:

    ...
    "flex-layout.row#top": {
      "children": [
        "total-products.v2",
        "order-by.v2"
      ]
    }
    ...
  3. Remove search-content and filter-navigator.v3 from search-result-layout.desktop and create a results line;

  4. 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"
        ]
      },
      ...
    }
  5. Set the filter column's width prop to 20%.

  6. 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.

  7. Define your search-content with the gallery and not-found blocks:

    {
      ...
      "search-content": {
        "blocks": ["gallery", "not-found"]
      }
      ...
    }
  8. Use product-summary.shelf in the Gallery's props:

    {
      ...
      "search-content": {
        "blocks": ["gallery", "not-found"]
      },
      "gallery": {
        "blocks": ["product-summary.shelf"]
      }
      ...
    }
  9. 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.


🚫 Are you lost?

Is there any problem with this step? What about sending us a feedback? 🙏

Submit feedback


If you're still unsure as to how to send your answers, click here.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.