JSFiddle - React, Tailwind, and code Playground

by Perry Kaufman

HTML

<script src="https://unpkg.com/vue"></script>
<script src="https://www.gstatic.com/firebasejs/4.5.0/firebase.js"></script>

<div id="app">
  <banner v-bind:status="status"></banner>
  <profile-section v-bind:status="status" v-if="status"></profile-section>
</div>

<template id="banner-template">
  <div class="banner">
    <div class="bannerLeft">
      <span class="bannerTitle">GW2 Profile</span>
    </div>
    <div class="bannerRight" v-if="!status">
      <form v-on:submit.prevent="signIn">
        <table>
          <tr>
            <td>
              <input v-bind:class="emailInputClass" v-model="email" v-on:keyup="checkPlaceholderReset('email')" type="text" v-bind:placeholder="emailHolder" />
            </td>
            <td>
              <input v-bind:class="passInputClass" v-model="password" v-on:keyup="checkPlaceholderReset('pass')" type="password" v-bind:placeholder="passHolder" />
            </td>
            <td>
              <button type="submit">sign in</button>
            </td>
            <td>
              <button type="button" v-on:click="signUp">sign up</button>
            </td>
        </table>
      </form>
    </div>
    <div class="bannerRight" v-if="status">
      <span class="loginMessage">Hello {{displayEmail}} </span>
      <button type="button" v-on:click="signOut">sign out</button>
    </div>
  </div>
</template>

<template id="profile-section-template">
  <div>
    <api-sub-banner v-on:apichange="updateAPI"></api-sub-banner>
    Parent Value: {{apikey}}
  </div>
</template>

<template id="api-sub-banner-template">
    <div class="api-key-content">
    <form class="api-key-form" v-on:submit.prevent="submitAPIKey">
      <table>
        <tr v-if="valid == false && edit == false">
          <td><span>You must enter a Guild Wars 2 API Key to create your profile</span></td>
          <td><button class="api-key-button" type="button" v-on:click="editStart">add a key</button></td>
        </tr>
        <tr v-if="valid == false && edit ==...

CSS

body {
  font-family: sans-serif;
  background-color: lightgray;
  padding: 0;
}

table {
  white-space: nowrap;
}

.banner {
  background-image: url("https://d3b4yo2b5lbfy.cloudfront.net/wp-content/uploads/wallpapers/add552014-11-18_TP-1920x1200.jpg");
  background-position: center;
  background-repeat: repeat;
  position: relative;
  padding: 5px;
  border: 2px solid black;
  background-color: #273746;
  height: 30px;
  min-width: 575px;
  margin: 0;
}

.bannerLeft {
  position: absolute;
  top: 50%;
  left: 5px;
  transform: translateY(-50%);
}

.bannerRight {
  position: absolute;
  top: 50%;
  right: 5px;
  transform: translateY(-50%);
}

.bannerTitle,
.loginMessage {
  color: white;
}

.bannerTitle {
  font-size: 26px;
  font-weight: bold;
}

.loginMessage {
  font-weight: 580;
}

.loginTextInput {
  border: 1px solid black;
  padding: 2px;
}

.loginTextError::placeholder {
  color: red;
  opacity: 1;
}

button {
  font-size: 15px;
  color: white;
  background-color: black;
  border: none;
  padding: 3px 8px 3px 8px;
}

button:active {
  background-color: darkgray;
}


/*MAIN-SECTION CSS*/

.input-api {
  width: 505px;
}

.input-api-error::placeholder {
  color: red;
  opacity: 1;
}

.api-key-content {
  position: relative;
  text-align: center;
  color: white;
  background-color: black;
  height: 40px;
}

.api-key-form {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.api-key-button {
  border: 1px solid white;
}

JavaScript

// Initialize Firebase
  var config = {
    apiKey: "AIzaSyAHmlXOLaS6vpp5VORKELlBYQURtn8utao",
    authDomain: "testproject-c8451.firebaseapp.com",
    databaseURL: "https://testproject-c8451.firebaseio.com",
    projectId: "testproject-c8451",
    storageBucket: "testproject-c8451.appspot.com",
    messagingSenderId: "809672710893"
  };
  firebase.initializeApp(config);
  var auth = firebase.auth();
  var database = firebase.database();

  auth.onAuthStateChanged(function(user) {
    if (user) {
      vm.status = true;
    } else {
      vm.status = false;
    }
  });

  Vue.component('banner', {
    template: '#banner-template',
    props: {
      status: status
    },
    data: function() {
      return {
        email: '',
        password: '',
        emailHolder: 'Email',
        passHolder: 'Password',
        emailError: false,
        passError: false
      };
    },
    methods: {
      signIn: function() {
        var promise = auth.signInWithEmailAndPassword(this.email, this.password);
        var bn = this;
        promise.catch(function(error) {
          var errorCode = error.code;
          if (errorCode == 'auth/invalid-email') {
            bn.emailFieldMessage('invalid email');
          } else if (errorCode == 'auth/user-not-found') {
            bn.emailFieldMessage('user not found', 'both');
          } else if (errorCode == 'auth/wrong-password') {
            bn.passFieldMessage('wrong password');
          } else {
            console.log(error.message);
          }
        });
      },
      signUp: function() {
        var promise = auth.createUserWithEmailAndPassword(this.email, this.password);
        var bn = this;
        promise.catch(function(error) {
          var errorCode = error.code;
          if (errorCode == 'auth/email-already-in-use') {
            bn.emailFieldMessage('email unavailable');
          } else if (errorCode == 'auth/invalid-email') {
            bn.emailFieldMessage('invalid email');
          } else if...