:root {
--font-stack: arboria, sans-serif;
--primary-hue: 240;
--money-hue: 120;
--primary-light: hsl(var(--primary-hue), 67%, 96%);
--primary: hsl(var(--primary-hue), 32%, 57%);
--money: hsl(var(--money-hue), 32%, 57%);
--white: white;
--gray: hsla(240, 10%, 48%, 1);
--blue: hsl(212, 62%, 57%);
--scale: 1.5;
--pie-1__color: var(--money);
--pie-1__value: 26%;
--pie-1__computed: calc(var(--pie-1__value) + 0%);
--pie-2__color: var(--gray);
--pie-2__value: 12%;
--pie-2__computed: calc(var(--pie-1__value) + var(--pie-2__value));
--pie-3__color: var(--blue);
--pie-3__value: 30%;
--pie-3__computed: calc(var(--pie-2__computed) + var(--pie-3__value));
--pie-4__color: var(--primary);
--pie-4__value: 38%;
--pie-4__computed: 0%;
--pie-1: var(--pie-1__color) var(--pie-1__computed);
--pie-2: var(--pie-2__color) 0 var(--pie-2__computed);
--pie-3: var(--pie-3__color) 0 var(--pie-3__computed);
--pie-4: var(--pie-4__color) 0 var(--pie-4__computed);
}
* {
box-sizing: border-box;
}
html, body {
background-color: var(--primary-light);
font-family: var(--font-stack);
height: 100vh;
display: grid;
padding: 1rem;
}
.container {
display: grid;
place-content: center;
}
.phone {
background: var(--white);
border-radius: calc(50px / var(--scale));
height: calc(972px / var(--scale));
width: calc(452px / var(--scale));
box-shadow: 2px 2px 24px -8px hsla(240, 40%, 33%, .45);
position: relative;
overflow: hidden;
}
.page-grid {
padding-top: 2rem;
display: flex;
flex-direction: column;
row-gap: 2rem;
}
.page-grid section:not(.fullbleed) {
padding-left: 1rem;
padding-right: 1rem;
}
.sign-in-grid {
display: flex;
flex-direction: column;
padding-left: 1rem;
padding-right: 1rem;
place-content: center;
height: 100%;
row-gap: 2rem;
}
.title {
display: grid;
row-gap: .5rem;
}
.title__heading {
font-size: 2.25rem;
font-weight: 400;
}
.title__label {
color: var(--primary);
font-size: 0.875rem;
font-weight: 700;
letter-spacing: 0.04ch;
text-transform: uppercase;
}
.title--logo {
display: flex;
flex-direction: column;
align-items: center;
row-gap: 1rem;
}
.title--logo__heading {
font-size: 32px;
font-weight: 500;
margin-top: .5rem;
}
.title__logo__subtitle {
font-size: 12px;
text-align: center;
}
.btn-primary {
background: hsl(240, 81%, 73%);
box-shadow: 4px 4px 16px -4px hsla(0, 0%, 0%, 0.25);
border-radius: 6px;
border: none;
color: white;
width: 100%;
height: 44px;
text-align: center;
}
.btn-primary:hover {
background: hsl(240, 83%, 75%);
color: hsl(0, 0, 96%);
}
.thin-border {
background-color: hsl(0, 0%, 90%);
height: 2px;
border-radius: 2px;
}
.form-control {
display: grid;
row-gap: .25rem;
margin-bottom: 1rem;
}
.form-control label {
display: block;
}
.form-control input[type="text"] {
display: block;
height: 44px;
border: none;
box-shadow: 4px 4px 16px -4px rgba(0, 0, 0, 0.25);
border-radius: 6px;
width: 100%;
padding: .5rem;
}
.main {
background-color: hsl(240, 77%, 86%);
height: 16rem;
display: flex;
justify-content: center;
align-items: center;
perspective: 1000px;
}
.main--light {
background-color: var(--white);
}
.legend {
display: flex;
justify-content: space-evenly;
}
.factor__color {
height: .75rem;
width: .75rem;
border-radius: 100%;
}
.factor {
display: flex;
align-items: center;
column-gap: .25rem;
}
.factor__color--food {
background-color: var(--money);
}
.factor__color--services {
background-color: var(--gray);
}
.factor__color--rent {
background-color: var(--blue);
}
.factor__color--oops {
background-color: var(--primary);
}
.factor__text, .factor__percentage {
font-size: .5rem;
text-transform: uppercase;
letter-spacing: .04ch;
font-weight: bold;
color: var(--gray);
}
.factor__percentage {
font-size: .65rem;
color: hsla(240, 100%, 6%);
}
.pie {
background:
conic-gradient(
var(--pie-1),
var(--pie-2),
var(--pie-3),
var(--pie-4)
);
border-radius: 50%;
width: 65%;
padding-top: 65%;
box-shadow: 2px 2px 24px -8px hsla(240, 40%, 33%, .75);
}
.action-section {
display: grid;
row-gap: 2rem;
place-content: center;
height: 100%;
padding-top: 2rem;
padding-bottom: 2rem;
}
.hidden {
display: none;
}
let firebaseConfig = {
apiKey: "AIzaSyANCgyffqqOMepBntmZ3SdyGOkqXSSBiwQ",
authDomain: "codepenfire.firebaseapp.com",
projectId: "codepenfire",
storageBucket: "codepenfire.appspot.com",
messagingSenderId: "263874418526",
appId: "1:263874418526:web:34b33bf61d8d7b9e7821cf",
measurementId: "G-29DTC3DBD8"
};
let firebaseApp = window.firebase.initializeApp(firebaseConfig);
let rootView = document.querySelector(".phone");
let session = redirectSession();
let root = document.documentElement;
firebaseApp.auth().onAuthStateChanged((user) => {
if (user != null) {
routeTo("demo", rootView, user);
} else {
routeTo("signIn", rootView);
}
});
checkForRedirect(session);
async function checkForRedirect(session) {
if (!session.isRedirected()) {
return;
}
session.removeLink();
try {
const result = await firebaseApp.auth().getRedirectResult();
} catch(error) {
switch(error.code) {
case 'auth/credential-already-in-use': {
// You can check for the provider it uses
// firebaseApp.auth().fetchProvidersForEmail(error.email)
// But in this case we don't want the user to link with
// an existing account we would prompt them about an
// error and prompt them to log in with their account
}
}
}
}
function routeTo(view, rootView, user) {
let clone, listeners;
switch (view) {
case "signIn": {
clone = cloneNode("#signIn");
// This is mostly to keep the code pen simple
// ideally you'd detach listeners
listeners = attachSignInListeners;
break;
}
case "demo": {
clone = cloneNode("#demo");
// This is mostly to keep the code pen simple
// ideally you'd detach listeners
listeners = attachDemoListeners;
break;
}
default:
throw new Error("???");
break;
}
rootView.innerHTML = "";
rootView.appendChild(clone);
listeners(document, firebaseApp, user);
}
function cloneNode(templateSelector) {
let template = document.querySelector(templateSelector);
return template.content.cloneNode(true);
}
// This is a performance optimization. Calling the method
// getRedirectResult() will load in code. We can avoid
// loading it before its needed by using sessionStorage
// to signal if the user initiated a redirect
function redirectSession() {
// Simple helpers for using sessionStorage to
// indicate if a user is returning from a redirect
return {
setLink() {
sessionStorage.setItem('link', 'true');
},
removeLink() {
sessionStorage.setItem('link', '');
},
isRedirected() {
return !!sessionStorage.getItem('link');
}
};
}
function signInGoogle({ link } = { link: false }) {
let provider = new firebase.auth.GoogleAuthProvider();
if(link) {
session.setLink();
firebaseApp.auth().currentUser.linkWithRedirect(provider);
} else {
firebaseApp.auth().signInWithRedirect(provider);
}
}
function attachSignInListeners(document, firebaseApp) {
let socialForm = document.querySelector("form.sign-in-social");
let guestForm = document.querySelector("form.sign-in-guest");
guestForm.addEventListener("submit", async (submitEvent) => {
submitEvent.preventDefault();
let formData = new FormData(guestForm);
let displayName = formData.get("name");
let photoURL = await getRandomPhotoURL();
// Firebase specific code
let { user } = await firebaseApp.auth().signInAnonymously();
await user.updateProfile({ displayName, photoURL });
// End Firebase specific code
});
socialForm.addEventListener("submit", (submitEvent) => {
submitEvent.preventDefault();
// Firebase specific code
signInGoogle();
// End Firebase specific code
});
async function getRandomPhotoURL() {
let response = await fetch("https://picsum.photos/128?blur");
return response.url;
}
}
function attachDemoListeners(document, firebaseApp, user) {
let convertForm = document.querySelector('form.convert');
let legend = document.querySelector('.legend');
let marchDoc = firebaseApp.firestore()
.collection('users')
.doc(user.uid)
.collection('expenses')
.doc('3-2021');
if(user.isAnonymous) {
convertForm.classList.toggle('hidden');
}
convertForm.addEventListener("submit", (submitEvent) => {
submitEvent.preventDefault();
signInGoogle({ link: true });
});
marchDoc.onSnapshot(snap => {
legend.innerHTML = '';
let { factors } = snap.data();
factors.forEach((factor, index) => {
let template = cloneNode('#factor');
let textEl = template.querySelector('.factor__text');
let percentageEl = template.querySelector('.factor__percentage');
let factorColorEl = template.querySelector('.factor__color');
root.style.setProperty(`--pie-${index+1}__value`, `${factor.value}%`);
textEl.textContent = factor.label;
percentageEl.textContent = `${factor.value}%`;
factorColorEl.classList.add(`factor__color--${factor.label.toLowerCase()}`);
legend.appendChild(template);
});
});
}
// Creates helpful hot-keys for debugging
// CTRL+O - Sign out
// CTRL+U - Log the current user to the console
document.addEventListener("keydown", async (event) => {
if (event.ctrlKey && event.key === "o") {
await firebaseApp.auth().signOut();
console.log("Signed out!");
}
if (event.ctrlKey && event.key === "u") {
let currentUser = firebaseApp.auth().currentUser;
console.log(currentUser.toJSON());
}
});