Simply copy and paste the following command line in your terminal to create your first Strapi project.
npx create-strapi-app
my-project
E-commerce websites have become increasingly popular due to their convenience and accessibility. They allow users to buy goods over the internet and have them delivered. In this tutorial, you will learn how to build an e-commerce website using SvelteKit and Strapi CMS.
To follow along with this tutorial, ensure you meet the following criteria:
To get started, let’s create a new Strapi project that will serve as the application backend. To do that, open your terminal, navigate to the directory where you want to install the project and run the command below.
npx create-strapi-app@latest my-project --quickstart
After the project installation is completed, the application development server will start automatically. When you open the application in your browser, you will be required to create a new account.
After creating a new Strapi application account, you will be redirected to the application dashboard, as shown in the screenshot below.
Now, let’s create the Collection Types that define how the application's data is structured and managed. We will create the userInfo
, Product
, and cartItem
collection types by following the steps below.
userInfo
Collection Type**userInfo
as the display name, and click on the "continue" button as shown in the screenshot below.Next, let’s structure how data will be managed in the userInfo
collection type by adding the following fields:
fullname
: type → textemail
: type → Emailpassword
: type → TextAfter adding the fields above, click the "Save" button, as shown in the screenshot below.
Repeat the above steps to create the following collection types.
Create a collection type named product
and add the following fields:
productName
: type→textproductDescription
: type→textproductImage
: type→ multiple mediaproductPrice
: type→textCreate a collection type named cartItem
and add the following fields:
userID
: type→textproductID
: type→textWe need to enable public access for each to interact with the created collection types via an API call. To do this, navigate to Settings → Roles → Public from your Strapi side menu and select all operations for each collection type.
Before we proceed to the frontend, let’s add items to the Product collection type. To do this, navigate to the Content Manager from the side menu and click on the Product collection type. Then, add as many products as you like, as shown in the screenshot below.
Now, let’s start creating the application frontend using SvelteKit. To scaffold a new SvelteKit project, run the command below.
npx degit sveltejs/template my-ecommerce-app
cd my-ecommerce-app
npm install
In this tutorial, we will use the Svelte-routing library to handle the application's page navigation. To install the library, run the command below:
npm install svelte-routing
After the installation, open the project in your preferred code editor or IDE.
Now, let’s start creating the application functionalities and UI, such as the user authentication page, home page, and cart page. To create the application, follow the steps below.
The application's home page will display a list of all available products in the store for users to browse. To create this home page, navigate to the src
folder in your project's root directory and create a new folder named Components
to store the application’s component files. Inside the Components
folder, create a file named Home.svelte
and add the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
<!-- Home.svelte -->
<script>
import { onMount } from "svelte";
import { Link } from "svelte-routing";
import Navbar from "./Navbar.svelte";
let products = [];
onMount(async () => {
try {
const response = await fetch(
"http://localhost:1337/api/products?populate=*",
);
const data = await response.json();
products = data.data.map((item) => ({
id: item.id,
name: item.attributes.productName,
description: item.attributes.productDescription,
price: parseFloat(item.attributes.productPrice),
imageUrl: item.attributes.productImage.data[0].attributes.url,
}));
} catch (error) {
console.error("Error fetching products:", error);
}
});
</script>
<Navbar />
<main>
<h1>Main Store</h1>
<div class="products">
{#each products as product}
<div class="product-card">
<img
src={`http://localhost:1337${product.imageUrl}`}
alt={product.name}
/>
<div class="details">
<h2>{product.name}</h2>
<p>{product.description}</p>
<p class="price">${product.price.toFixed(2)}</p>
<Link to={`/product/${product.id}`}>
<button>View Product</button>
</Link>
</div>
</div>
{/each}
</div>
</main>
<style>
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow-x: hidden;
}
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
}
nav {
background-color: #71b3bf;
color: white;
padding: 1em 0;
width: 100%;
box-sizing: border-box;
}
.nav-container {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 2em;
max-width: 1200px;
margin: 0 auto;
}
.nav-brand a {
color: white;
text-decoration: none;
font-size: 1.5em;
font-weight: bold;
}
.nav-links {
display: flex;
gap: 1em;
}
.nav-links a {
color: white;
text-decoration: none;
font-size: 1em;
}
.nav-links a:hover {
text-decoration: underline;
}
main {
padding: 2em;
width: 100%;
box-sizing: border-box;
flex: 1;
}
h1 {
color: #ff3e00;
text-transform: uppercase;
font-size: 2.5em;
font-weight: 300;
margin-bottom: 1em;
}
.products {
display: flex;
flex-wrap: wrap;
gap: 2em;
justify-content: center;
}
.product-card {
background: #fff;
border: 1px solid #ddd;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
overflow: hidden;
flex: 1 1 calc(33.333% - 2em);
max-width: calc(33.333% - 2em);
transition: transform 0.2s;
box-sizing: border-box;
}
.product-card:hover {
transform: scale(1.05);
}
.product-card img {
width: 100%;
height: 200px;
object-fit: cover;
}
.details {
padding: 1em;
text-align: left;
}
.details h2 {
margin: 0 0 0.5em;
font-size: 1.5em;
color: #333;
}
.details p {
margin: 0;
color: #666;
}
.price {
margin-top: 0.5em;
font-size: 1.2em;
font-weight: bold;
color: #ff3e00;
padding-top: 10px;
}
button {
background-color: transparent;
color: #71b3bf;
border: 1px solid #71b3bf;
padding: 0.75em 1.5em;
border-radius: 5px;
cursor: pointer;
font-size: 1em;
transition: background-color 0.3s;
margin-left: 30%;
margin-top: 25px;
}
button:hover {
background-color: #71b3bf;
color: white;
border: none;
}
@media (max-width: 768px) {
.product-card {
flex: 1 1 calc(50% - 2em);
max-width: calc(50% - 2em);
}
}
@media (max-width: 480px) {
.product-card {
flex: 1 1 100%;
max-width: 100%;
}
}
</style>
In the above code, the onMount
method fetches all the available products from the backend by making a GET
request to http://localhost:1337/api/products?populate=*
. The products are then rendered in the user interface inside the main component.
Here is what the home page looks like:
To create the registration page, in the src/Components
directory, create a file named Register.svelte
and add the following code to it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<!-- Register.svelte -->
<script>
import { createEventDispatcher } from "svelte";
import { navigate } from "svelte-routing";
let email = "";
let fullname = "";
let password = "";
const dispatch = createEventDispatcher();
const handleRegister = async () => {
try {
const checkResponse = await fetch(
`http://localhost:1337/api/user-infos?filters[email][$eq]=${email}`,
);
if (!checkResponse.ok) {
throw new Error("Error checking user registration status");
}
const existingUsers = await checkResponse.json();
if (existingUsers.data.length > 0) {
alert("User with this email is already registered");
return;
}
const response = await fetch("http://localhost:1337/api/user-infos", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
data: {
email: email,
fullname: fullname,
password: password,
},
}),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error.message || "Registration failed");
}
alert(`Registered successfully.`);
navigate(`/login`);
} catch (error) {
alert(`Error: ${error.message}`);
}
};
const handleLoginLinkClick = () => {
navigate(`/login`);
};
</script>
<main>
<h1>Register</h1>
<form on:submit|preventDefault={handleRegister}>
<label>
Fullname:
<input type="text" bind:value={fullname} required>
</label>
<label>
Email:
<input type="email" bind:value={email} required>
</label>
<label>
Password:
<input type="password" bind:value={password} required>
</label>
<button type="submit">Register</button>
</form>
<p>Already have an account? <a href="login" on:click|preventDefault={handleLoginLinkClick}>Login</a></p>
</main>
<style>
main {
text-align: center;
padding: 1em;
max-width: 240px;
margin: 0 auto;
}
h1 {
color: #ff3e00;
text-transform: uppercase;
font-size: 2em;
font-weight: 100;
}
label {
display: block;
margin: 0.5em 0;
}
input {
width: 100%;
padding: 0.5em;
margin: 0.5em 0;
}
button {
padding: 0.5em 1em;
background-color: #ff3e00;
color: white;
border: none;
cursor: pointer;
}
button:hover {
background-color: #e63600;
}
p {
margin-top: 1em;
}
a {
color: #ff3e00;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>
From the code above, we create a registration form that accepts the user's information as input and stores it in the Strapi backend via an API call. Once the registration is successful, the user is redirected to the login page.
Below is what the registration page looks like:
To create the login page, create a file named Login.svelte
inside the Components
folder and add the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
<!-- Login.svelte -->
<script>
import { createEventDispatcher } from "svelte";
import { navigate } from "svelte-routing";
let email = "";
let password = "";
let userId = "";
const dispatch = createEventDispatcher();
const handleLogin = async () => {
try {
const response = await fetch(
`http://localhost:1337/api/user-infos?filters[email][$eq]=${email}`,
);
if (!response.ok) {
throw new Error("Error checking user login status");
}
const data = await response.json();
if (data.data.length === 0) {
alert("User not found");
return;
}
const user = data.data[0].attributes;
if (user.password !== password) {
alert("Incorrect password");
return;
}
alert(`Logged in successfully`);
navigate(`/`);
document.cookie = `email=${user.email}; path=/; max-age=${7 * 24 * 60 * 60}`;
document.cookie = `fullname=${user.fullname}; path=/; max-age=${7 * 24 * 60 * 60}`;
document.cookie = `userId=${data.data[0].id}; path=/; max-age=${7 * 24 * 60 * 60}`;
} catch (error) {
alert(`Error: ${error.message}`);
}
};
const handleRegisterLinkClick = () => {
navigate(`/register`);
};
</script>
<main>
<h1>Login</h1>
<form on:submit|preventDefault={handleLogin}>
<label>
Email:
<input type="email" bind:value={email} required>
</label>
<label>
Password:
<input type="password" bind:value={password} required>
</label>
<button type="submit">Login</button>
</form>
<p>Don't have an account? <a href="#" on:click={handleRegisterLinkClick}>Register</a></p>
</main>
<style>
main {
text-align: center;
padding: 1em;
max-width: 240px;
margin: 0 auto;
}
h1 {
color: #ff3e00;
text-transform: uppercase;
font-size: 2em;
font-weight: 100;
}
label {
display: block;
margin: 0.5em 0;
}
input {
width: 100%;
padding: 0.5em;
margin: 0.5em 0;
}
button {
padding: 0.5em 1em;
background-color: #ff3e00;
color: white;
border: none;
cursor: pointer;
}
button:hover {
background-color: #e63600;
}
p {
margin-top: 1em;
}
a {
color: #ff3e00;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>
In the code above, we create a login form that accepts the user's email and password as input. If the login details are correct, the user's details are stored in cookies; otherwise, a login error is displayed for the user.
Here is what the login page looks like:
Now, let’s create the product preview page showing more details about each product. To do this, create a file named Product.svelte
inside the Components
folder and add the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
<!-- Product.svelte -->
<script>
import { onMount } from "svelte";
import { Link, navigate } from "svelte-routing";
import Navbar from "./Navbar.svelte";
export let id;
let product = null;
let userId = getCookie("userId");
let successMessage = "";
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(";").shift();
}
onMount(async () => {
if (!userId) {
navigate("/login");
} else {
try {
const response = await fetch(
`http://localhost:1337/api/products/${id}?populate=*`,
);
const data = await response.json();
const attributes = data.data.attributes;
const imageUrl = attributes.productImage.data[0].attributes.url;
product = {
id: data.data.id,
name: attributes.productName,
description: attributes.productDescription,
price: parseFloat(attributes.productPrice),
imageUrl: `http://localhost:1337${imageUrl}`,
};
} catch (error) {
console.error("Error fetching product:", error);
}
}
});
const addToCart = async () => {
try {
const response = await fetch(`http://localhost:1337/api/cart-items`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
data: {
userID: userId,
productID: id,
},
}),
});
if (!response.ok) {
throw new Error(response);
}
successMessage = "Product added to cart successfully!";
} catch (error) {
console.error("Error adding product to cart:", error);
}
};
</script>
<Navbar />
<main>
{#if product}
<div class="product-container">
<img src={product.imageUrl} alt={product.name} />
<div class="product-details">
<h1>{product.name}</h1>
<p>{product.description}</p>
<p class="price">${product.price.toFixed(2)}</p>
<button on:click={addToCart}>Add to Cart</button>
{#if successMessage}
<p class="success-message">{successMessage}</p>
<p><Link to="/cart/w">View Cart</Link></p>
{/if}
<p><Link to="/">Back to Home</Link></p>
</div>
</div>
{:else}
<p>Product not found</p>
{/if}
</main>
<style>
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow-x: hidden;
font-family: Arial, sans-serif;
}
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
main {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 2em;
background-color: #f9f9f9;
}
.product-container {
display: flex;
flex-direction: column;
align-items: center;
background: #fff;
border: 1px solid #ddd;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
overflow: hidden;
max-width: 600px;
width: 100%;
box-sizing: border-box;
padding: 2em;
}
.product-container img {
width: 50%;
height: auto;
border-bottom: 1px solid #ddd;
margin-bottom: 1em;
}
.product-details {
text-align: center;
}
h1 {
color: #ff3e00;
text-transform: uppercase;
font-size: 2em;
font-weight: 300;
margin: 0 0 1em;
}
p {
font-size: 1em;
color: #666;
margin: 0 0 1em;
}
.price {
font-size: 1.5em;
font-weight: bold;
color: #ff3e00;
margin: 0.5em 0;
}
button {
background-color: #ff3e00;
color: white;
border: none;
padding: 0.75em 1.5em;
border-radius: 5px;
cursor: pointer;
font-size: 1em;
transition: background-color 0.3s;
}
button:hover {
background-color: #e03500;
}
.success-message {
color: green;
font-weight: bold;
margin-top: 1em;
}
a {
color: #ff3e00;
text-decoration: none;
font-size: 1em;
}
a:hover {
text-decoration: underline;
}
</style>
From the code above, we fetch the details of a product from the Strapi endpoint using the product ID and render the product details, allowing the user to add the product to the cart.
From the image below, we can see the details of a product.
To create the cart page, create a file named Cart.svelte
and add the following code to it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
<script>
import { onMount } from "svelte";
import { navigate } from "svelte-routing";
import { Link } from "svelte-routing";
import Navbar from "./Navbar.svelte";
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(";").shift();
}
let userId = getCookie("userId");
let cart = [];
let message = "";
const fetchCartItems = async () => {
try {
const cartResponse = await fetch(`http://localhost:1337/api/cart-items`);
const cartData = await cartResponse.json();
const userCartItems = cartData.data.filter(
(item) => item.attributes.userID === userId,
);
const products = await Promise.all(
userCartItems.map(async (item) => {
const productResponse = await fetch(
`http://localhost:1337/api/products/${item.attributes.productID}?populate=*`,
);
const productData = await productResponse.json();
const attributes = productData.data.attributes;
const imageUrl = attributes.productImage.data[0].attributes.url;
return {
id: productData.data.id,
item_id: item.id,
name: attributes.productName,
description: attributes.productDescription,
price: parseFloat(attributes.productPrice),
imageUrl: `http://localhost:1337${imageUrl}`,
};
}),
);
cart = products;
} catch (error) {
console.error("Error fetching cart items:", error);
}
};
const deleteItem = async (cartItemId) => {
try {
const response = await fetch(
`http://localhost:1337/api/cart-items/${cartItemId}`,
{
method: "DELETE",
},
);
if (response.ok) {
console.log(`Item ${cartItemId} deleted successfully.`);
cart = cart.filter((product) => product.item_id !== cartItemId);
message = "Item removed successfully!";
setTimeout(() => (message = ""), 3000);
} else {
console.error(`Failed to delete item ${cartItemId}.`);
message = "Failed to remove item.";
setTimeout(() => (message = ""), 3000);
}
} catch (error) {
console.error("Error deleting item:", error);
message = "Error removing item.";
setTimeout(() => (message = ""), 3000);
}
};
onMount(() => {
if (!userId) {
navigate("/login");
} else {
fetchCartItems();
}
});
const handlePurchase = () => {
alert("You will be redirected to a payment gateway");
navigate("/");
};
$: totalPrice = cart
.reduce((total, product) => total + product.price, 0)
.toFixed(2);
</script>
<Navbar />
<main>
{#if cart.length > 0}
<div class="checkout-container">
<h1>Cart</h1>
<ul class="product-list">
{#if message}
<div class="message">{message}</div>
{/if}
{#each cart as product}
<li class="product-item">
<img src={product.imageUrl} alt={product.name} />
<div class="product-details">
<p><strong>{product.name}</strong></p>
<p>{product.description}</p>
<p>Price: ${product.price.toFixed(2)}</p>
</div>
<button
class="delete-button"
on:click={() => deleteItem(product.item_id)}>Remove</button
>
</li>
{/each}
</ul>
<div class="total-price">
<p><strong>Total Price: ${totalPrice}</strong></p>
</div>
<button on:click={handlePurchase}>Check Out</button>
<p><Link to="/">Back to Home</Link></p>
</div>
{:else}
<p>Your cart is empty</p>
{/if}
</main>
<style>
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow-x: hidden;
font-family: Arial, sans-serif;
}
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
main {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 2em;
background-color: #f9f9f9;
}
.checkout-container {
display: flex;
flex-direction: column;
align-items: center;
background: #fff;
border: 1px solid #ddd;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
padding: 2em;
max-width: 600px;
width: 100%;
box-sizing: border-box;
}
.checkout-container h1 {
color: #ff3e00;
text-transform: uppercase;
font-size: 2em;
font-weight: 300;
margin: 0 0 1em;
}
.product-list {
list-style: none;
padding: 0;
margin: 0 0 2em;
width: 100%;
}
.product-item {
display: flex;
align-items: center;
border-bottom: 1px solid #ddd;
padding: 1em 0;
}
.product-item img {
width: 150px;
height: auto;
margin-right: 1em;
border-radius: 5px;
}
.product-details {
flex-grow: 1;
}
.product-details p {
margin: 0.5em 0;
font-size: 1em;
color: #666;
}
.total-price {
font-size: 1.2em;
font-weight: bold;
margin-bottom: 1em;
}
button {
background-color: #ff3e00;
color: white;
border: none;
padding: 0.75em 1.5em;
border-radius: 5px;
cursor: pointer;
font-size: 1em;
transition: background-color 0.3s;
margin-bottom: 1em;
}
button:hover {
background-color: #e03500;
}
a {
color: #ff3e00;
text-decoration: none;
font-size: 1em;
}
a:hover {
text-decoration: underline;
}
.delete-button {
background-color: #e03500;
color: white;
border: none;
padding: 0.5em 1em;
border-radius: 5px;
cursor: pointer;
font-size: 0.9em;
transition: background-color 0.3s;
margin-left: 1em;
}
.delete-button:hover {
background-color: #d02e00;
}
.message {
background-color: #dff0d8;
color: #3c763d;
padding: 1em;
border-radius: 5px;
margin-bottom: 1em;
font-size: 1em;
text-align: center;
width: 100%;
max-width: 600px;
}
</style>
From the code above, we fetch all the products in the cart and display them on the page. We also calculate the total price by summing up the prices of all the products in the cart.
Here is a demo of how the cart functionality works.
To wrap up the application, let’s create the application navbar component. Inside the Components
folder, create a file named Navbar.svelte
and add the following code to it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<script>
import { Link, navigate } from "svelte-routing";
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(";").shift();
}
const email = getCookie("email");
const fullname = getCookie("fullname");
const userId = getCookie("userId");
const handleLogout = () => {
document.cookie = "email=; path=/; max-age=0";
document.cookie = "fullname=; path=/; max-age=0";
document.cookie = "userId=; path=/; max-age=0";
navigate("/login");
};
</script>
<nav>
<div class="nav-container">
<div class="nav-brand">
<Link to="/">My Store</Link>
</div>
<div class="nav-links">
<Link to="/">Home</Link>
{#if email}
<span>Welcome, {fullname}</span>
<Link to="/cart/w"><span class="meun">Cart</span></Link>
<a href="#" on:click|preventDefault={handleLogout}>Logout</a>
{:else}
<Link to="/login">Login</Link>
<Link to="/register">Register</Link>
{/if}
</div>
</div>
</nav>
<style>
nav {
background-color: #71b3bf;
color: white;
padding: 1em 0;
width: 100%;
box-sizing: border-box;
}
.nav-container {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 2em;
max-width: 1200px;
margin: 0 auto;
}
.nav-brand a {
color: white;
text-decoration: none;
font-size: 1.5em;
font-weight: bold;
}
.nav-links {
display: flex;
gap: 1em;
}
.nav-links a,
.nav-links span {
color: white;
text-decoration: none;
font-size: 1em;
}
.nav-links span {
font-size: 1em;
}
.meun {
padding: 15px;
}
.meun:hover {
background-color: #71b3bf;
}
</style>
Here is a demo of our Cart functionality.
Next, let’s configure the application route. Inside the src
folder, open the App.svelte
file and replace its code with the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!-- App.svelte -->
<script>
import { Router, Link, Route } from "svelte-routing";
import Home from "./Components/Home.svelte";
import Login from "./Components/Login.svelte";
import Register from "./Components/Register.svelte";
import Product from "./Components/Product.svelte";
import Cart from "./Components/Cart.svelte";
</script>
<main>
<Router>
<Route path="/" component="{Home}" />
<Route path="login" component="{Login}" />
<Route path="register" component="{Register}" />
<Route path="product/:id" component="{Product}" />
<Route path="cart/:id" component="{Cart}" />
</Router>
</main>
<style>
main {
text-align: center;
padding: 1em;
max-width: 100%;
margin: 0 auto;
}
</style>
Start the Svelte development server by running the command below in your terminal to test the application.
npm run dev
Next, open your browser and go to http://localhost:8080. You should see the application functioning as shown in the GIF image below.
In this tutorial, we learned the complete process, from setting up the backend with Strapi to developing the frontend with SvelteKit to create an e-commerce website.
Building an e-commerce website with SvelteKit and Strapi CMS offers a powerful and flexible solution for creating dynamic and responsive online stores.