abdfn
Posted on October 30, 2020
In this article, you'll know how to build a contact website and contact ways...
First, we'll build a simple page and in it how to contact us like Twitter, Dev, Github...
Nuxtjs
Nuxt is an open-source web application framework built on top of Vue.js, It is well known for its SSR capabilities, but it can also do static.
Instead of having a Node server process each client request - eventually fetching data from an API or database in between, we'll be using Nuxt as a static site generator to do the heavy lifting during the build stage.
FaunaDB
Fauna is a globally distributed, low-latency database, with native GraphQL support, that promises to be always consistent and always secure.
As a serverless database, FaunaDB allows applications to access data through a secure API, in contrast to more "traditional" relational databases that require you to open a connection. In that sense, FaunaDB is “connectionless” and rather behaves like an API, which fits perfectly in a Jamstack architecture. There is also no need to host and manage our own database. It requires zero server configuration and supports seamless scalability out-of-the-box.
Demo
you can try the project (demo)
Pre-requisites
before we move on, you'll need :
Npm, Node & Npx installed.
Let's go
first, you'll need to install create-nuxt-app
$ npm i -g create-nuxt-app
after install let's create our site
$ create-nuxt-app PROJ_NAME && cd PROJ_NAME
now we need three packages :
faunadb: JavaScript driver for FaunaDB
slugify: we'll use this package to generate slugs from con names
$ npm i faunadb slugify dotenv
now let's create graphql schema
$ mkdir graphql && cd graphql && touch schema.gql
data modiling (graphql schema)
structure:
desc: contact description
repoUrl: contact url
brand || solid: check if fontawesome icon is
fab
orfas
faI: contact fontawesome icon
hashtag: if the contact has a hashtag
hashtag_name: hashtag name
inside schema.gql
type Repo {
desc: String! @unique
repoUrl: String! @unique
# if font-awesome icon is brand or solid
brand: Boolean
solid: Boolean
faI: String
# this only for twitter & dev contacts
hashtag: Boolean
hashtag_name: String
}
type Query {
allRepos: [Repo!]!
}
now go to faunaDB dashboard & create new database
go to graphql section and import your schema
now you should have collections
Creating keys
create Admin key
& Server key
ADMIN
Press SAVE
in your project create .env
file
replace 🔑️ with your key
SERVER
Also press SAVE
in .env
replace 🗝️ with your second key
ok we finish all this
return to graphql
folder and create db-connection.js
$ touch db-connection.js
inside it paste this code
require("dotenv").config();
const faunadb = require("faunadb");
const query = faunadb.query;
function createClient() {
if (!process.env.FAUNA_ADMIN_KEY) {
throw new Error("FAUNA_ADMIN_KEY not found");
}
const client = new faunadb.Client({
secret: process.env.FAUNA_ADMIN_KEY
});
return client;
}
exports.client = createClient();
exports.query = query;
very important step
in nuxt.config.js
in above
require("dotenv").config();
and let's add generate
prop
generate: {
async routes() {
const faunadb = require("faunadb");
const query = faunadb.query;
const slugify = require("slugify");
const q = query;
if (!process.env.FAUNA_SERVER_KEY) {
throw new Error("FAUNA_SERVER_KEY not found.");
}
const client = new faunadb.Client({
secret: process.env.FAUNA_SERVER_KEY
});
const result = await client.query(
q.Map(
q.Paginate(q.Match(q.Index("allRepos"))),
q.Lambda("X", q.Get(q.Var("X")))
)
);
const repos = result.data.map(repo => repo.data);
const routes = repos.map(repo => {
const repoUrlParts = repo.repoUrl.split("/");
const repoOwner = repoUrlParts[repoUrlParts.length - 2];
const repoName = repoUrlParts[repoUrlParts.length - 1];
const slug = slugify(repoName, {
remove: /[*+~.()'"!:@]/g
});
repo.slug = slug;
repo.owner = repoOwner;
repo.name = repoName;
return {
payload: repo
};
});
routes.push({
route: "/",
payload: repos
});
return routes;
}
}
Import collections
return to faunaDB dashboard, collections section to create new collection
press new document
example data
{
"desc": "you can make a github issue",
"repoUrl": "https://github.com/YOUR_REPO/issues",
"brand": true,
"solid": false,
"faI": "github",
"hashtag": false
}
I put dev-x Twitter, GitHub issue, Dev org
now go to pages
before beginning, we need some packages
font-awesome
sass & sass-loader
$ npm i @fortawesome/fontawesome-svg-core @fortawesome/vue-fontawesome @fortawesome/free-brands-svg-icons @fortawesome/free-solid-svg-icons sass sass-loader
now go to nuxt.config.js
in css
section
we going to import font-awesome style
type this
css: [
"@fortawesome/fontawesome-svg-core/styles.css",
...
],
go to pages
and create index.scss
in pages
you should have two files
├── index.vue
└── index.scss
in index.vue
template
<template>
<div class="container">
<div>
<Logo />
<h1 class="title">contact.dev-x</h1>
<div>
<div class="card">
<h3>Contacts →</h3>
<ul v-for="repo in repos" :key="repo.desc">
<li>
{{ repo.desc }}
<strong v-if="repo.hashtag">{{ repo.hashtag_name }}</strong>
<a :href="repo.repoUrl">
<a class="btn">
<fai v-if="repo.brand" :icon="['fab', `${repo.faI}`]" />
<fai v-if="repo.solid" :icon="repo.faI" />
</a>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
script
<script>
import Vue from "vue";
import { library, config } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { fab } from "@fortawesome/free-brands-svg-icons";
import { fas } from "@fortawesome/free-solid-svg-icons";
// This is important, we are going to let Nuxt.js worry about the CSS
config.autoAddCss = false;
// You can add your icons directly in this plugin. See other examples for how you
// can add other styles or just individual icons.
library.add(fab);
library.add(fas);
// Register the component globally
Vue.component("fai", FontAwesomeIcon);
Vue.config.productionTip = false;
export default {
asyncData({ payload }) {
return { repos: payload };
}
};
</script>
style
<style lang="scss">
@import "index.scss";
</style>
index.scss
$color: #121312;
.container {
margin: 0 auto;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.title {
display: block;
font-weight: 300;
font-size: 100px;
color: #31465e;
letter-spacing: 1px;
}
.subtitle {
font-weight: 300;
font-size: 42px;
color: #526488;
word-spacing: 5px;
padding-bottom: 15px;
}
.links {
padding-top: 15px;
}
.card {
cursor: pointer;
margin: 1rem;
flex-basis: 45%;
padding: 1.5rem;
text-align: left;
color: inherit;
text-decoration: none;
border: 2px solid#000000;
border-radius: 2.5px;
flex-direction: column;
box-shadow: 5px 6px 0px black;
}
.card h3 {
margin: 0 0 1rem 0;
font-size: 1.5rem;
}
.card li {
margin: 0;
font-size: 1.25rem;
line-height: 1.5;
list-style: none;
font-family: DF;
}
a {
color: rgb(0, 119, 255);
}
strong {
color: dodgerblue;
}
.btn {
display: inline-block;
border-radius: 4px;
border: 1px solid $color;
color: $color;
text-decoration: none;
padding: 10px 30px;
margin-left: 15px;
}
.btn:hover {
color: #fff;
background-color: $color;
}
Everything is ok
the step before end
in terminal type...
$ npm run generate
if you see this error
don't worry it's a soft error
after generate
we'll use serve
to serve the output build
$ npx serve dist
# or
$ sudo npm i -g serve
$ serve dist
go to localhost:5000
and see your result
Deploy to firebase (optional)
install firebase globally
if you've windows
npm i -g firebase firebase-tools
mac or linux
$ sudo npm i -g firebase firebase-tools
now go to firebase console
let's create a web app
and create a new project
hosting
final touches
copy "site"
prop
go to the project and type
$ firebase login
it's going to login in browser
initializing
$ firebase init
go to firebase.json
{
"hosting": {
"site": "contactus-x",
"public": "dist",
...
}
}
and the final step
$ firebase deploy --only hosting:contactus-x
that it
$ echo happy coding ⌨️
Posted on October 30, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.