Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div class="container">
  <div class="phone">

  </div>
</div>

<template id="factor">
  <div class="factor">
    <div class="factor__color"></div>
    <div class="">
      <div class="factor__percentage">26%</div>
      <div class="factor__text">Food</div>
    </div>
  </div>
</template>

<template id="demo">
  <div class="page-grid">
    <section class="title">
      <div class="title__label">March 2021</div>
      <h1 class="title__heading">Budget</h1>
    </section>

    <section class="main">
      <div class="pie"></div>
    </section>

    <section class="legend fullbleed">

      <div class="factor">
        <div class="factor__color factor__color--food"></div>
        <div class="">
          <div class="factor__percentage">26%</div>
          <div class="factor__text">Food</div>
        </div>
      </div>

      <div class="factor">
        <div class="factor__color factor__color--services"></div>
        <div class="factor__text">
          <div class="factor__percentage">12%</div>
          <div class="factor__text">Services</div>
        </div>
      </div>

      <div class="factor">
        <div class="factor__color factor__color--rent"></div>
        <div class="factor__text">
          <div class="factor__percentage">30%</div>
          <div class="factor__text">Rent</div>
        </div>
      </div>

      <div class="factor">
        <div class="factor__color factor__color--oops"></div>
        <div class="factor__text">
          <div class="factor__percentage">38%</div>
          <div class="factor__text">Oops</div>
        </div>
      </div>

    </section>

    <form class="action-section convert hidden">

      <h3>
        Want to see your own expenses?
      </h3>

      <button type="submit" class="btn-primary">
        Create an account
      </button>
    </form>

  </div>
</template>

<template id="signIn">
  <div class="sign-in-grid">
    <section class="title--logo">
      <div class="title--logo__svg">
        <svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
          <rect width="36" height="36" rx="12" fill="#6E6EC4" />
          <path d="M17.2533 7.41421C18.0343 6.63316 19.3006 6.63317 20.0817 7.41421L22.203 9.53553C22.9841 10.3166 22.9841 11.5829 22.203 12.364L21.4959 13.0711C19.9338 14.6332 17.4012 14.6332 15.8391 13.0711L15.1319 12.364C14.3509 11.5829 14.3509 10.3166 15.1319 9.53553L17.2533 7.41421Z" fill="white" />
          <path d="M10.5358 14.1317C11.3168 13.3507 12.5831 13.3507 13.3642 14.1317L15.4855 16.253C16.2665 17.0341 16.2665 18.3004 15.4855 19.0815L14.7784 19.7886C13.2163 21.3507 10.6836 21.3507 9.12154 19.7886L8.41443 19.0815C7.63338 18.3004 7.63338 17.0341 8.41443 16.253L10.5358 14.1317Z" fill="white" />
          <path d="M17.9604 21.5563C18.7414 20.7753 20.0078 20.7753 20.7888 21.5563L22.9101 23.6777C23.6912 24.4587 23.6912 25.725 22.9101 26.5061L22.203 27.2132C20.6409 28.7753 18.1083 28.7753 16.5462 27.2132L15.8391 26.5061C15.058 25.725 15.058 24.4587 15.8391 23.6777L17.9604 21.5563Z" fill="white" />
        </svg>
      </div>

      <h1 class="title--logo__heading">
        Login
      </h1>

      <div class="title__logo__subtitle">
        <span>Aren't a member yet?</span>
        <a href="#">Create an account</a>
      </div>

    </section>

    <form class="sign-in-social">

      <button class="btn-primary">
        Sign in with Google
      </button>

    </form>

    <section>
      <div class="thin-border"></div>
    </section>

    <form class="sign-in-guest">

      <div data-control="name" class="form-control">
        <label for="name">Name</label>
        <input type="text" required placeholder="Sparky McFirebase" name="name" />
      </div>

      <button type="submit" class="btn-primary">
        Sign in as Guest
      </button>
    </form>

  </div>
</template>
              
            
!

CSS

              
                :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;
}

              
            
!

JS

              
                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());
  }
});

              
            
!
999px

Console