This is part two in our series on how to create a JAMStack e-commerce site with Nuxt 3, Strapi 4 and Snipcart. We will build out the site’s structure, layout and any components we need in the process.
Well, fancy seeing you here, either you've accidentally stumbled across this Wahay, it looks like you've made it to the second blog post of the series, well I never, thank you ever so much for joining again. Alternatively you might have accidentally stumbled here, if that's the case and you're intrigued by what you've seen then you can skip back to the previous blog post and start building your very own candle shop 😉.
In the last blog post we set up Strapi 4- we created a collection type and added in some products, made them public so we can get them from the Nuxt 3 frontend.
We will build out the site's structure, layout, and some of the components needed during this blog post. Then, in the next blog post, we will pull through the products, create components for them, and build out more of the site.
You can watch the video or follow along below.
Here's a reminder of the code if you would like to dive straight into it, we have created example repositories for both the Nuxt and Strapi parts:
To get started today we're going to add in an .env file we're doing this so that we can easily change the API URL in one place, then when we deploy it we can easily change it to the production endpoint.
BASH
API_URL=http://localhost:1337/
Adding in environment variables in Nuxt 3
Also we need to update the nuxt.config.ts. Any environment variable we want to use in our frontend Vue code you have to tell Nuxt to expose. You do this by adding it to the publicRuntimeConfig object, like below:
So open up the terminal and get the frontend and backend running.
Next let's start working through the designs and building out each section, first we'll build out the layout and within this, there will be the header, main and footer sections.
Create a directory called layouts with a file called default.vue in it, this will be your default layout template. If you're familiar with Nuxt 2 then this won't look much different. The content from the index.vue page will come out in the slot here. Here we're just setting the default fonts and background colours with the Tailwind theme classes.
The -webkit-font-smoothing changes the rendering of the font to make it match the design
JAVASCRIPT
<template><div class="relative font-body"><div class="pt-24 bg-brand-beige-300"><slot /></div></div></template><style scoped>
body {-webkit-font-smoothing: antialiased;}</style>
Next we are going to build out the header component, which will be made up from a number of child components. There's a few elements that will look something like this:
Header
Logo icon
Desktop Menu
Cart Price
Cart icon
Mobile menu
Let's create a component for our logo, first create a directory in the root called components, then a file called logo.vue :
Now let’s build out the desktop navigation, they aren't going to link yet because that will break the site. Create a file called NavBar.vue in the components directory.
We now need to create the CartInfo.vue component , in the next post we will be adding in the cart total but for now we're just going to have the icon in there.
In the HeaderSection.vue we can now import the components that we built earlier. The way that I would usually do this is by adding in 1 by 1 at a time and just go check the frontend to check everything is okay. But for ease I've just added them all in straight away:
You'll see here you don't need to import components and declare them like you used to. Nuxt 3 auto imports components for you. Which makes components quicker to write, less crowded and easier to read. If you have your component inside a nested directory like this :
Then the name of the component inside your template will be named like this <IconsCart />.
Let's go and check everything looks as it should:
Before we move on we're going to add in the mobile menu. Add in a new file into the components directory called MobileMenu.vue
useRoute allows us to get the current route and the defineEmits basically tells the component that it can emit an event called close, then we use the watch API to emit the close event whenever the route changes. The mobile menu will close when you change routes.
Next, we are going to update our HeaderSection.vue to pull in the MobileMenu.vue, add some transitions to it and hide the desktop menu. So open up your HeaderSection.vue and your code should now look like this:
Now let's just go and tidy up the app.vue , add in the background colour and add a meta title.
JAVASCRIPT
<template><Title>Pick a Sick Wick - Candle Shop</Title><NuxtPage /></template><style>
body {
@apply text-brand-grey bg-brand-beige-300;}</style>
Nuxt 3 Meta components
It's now really easy to add in a meta title and other meta elements in Nuxt 3, thye have made a number of conponents that oyu can use in other components and it will add to your pages meta. In this case we're just using the title component to add a title to our site.
Wooo we're in a good place to start building out the rest of the site. Lets start adding a few components that are useful in any site.
Creating a heading component
Adding a heading component like this means you all your headings will match your design system perfectly. So lets go ahead and create our heading.vue inside the components directory.
This is handy for keeping all heading styles consistent, and means you only have to change them in 1 place rather than multiple.
If you're using the <script setup> you create your props by using the defineProps function.
Container component
We normally create a Container component in any site. It helps us consistently size, horizontally centre and add padding to its children. Lets add that into the components directory and should look like this:
Every project needs a button component, so let's go ahead and add that with it's two different styles. We pass in a theme prop that then is used to choose the set of classes that should be applied using a computed property. Here we will have multiple classes that apply to each of the button themes.
Right! Time to build out the footer, create a file in your components directory called footer.vue that will look something like this:
JAVASCRIPT
<template><footer class="py-12 text-white bg-brand-grey-800"><Container class="grid grid-cols-12 gap-6"><div class="col-span-12 md:col-span-6"><img :src="LogoWhite"class="w-32" alt="Pick a Sick Wick"/><p
class="py-4 md:w-4/5">Pick a Sick Wick is a JAMStack demo site built with Nuxt 3, Strapi 4 and Snipcart. If you are interested in how it was built, find out more here: JAMStack E-commerce with Nuxt 3, Strapi 4, and Snipcart.</p></div><div class="col-span-12 md:col-span-3"><Heading tag="h4" font-style="h4" color="text-white">Menu</Heading><ul><li class="underline list-disc list-inside"><nuxt-link to="/">Home</nuxt-link></li><li class="underline list-disc list-inside"><nuxt-link to="/">About</nuxt-link></li><li class="underline list-disc list-inside"><nuxt-link to="/shop">Shop</nuxt-link></li><li class="underline list-disc list-inside"><nuxt-link to="/contact">Contact</nuxt-link></li></ul></div><div class="col-span-12 md:col-span-3"><Heading tag="h4" font-style="h4" color="text-white">Contact</Heading><p>The Wick Factory,</p><p>Flame Lane,</p><p>Waxiton,</p><p>BN15TB</p><p>United Kingdom</p></div></Container></footer></template><script setup>// We have to import images like this because Nuxt build doesn't incude them otherwsieimport LogoWhite from'assets/images/logo-white.svg';</script>
Lets import them into the layout and check they're working, your default.vue should look something like this
Let's go update the juicy parts of the site, the main content. First we're going
Add a couple of new directories assets/images into the route of the director. Inside this we need to add in our main image that's going to sit at the top of the homepage.
Next update the index.vue
JAVASCRIPT
<template><div><section class="relative mb-20 -mt-24 border-b-4 md:mb-10 header border-brand-beige"><div class="absolute inset-0 z-0 overflow-hidden"><img :src="HeaderBg"class="object-cover w-full h-full" alt="Pick a sick wick"/></div><div class="relative z-20 h-full header-content"><div class="absolute flex flex-col justify-center p-8 mx-auto hero-box"><div class="relative px-6 py-8 bg-white rounded-lg drop-shadow-2xl"><Heading tag="h3" font-style="h3">Smelly candles</Heading><Heading tag="h2" font-style="h2">Only the sickest wicks</Heading><p class="pb-4 pr-4 text-brand-gray font-body">
If you’re like us and can’t get enough of burning
things in your own home, pick a sick wick and
<span
class="font-bold">feed your burning habbit safely with added benifit of smelling delicious.</span></p><Btn class="absolute md:-right-3 md:-bottom-3">Shop Now</Btn></div></div></div></section><section class="mb-28"><Container><div class="w-full mx-auto mb-12 text-center md:w-2/3 lg:w-1/3"><Heading tag="h2" font-style="h3">Our Candles</Heading><Heading tag="h3" font-style="h2"class="mb-2">Show me the sick wicks</Heading><p>All our candles our hand made and 100% verified to satisfy any pyromaniac’s itch to burn things in a safe way.</p></div><div class="flex justify-center mt-10"><Btn theme="secondary">View all the sick wicks</Btn></div></Container></section></div></template><script setup>//We we're having issues with Nuxt importing images into this template but this work around fixes thingsimport HeaderBg from'assets/images/header-bg.jpg';</script><style scoped>.header {
height:600px;}
@screen md {.hero-box {
left:10%;
top:175px;
width:485px;}}
@screen md {.header {
height:700px;}}
@screen md {.home-head-image {
top:-110px;
height:770px;
width:100%;}}.hero-box {
bottom:-50px;
left:0px;
width:100%;}
@screen md {.hero-box {
left:10%;
top:100px;
width:485px;}}</style>
Okay great, you should now have something that looks like this now
Yayyy! One step closer to getting that shop of yours set up. That's the end of this tutorial, we hope it's been helpful and you've got a lot from it, if you have any questions feel free to get in touch and ask any more questions via our website or Twitter. Thanks for taking the time to read it. The next one is going to be about getting the products in from Strapi and it will be out very shortly. You can also subscribe to our newsletter on the right hand side of the page.
Creating an internationalised site with Strapi and Nuxt
We were really excited when Strapi released a new update a few weeks ago that included internationalisation! This post will show you the basics of creating an internationalised site using Strapi and Nuxt.
Dynamic social images with Nuxt, Cloud Functions and Cloudinary
Every little helps when trying to get your content noticed on social media, and having an eye-catching sharing image could be the difference between getting someone passing you by or someone clicking through.
This post will guide you by creating dynamic social sharing images unique to each page/post using Firebase cloud functions, Cloudinary and Nuxt.