DEV Community

abdfn
abdfn

Posted on • Edited on

How to build a cool simple contact page with Nuxt and FaunaDB

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 :

Let's go

first, you'll need to install create-nuxt-app

$ npm i -g create-nuxt-app 
Enter fullscreen mode Exit fullscreen mode

after install let's create our site

$ create-nuxt-app PROJ_NAME && cd PROJ_NAME 
Enter fullscreen mode Exit fullscreen mode

Alt Text

now we need three packages :

  • faunadb: JavaScript driver for FaunaDB

  • slugify: we'll use this package to generate slugs from con names

  • dotenv

$ npm i faunadb slugify dotenv 
Enter fullscreen mode Exit fullscreen mode

now let's create graphql schema

$ mkdir graphql && cd graphql && touch schema.gql 
Enter fullscreen mode Exit fullscreen mode

data modiling (graphql schema)

structure:

  • desc: contact description

  • repoUrl: contact url

  • brand || solid: check if fontawesome icon is fab or fas

  • 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!]! } 
Enter fullscreen mode Exit fullscreen mode

now go to faunaDB dashboard & create new database

Alt Text

go to graphql section and import your schema

Alt Text

now you should have collections

Alt Text

Creating keys

create Admin key & Server key

ADMIN

Alt Text

Press SAVE

in your project create .env file

Alt Text

replace 🔑️ with your key

SERVER

Alt Text

Also press SAVE

in .env

Alt Text

replace 🗝️ with your second key

ok we finish all this

return to graphql folder and create db-connection.js

$ touch db-connection.js 
Enter fullscreen mode Exit fullscreen mode

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; 
Enter fullscreen mode Exit fullscreen mode
very important step

in nuxt.config.js in above

require("dotenv").config(); 
Enter fullscreen mode Exit fullscreen mode

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; } } 
Enter fullscreen mode Exit fullscreen mode

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 } 
Enter fullscreen mode Exit fullscreen mode

I put dev-x Twitter, GitHub issue, Dev org

Alt Text

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 
Enter fullscreen mode Exit fullscreen mode

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", ... ], 
Enter fullscreen mode Exit fullscreen mode

go to pages and create index.scss

in pages you should have two files

├── index.vue └── index.scss 
Enter fullscreen mode Exit fullscreen mode

in index.vue

template

<template> <div class="container"> <div> <Logo /> <h1 class="title">contact.dev-x</h1> <div> <div class="card"> <h3>Contacts &rarr;</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> 
Enter fullscreen mode Exit fullscreen mode

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> 
Enter fullscreen mode Exit fullscreen mode

style

<style lang="scss"> @import "index.scss"; </style> 
Enter fullscreen mode Exit fullscreen mode

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; } 
Enter fullscreen mode Exit fullscreen mode

Everything is ok

the step before end

in terminal type...

$ npm run generate 
Enter fullscreen mode Exit fullscreen mode

if you see this error

Alt Text

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 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

mac or linux

$ sudo npm i -g firebase firebase-tools 
Enter fullscreen mode Exit fullscreen mode

now go to firebase console

let's create a web app

Alt Text

and create a new project

Alt Text

hosting

Alt Text

final touches

Alt Text

copy "site" prop

go to the project and type

$ firebase login 
Enter fullscreen mode Exit fullscreen mode

it's going to login in browser

initializing

$ firebase init 
Enter fullscreen mode Exit fullscreen mode

Alt Text

Alt Text

Alt Text

Alt Text

Alt Text

go to firebase.json

{ "hosting": { "site": "contactus-x", "public": "dist", ... } } 
Enter fullscreen mode Exit fullscreen mode

and the final step

$ firebase deploy --only hosting:contactus-x 
Enter fullscreen mode Exit fullscreen mode

that it

$ echo happy coding ⌨️ 
Enter fullscreen mode Exit fullscreen mode

Top comments (0)