Skip to content

Results Summary Component

Posted on:November 26, 2023 at 01:13 PM at 4 min read

Markup

<!DOCTYPE html>
<html lang="en">
  <head>
    ...
  </head>
  <body>
    <div class="container">
      <div class="result">
        <h1 class="result-title">Your Result</h1>
        <div class="result-score">
          <div class="result-score-number">76</div>
          <div class="result-score-total">of 100</div>
        </div>
        <div class="result-content">
          <h3 class="result-content-title">Great</h3>
          <p class="result-content-text">
            You scored higher than 65% of the people who have taken these tests.
          </p>
        </div>
      </div>
      <div class="summary-wrapper">
        <div class="summary">
          <h3 class="summary-title">Summary</h3>
          <div class="stats"></div>
          <button class="summary-button">Continue</button>
        </div>
      </div>
    </div>
    <script src="./app.js"></script>
  </body>
</html>

CSS

@font-face {
    font-family: 'HankenGrotesk';
    src: url('./assets/fonts/HankenGrotesk-VariableFont_wght.ttf') format('truetype');
}


body {
    padding: 0;
    margin: 0;
    font-family: 'HankenGrotesk', sans-serif;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100vh;
    background-color: #ffffff;
}

.container {
    display: flex;
    box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.2);
    border-radius: 25px;
    justify-content: center;
    align-items: center;
    width: 600px;
}

.result {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-evenly;
    background: linear-gradient(to top, hsla(241, 81%, 54%, 0.95), hsla(252, 100%, 67%, 1));
    border-radius: 25px;
    width: 300px;
    height: 400px;
    padding: 10px;
}

.result-title {
    color: #cdc2ff;
    font-size: 20px;
    font-weight: 700;
    margin-bottom: 10px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.result-score {
    border-radius: 50%;
    background: linear-gradient(to top, hsla(252, 100%, 67%, 0.1), hsla(241, 81%, 54%, 0.8));
    padding: 30px 45px 30px 45px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
}

.result-score-number {
    color: #fdfdff;
    font-size: 60px;
    font-weight: 700;
    width: 70px;
}

.result-score-total {
    color: #8276ff;
    font-weight: 700;
}

.result-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 80%;
    text-align: center;
    padding-top: 10px;
}

.result-content-title {
    color: #fff9ff;
    font-size: 1.5rem;
    margin: 0;
    padding-bottom: 10px;
}

.result-content-text {
    color: #b9b4ff;
    margin: 0;
    width: 93%;
    padding: 10px;
}


.summary {
    display: flex;
    flex-direction: column;
    justify-content: space-evenly;
    width: 80%;
    height: 400px;
    padding: 10px;
}

.summary-wrapper {
    width: 300px;
    display: flex;
    flex-direction: column;
    gap: 15px;
    justify-content: center;
    align-items: center;
}

.summary-title {
    margin: 0;
}


.stats {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.stat {
    padding: 15px;
    border-radius: 8px;
    display: flex;
    gap: 1px;
    align-items: center;
    justify-content: space-between;
}

.stat:hover {
    transform: scale(1.02);
    transition-property: all;
    transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
    transition-duration: 150ms;
}

.stat-info {
    display: flex;
    gap: 5px;
    align-items: center;
}

.stat-ratings {
    display: flex;
    gap: 5px;
    align-items: center;
}

.stat-icon {
    width: 20px;
    height: 20px;
}

.stat-score {
    font-weight: 900;
    margin: 0;
}

.stat-max {
    color: #a8a1a5;
    margin: 0;
}

.stat-name-reaction {
    color: #df8387;
    font-weight: 700;
    margin: 0;
}

.stat-name-memory {
    color: #fbbe46;
    font-weight: 700;
    margin: 0;
}

.stat-name-verbal {
    color: #49b39a;
    font-weight: 700;
    margin: 0;
}

.stat-name-visual {
    color: #6067cd;
    font-weight: 700;
    margin: 0;
}

.reaction {
    background-color: #fff6f6;
}

.memory {
    background-color: #fffbf2;
}

.verbal {
    background-color: #f3fafa;
}

.visual {
    background-color: #f3f3fd;
}

.summary-button {
    background-color: #303b59;
    border: none;
    border-radius: 25px;
    padding: 15px 10px 15px 10px;
    font-weight: 600;
    color: #ffffff;
    cursor: pointer;
}

.summary-button:hover {
    background: linear-gradient(to bottom, hsla(252, 100%, 67%, 0.8), hsla(241, 81%, 54%, 0.9));
    transform: scale(1.02);
    transition-property: all;
    transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
    transition-duration: 150ms;
}

@media only screen and (max-width: 640px) {
    body {
        width: 100%;
        height: 100%;
    }

    .container {
        width: 100%;
        flex-direction: column;
        box-shadow: none;
    }

    .result {
        border-radius: 0 0 60px 60px;
        width: 100%;
        padding: 0;
    }

    .summary {
        border-radius: 50px 50px 0 0;
        width: 100%;
    }

    .summary-wrapper {
        width: 80%;

    }
}

JavaScript

function generateStat(type, category, score, icon) {
  return `<div class="stat ${type}">
    <div class="stat-info">
      <img
        class="stat-icon"
        src="${icon}"
        alt="${type}-icon"
      />
      <p class="stat-name-${type}">${category}</p>
    </div>
    <div class="stat-ratings">
      <p class="stat-score">${score}</p>
      <span>/</span>
      <p class="stat-max">100</p>
    </div>
  </div>`;
}

document.addEventListener("DOMContentLoaded", function () {
  const resultScoreNumber = document.querySelector(".result-score-number");

  const achievedScore = 76;
  const interval = 10;
  const step = achievedScore / (2000 / interval);

  let currentCount = 0;

  function updateScore() {
    resultScoreNumber.textContent = Math.round(currentCount);

    if (currentCount >= achievedScore) {
      clearInterval(counterInterval);
    }
    const difference = achievedScore - currentCount;
    if (difference > 20) {
      currentCount += step;
    } else if (difference > 10) {
      currentCount += step / 2;
    } else if (difference > 5) {
      currentCount += step / 4;
    } else if (difference > 2) {
      currentCount += step / 8;
    } else {
      currentCount += step / 16;
    }
  }

  const counterInterval = setInterval(updateScore, interval);
});

fetch("./data.json")
  .then((response) => response.json())
  .then((data) => {
    const stats = data.map((stat) =>
      generateStat(
        stat.category.toLowerCase(),
        stat.category,
        stat.score,
        stat.icon
      )
    );
    document.querySelector(".stats").innerHTML = stats.join("");
  });

Result

Live Demo