EasySite is a versatile Vue.js and Quasar template designed for creating sleek and intuitive facade websites. It's engineered for simplicity, making it effortless to customize and enhance according to your specific needs.
Watch this site realized with this template
- EasySite - Template Vue.js
- Requisites
- How to use this Template?
- Make it Personal
- Build the app for production
- Extras
- Contributing
Make sure that you have Node.js installed. If not, you can download it from nodejs.org.
After installing Node.js, you can install Vue CLI globally using the following command:
npm install -g @vue/cli
Make sure you have Quasar CLI installed globally. If not, you can install it using npm:
npm install -g @quasar/cli
Refers always to the official documentation of Quasar that you will find on their official website.
Clone this repository to your local machine:
git clone https://github.com/PedemonteGiacomo/EasySite
Now you should navigate to the project directory:
cd EasySite
Inside the project directory, you should install the project dependencies:
npm install
Since we are using Firebase I've created a personal usage of the SendGrid Trigger a simple function calling via API hosted by Firebase functions as discussed later in this guide.
When you run firebase deploy
will instantiate those functions declared in the function/index.js so install the dependencies that those functions need following these steps.
cd functions
npm install
cd ..
To run the Quasar project in development mode, as suggested, users can use the following command:
quasar dev
This will start the development server, and Quasar will automatically open the development server page. If you can see the main page your installation was successful.
Explore the config file to adapt it to fit your needs.
For the moment, I suggest only to change the project name to your one:
builder: {
// https://www.electron.build/configuration/configuration
appId: "quasar-itl", //change with your personal appID
},
To adapt the site to your usage, go change inside the package-lock.json the name of the project:
{
"name": "quasar-itl", // Adapt this to you personal name
"version": "0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "quasar-itl", // Change package managing
...
}
...
}
}
You need to do the same in the package.json file, in the following code:
{
"name": "quasar-itl",
"version": "0.0.1",
"description": "ITL impresa di pulizie web",
"productName": "ITL app",
"author": "Giacomo Pedemonte <[email protected]>",
"private": true,
"scripts": {
"lint": "eslint --ext .js,.vue ./",
"format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\"--ignore-path .gitignore",
"test": "echo \"No test specified\" && exit 0",
"dev": "quasar dev",
"build": "quasar build"
},
...
}
Inside the script tag of IndexPage adapt your web app metadata to your needs:
// all the MetaData that application needs to have like API handlers for G-Analytics and SEO
const metaData = {
// sets document title
title: 'ITL srl impresa di pulizie',
// optional; sets final title as "Index Page - My Website", useful for multiple level meta
titleTemplate: title => `${title} - Genova`,
// meta tags
meta: {
//title: { name: "title", content: 'ITL sas Impresa di pulizie'},
description: { name: 'description', content: 'ITL impresa di pulizie genova, servizi di pulizie' },
keywords: { name: 'keywords', content: 'ITL impresa di pulizi Genova' },
equiv: { 'http-equiv': 'Content-Type', content: 'text/html; charset=UTF-8' },
},
//... other metadata if needed
}
To easily adapt the the icon to you needs just follow the icongenie configuration and setup.
This will generate a brand new icon from a picture that you insert in the path argument.
icongenie generate -m spa -i .\path\to\your\image
ANd then put the code that the command generat and insert it in the index.html file.
<link rel="icon" type="image/png" sizes="128x128" href="icons/favicon-128x128.png">
<link rel="icon" type="image/png" sizes="96x96" href="icons/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png">
<link rel="icon" type="image/ico" href="favicon.ico">
Trustmary is the plugin that is simply used to get Google reviews inside the AboutUsPage by using the following code which is already implemented, you will follow the instruction on Trustmary plugin site to get the correct setup and you need to organize it like the following inside the <script>
tag of the component GoogleReview:
<template>
<div id="trustmary"></div>
</template>
<script>
export default {
mounted() {
// Dynamically add Trustmary script tag to the document
this.addTrustmaryScript();
},
methods: {
addTrustmaryScript() {
// Create script element for Trustmary widget
const script = document.createElement('script');
script.src = 'https://widget.trustmary.com/X6xhp1Y1h';
// Append the script to the document's body or head
//document.body.appendChild(script); // or document.head.appendChild(script);
document.getElementById('trustmary').appendChild(script);
// Initialize Trustmary widget after the script is loaded (might need some delay)
script.onload = () => {
this.initTrustmaryWidget();
};
},
initTrustmaryWidget() {
// Trigger the Trustmary widget creation
// This assumes Trustmary widget has a specific method to initialize it, replace with correct code if needed
window.TrustmaryWidget?.initWidget({
target: '#trustmary-widget', // The element to attach the widget to
// Other configuration options as needed for Trustmary widget initialization
});
},
},
}
</script>
So, to remain simple, the only thing you should take care is to change the code in the following code inside the <script>
tag:
...
// Create script element for Trustmary widget
const script = document.createElement('script');
script.src = 'https://widget.trustmary.com/X6xhp1Y1h';
// CHANGE THIS YOUR OWN CODE OF THE SCRIPT THAT YOU GET FROM TRUSTMARY
...
Than you should simple use the components as usual in the page that you want to insert it without repeating code like the following:
...
<GoogleReviews/>
...
<script>
import AboutUsCarousel from 'src/components/AboutUsCarousel.vue';
import MapComponent from 'src/components/MapComponent.vue';
import CallToActionButton from 'src/components/CallToActionButton.vue';
import GoogleReviews from 'src/components/GoogleReviews.vue';
export default {
components: {
AboutUsCarousel,
MapComponent,
CallToActionButton,
GoogleReviews
},
...
<script/>
Go to Firebase official site and follow the instructions to create a new project and link this project to Firebase. I suggest having a hosting based on Firebase that makes you obtain a development server that is reachable also for possible users.
Change the content of /firebase/index.js with the configuration provided in Firebase after setting your project.
// Your web app's Firebase configuration:
// - follow firebase documentation when you setup your firebase project
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: "YOUR_API_KEY", // this is the key relevant to your project
authDomain: "YOUR_AUTH_DOMAIN", // relevant to your application of your project
databaseURL: "YOUR_DATABASE_URL", // firebase db url (depends on Timezones)
projectId: "YOUR_PROJECT_ID", // project ID
storageBucket: "YOUR_STORAGE_BUCKET", // bucket of your application
messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
appId: "YOUR_APP_ID",
measurementId: "yOUR_MEASUREMENT_ID" // google analytics tag (if needed)
};
Change the name of the project to your own that you configured in Firebase in inside firebaserc:
{
"projects": {
"default": "PUT_YOUR_PROJECT_NAME_THAT_APPEARS_ON_FIREBASE"
}
}
To make available the form usage by the user and your visualization you will need to insert also Firestore Database connection directly in the Firebase console (as done for the hosting and/or for the analytics).
When setting up the Firestore database make sure to modify the content of [firestore.rules that reflect the rules that you can find in the Firebase Firestore dashboard. In the following, we are assuming that all the users can read and write in the db to make people add without auth. permissions to obtain all the appointment requests without limitation.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
So, the Firestore database is used to store the emails received by the users that compile the contact form inside almost all the pages.
So the declaration of the database is made once and is in firebase/index.js:
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
const analytics = firebase.analytics();
analytics.setAnalyticsCollectionEnabled; // set the analytics collection on that tag
//P.S. don't deserve google tag manager if you copy the ga(google-analytics) tag that firebase provide you directly from the dashboard of your project
// Initialize Cloud Firestore and get a reference to the service
const db = firebase.firestore();
export { db }; // extract the db to easily recover it
So, when you need to use the DB you can call it easily in the following way:
import { db } from "../firebase";
In this template site, we use the DB to store the mail received by users in one place with easy access. So, this db is used in the catchingClientComponent, more precisely in this part of the code:
// Your form data
const formData = {
firstName: firstName.value,
lastName: lastName.value,
email: email.value,
phoneNumber: phoneNumber.value,
text: text.value,
};
// Add a new document with a generated id to store the message on firestore
var newMexRef = db.collection("formData").doc
newMexRef.set(formData)
console.log("Document written with ID: ", newMexRef.id);
You can then manage the requests received directly inside your console in Firebase.
This template uses a Google Map template and requesting positions need a simple API key generated by Google. Follow the instructions at this link to the official page.
MapComponent contains Google Maps API usage so change it with your personal API_KEY obtained by Google. Otherwise, without specifying it, the result will be the following:
Insert your Google Maps API in MapComponent.vue in the following code:
<script>
export default {
props: {
// You can pass the address as a prop to dynamically generatethe map URL
address: {
type: String,
required: true
}
},
computed: {
// Computed property to generate the dynamic map URL based onthe passed address prop
mapUrl() {
const apiKey = 'YOUR_GOOGLE_API_KEY'; // Replace with yourGoogle Maps API Key
const formattedAddress = encodeURIComponent(this.address);
return `https://www.google.com/maps/embed/v1/place?key={apiKey}&q=${formattedAddress}`;
}
}
};
</script>
And then to utilize this component simply modify the string that refers to the place that want to visualize.
Example of usage in AboutUs.vue Page:
<MapComponent address="ITL Srl IMPRESA PULIZIA, Genova Italy"/>
This can be used by simply including the Map as a component in the following way in the <script>
:
import MapComponent from 'src/components/MapComponent.vue';
export default {
components: {
MapComponent,
// ... insert other components if needed
},
...
}
This will help you obtain as result the following map rendering:
SenGrid API is used to trigger mail(s) when the user completes the contact form. In this template, there is a simple contact form that can be used by the user and make the owner of the site receive the content of the message sent by the user.
The mail trigger is handled by Sendgrid so follow the instructions in the guide to get the API KEY to send mails automatically and put you API KEY directly here or in your env.
// Initialize SendGrid API key
sgMail.setApiKey("YOUR_SENDGRID_API_KEY");
Then you will change all the configuration of your response email in the following code (SendGrid will provide you all the code):
exports.SendMail = functions.https.onRequest((request, response) => {
cors(request, response, () => {
// Your function logic here
// Send email to user
const userMsg = {
to: email, // Email of the user obtained by the contact form
from: {
email: "[email protected]", // Use your authenticated domain to not get email goes into SPAM
name: "Giacomo Pedemonte", // Replace with your sender name
},
// if you don't have an AUTHORIZED DOMAIN you need to replace this with a Verified Sender as Sengrid asks, example:
// from: "[email protected]", // Replace with your verified sender email
templateId: "d-c4825a7d9322498ebc92c784d0e5ff62", // Replace with your SendGrid template ID
asm: {
groupId: "YOUR_UNSUBSCRIBE_GROUP_ID" // Replace YOUR_UNSUBSCRIBE_GROUP_ID with the actual ID of your unsubscribe group
},
sgMail
.send(userMsg)
.then(() => {
// Email sent successfully, you can handle the response if needed
})
.catch((error) => {
console.error("Error sending email to user:", error);
});
...
// Send email to owner in the same way to have the confirmation on both sides
};
})
}
)
This function will be deployed and hosted by Firebase and you can access and check the state of this function in the panel in the Firebase console.
You will obtain your personal function link by performing the command:
firebase deploy --only functions
Once you have obtained your function URL, you can use this as an API hosted by Firebase which the endpoints are your exported functions declared in the functions/index.js file, VERY COOL!
In this template, the only function implemented is the integration with Twilio Sendgrid. You can use this as a starting point for your needs.
An example of usage of this endpoint is the following inside the CatchingClientComponent:
// Make a POST request to your Firebase Function endpoint
await axios.post(
// this url needs to be replaced
'https://us-central1-itl-impresadipulizie-genova.cloudfunctions.net/SendMail',
formData);
This also will bypass all possible Cross-Origin errors because all the mail requests performed to the SendGrid API pass through the same address which is your function URL.
Finally, after you have followed all the instructions in Sendgrid, this system can make you obtain a template mail like the following:
The owner(or you), on the other hand, will receive a simple content-based email with a simple visualization of the message of the user.
You can adapt this mail system with every kind of usage, starting from confirmation mail until the verification of user payments...
When the site is ready to be launched you will no longer need the development server that Quasar provides you with quasar dev
, you can simply type in the command prompt:
quasar build
This will make you "compile" your quasar project and setup the SPA (Single Page Application) that can be easily hosted on Firebase as reported in firebase.json.
If you are hosting the site with Firebase then to make the changes visible also in the deployment server (obtained by Firebase in the Firebase Hosting console web page related to your project connected to the site you are realizing) you need to perform the following command:
firebase deploy
The site should run even without all the API KEY updates.
If your firebase deploy
isn't working try to check if all the API KEYs are set, but a first possible solution could be to check the endpoint URL of the firebase functions that are not accessible to you, for further assistance check this.
If more problems are discovered, please, contact me directly by mail at [email protected].
Animation are based on animation.style.
Animations in quasar are triggered by Transitions that are managed by Intersection within the page.
If interested follow quasar docs to know more about animation, transitions and intersections.
Contributions are welcome! For further assistance write directly to [email protected].