21
loading...
This website collects cookies to deliver better user experience
npm init @vitejs/app
cd *your project name*
npm install
npm run dev
npm install @supabase/supabase-js
ANON KEY
& API URL
from the Supabase dashboard & then create the .env
file and paste your keys as I have done below.VITE_SUPABASE_URL=YOUR SUPABASE URL
VITE_SUPABASE_ANON_KEY=YOUR SUPABASE ANON KEY
supabase.js
file in your project's directory and add the following configurations.import { createClient } from "@supabase/supabase-js";
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
styles.css
file. The code is from John's Smilga JavaScript Course.@import url("https://fonts.googleapis.com/css?family=Open+Sans|Roboto:400,700&display=swap");
:root {
--clr-primary-8: hsl(205, 86%, 81%);
--clr-grey-5: hsl(210, 22%, 49%);
--clr-grey-10: hsl(210, 36%, 96%);
--clr-white: #fff;
--clr-red-dark: hsl(360, 67%, 44%);
--clr-red-light: hsl(360, 71%, 66%);
--ff-primary: "Roboto", sans-serif;
--ff-secondary: "Open Sans", sans-serif;
--transition: all 0.3s linear;
--spacing: 0.25rem;
--radius: 0.5rem;
--light-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
--dark-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
*,
::after,
::before {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: var(--ff-secondary);
background: var(--clr-grey-10);
color: var(--clr-grey-1);
line-height: 1.5;
font-size: 0.875rem;
}
h3 {
letter-spacing: var(--spacing);
text-transform: capitalize;
line-height: 1.25;
margin-bottom: 0.75rem;
font-family: var(--ff-primary);
}
h3 {
font-size: 1.25rem;
}
.section-center {
width: 90vw;
margin: 0 auto;
max-width: 35rem;
margin-top: 8rem;
}
@media screen and (min-width: 992px) {
.section-center {
width: 95vw;
}
}
.section-center {
background: var(--clr-white);
border-radius: var(--radius);
box-shadow: var(--light-shadow);
transition: var(--transition);
padding: 2rem;
}
.section-center:hover {
box-shadow: var(--dark-shadow);
}
.grocery-form h3 {
color: var(--clr-primary-1);
margin-bottom: 1.5rem;
text-align: center;
}
.form-control {
display: flex;
justify-content: center;
}
#grocery {
padding: 0.25rem;
padding-left: 1rem;
background: var(--clr-grey-10);
border-top-left-radius: var(--radius);
border-bottom-left-radius: var(--radius);
border-color: transparent;
font-size: 1rem;
flex: 1 0 auto;
color: var(--clr-grey-5);
}
#grocery::placeholder {
font-family: var(--ff-secondary);
color: var(--clr-grey-5);
}
.submit-btn {
background: var(--clr-primary-8);
border-color: transparent;
flex: 0 0 5rem;
display: grid;
align-items: center;
padding: 0.25rem;
text-transform: capitalize;
letter-spacing: 2px;
border-top-right-radius: var(--radius);
border-bottom-right-radius: var(--radius);
cursor: pointer;
content: var(--clr-primary-5);
transition: var(--transition);
font-size: 0.85rem;
}
.submit-btn:hover {
background: var(--clr-primary-5);
color: var(--clr-white);
}
.grocery-container {
margin-top: 2rem;
transition: var(--transition);
}
.grocery-item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 0.5rem;
transition: var(--transition);
padding: 0.25rem 1rem;
border-radius: var(--radius);
text-transform: capitalize;
}
.grocery-item:hover {
color: var(--clr-grey-5);
background: var(--clr-grey-10);
}
.grocery-item:hover .title {
color: var(--clr-grey-5);
}
.title {
margin-bottom: 0;
color: var(--clr-grey-1);
letter-spacing: 2px;
transition: var(--transition);
}
.delete-btn {
background: transparent;
border-color: transparent;
cursor: pointer;
font-size: 0.7rem;
margin: 0 0.15rem;
transition: var(--transition);
}
.delete-btn {
color: var(--clr-red-light);
}
.delete-btn:hover {
color: var(--clr-red-dark);
}
.clear-btn {
text-transform: capitalize;
width: 10rem;
height: 1.5rem;
display: grid;
align-items: center;
background: transparent;
border-color: transparent;
color: var(--clr-red-light);
margin: 0 auto;
font-size: 0.85rem;
letter-spacing: var(--spacing);
cursor: pointer;
transition: var(--transition);
margin-top: 1.25rem;
}
.clear-btn:hover {
color: var(--clr-red-dark);
}
index.html
file.<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="stylesheet"
href="https://use.fontawesome.com/releases/v5.15.3/css/all.css"
integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk"
crossorigin="anonymous"
/>
<title>Vite App</title>
</head>
<body>
<section class="section-center">
<!-- form -->
<form class="grocery-form" id="groceryForm">
<h3>grocery bud</h3>
<div class="form-control">
<input
type="text"
id="grocery"
autocomplete="off"
placeholder="e.g. eggs"
/>
<button type="submit" class="submit-btn">submit</button>
</div>
</form>
<!-- list -->
<div class="grocery-container">
<div class="grocery-list" id="groceryList"></div>
<button class="clear-btn" id="clearBtn">clear items</button>
</div>
</section>
<!-- JavaScript -->
<script type="module" src="./main.js"></script>
</body>
</html>
name
. It will hold all our grocery names.get groceries()
which will get all the groceries data from Supabase and add it to the frontend whenever the DOMContent is loaded (The first time).import "./style.css";
import { supabase } from "./supabase";
const groceryList = document.getElementById("groceryList");
const getGroceries = async () => {
const { data, error } = await supabase.from("groceries").select(); // getting datas
let html = "";
data.forEach((grocery) => {
html += `
<article class="grocery-item" data-id="${grocery.id}">
<p class="title">${grocery.name}</p>
<div class="btn-container">
<button type="button" class="delete-btn" id="deleteBtn">
<i class="fas fa-trash"></i>
</button>
</div>
</article>
`;
});
groceryList.innerHTML = html;
};
// Event Listeners
window.addEventListener("DOMContentLoaded", getGroceries);
addGroceries()
which will execute as soon as our form is submitted. You can also see in the last line of the function that I have executed getGroceries()
function because if new data is added in Supabase then the function will refresh our data. We could have also used Supabase real-time database but I didn't know how to use it. If you know, please comment below.const groceryForm = document.getElementById("groceryForm");
const grocery = document.getElementById("grocery");
const addGroceries = async (e) => {
e.preventDefault(); // preventing browser from refreshing
const { data, error } = await supabase
.from("groceries")
.insert([{ name: grocery.value }]); // inserting data in supabase
groceryForm.reset(); // resetting form values
getGroceries();
};
groceryForm.addEventListener("submit", addGroceries);
getGroceries()
function I am getting the delete button reference and then iterating all buttons and adding event listeners to it. The event listener calls thedeleteGroceries()
function and first it takes the id of the blog and then deleting it from our Supabase dashboard. And again, we are calling getGroceries()
function to refresh the data.const getGroceries = async () => {
const { data, error } = await supabase.from("groceries").select();
let html = "";
data.forEach((grocery) => {
html += `
<article class="grocery-item" data-id="${grocery.id}">
<p class="title">${grocery.name}</p>
<div class="btn-container">
<button type="button" class="delete-btn" id="deleteBtn">
<i class="fas fa-trash"></i>
</button>
</div>
</article>
`;
});
groceryList.innerHTML = html;
const deleteBtn = document.querySelectorAll("#deleteBtn");
deleteBtn.forEach((btn) => {
btn.addEventListener("click", deleteGroceries);
});
};
const deleteGroceries = async (e) => {
const id =
e.currentTarget.parentElement.parentElement.getAttribute("data-id"); // getting id
const { data, error } = await supabase
.from("groceries")
.delete()
.match({ id: id });
getGroceries();
};
clearGroceries()
function which will simply delete all the data from Supabase.const clearBtn = document.getElementById("clearBtn");
const clearGroceries = async () => {
const { data, error } = await supabase.from("groceries").delete();
getGroceries();
};
clearBtn.addEventListener("click", clearGroceries);