JavascriptTutorias

Cripto Dashboard em Javascript

Cripto Dashboard em Javascript
Cripto Dashboard em Javascript

 

 

Introdução

Neste tutorial, você aprenderá a criar um Cripto Dashboard utilizando apenas HTML, CSS e JavaScript, sem a necessidade de bibliotecas externas.

Este guia prático ensina como visualizar informações sobre a cotação de criptomoedas de forma simples e eficiente. Utilizaremos a API do Mercado Bitcoin para consultar e exibir os dados no dashboard.

 

Cripto Dashboard em Javascript

 

Primeiro passo você deverá criar a estrutura da página, para isso crie um arquivo html contendo  o seguinte código :

 

<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>Cripto DashBoard</title>
</head>
<body>
    <script>
    </script>
</body>
</html>

 

Logo após crio a estrutura do conversor:

 

 <div class="container">
        <div class="header">
            <div class="title-container">
                <svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" stroke="currentColor" fill="currentColor"
                    width="1em" height="1em" viewBox="0 0 30 30" alt="Ícone de Criptomoeda" >
                    <path
                        d="M 15 3 C 8.373 3 3 8.373 3 15 C 3 21.627 8.373 27 15 27 C 21.627 27 27 21.627 27 15 C 27 8.373 21.627 3 15 3 z M 14 8 L 16 8 L 16 10.007812 C 17.86 10.050812 18.970703 10.984141 18.970703 12.494141 C 18.970703 13.554141 18.188109 14.476906 17.162109 14.628906 L 17.162109 14.753906 C 18.486109 14.850906 19.449219 15.849672 19.449219 17.138672 C 19.449219 18.888672 18.129 19.995047 16 19.998047 L 16 22 L 14 22 L 14 20 L 11.5 20 L 11.5 10 L 14 10 L 14 8 z M 13.59375 11.601562 L 13.59375 14.144531 L 15.166016 14.144531 C 16.296016 14.144531 16.912109 13.680953 16.912109 12.876953 C 16.912109 12.079953 16.337844 11.601563 15.339844 11.601562 L 13.59375 11.601562 z M 13.59375 15.558594 L 13.59375 18.398438 L 15.457031 18.398438 C 16.663031 18.398438 17.314453 17.892031 17.314453 16.957031 C 17.314453 16.042031 16.641203 15.558594 15.408203 15.558594 L 13.59375 15.558594 z">
                    </path>
                </svg>
                <h2><span>C</span>ripto <span>D</span>ashboard</h2>
            </div>
            <div class="search-input">
                <input type="text" id="filter-input" placeholder="Selecione uma Cripto Moeda. ex: Bitcoin" />
                <div class="select-dropdown">
                    <ul id="optionsList">
                        <li>Bitcoin</li>
                        <li>Ethereum</li>
                        <li>Ripple</li>
                    </ul>
                </div>
                <button id="searchButton">
                    <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em"
                        width="1em" xmlns="http://www.w3.org/2000/svg" alt="Ícone de search">
                        <path
                            d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z">
                        </path>
                    </svg>
                </button>
            </div>
        </div>
        <div class="dashBoard" id="dashBoard">
            <div id="loading" style="display: none;">Carregando...</div>
            <div class="card">
                <div class="css-text-mask mask-one">Bitcoin</div>
                <p>Ativo Selecionado</p>
            </div>
            <div class="card">
                <div class="css-text-mask mask-two">BTC</div>
                <p>Ticker</p>
            </div>
            <div class="card">
                <div class="css-text-mask mask-three">385M</div>
                <p>Última cotacação em (R$)</p>
            </div>
            <div class="card">
                <div class="css-text-mask mask-three">Cripto</div>
                <p>Segmento </p>
            </div>
            <div class="card">
                <div class="css-text-mask mask-four">+0,82%</div>
                <p>Variação em 24H</p>
            </div>
            <div class="card">
                <div class="css-text-mask mask-one">6,9B</div>
                <p>Capitalização de mercado</p>
            </div>
        </div>
    </div>
    <div id="loadingModal" class="modal">
        <div class="modal-content">
            <div class="loader"></div>
            <p>Carregando...</p>
        </div>
    </div>
    <script src="main.js"></script>

 

No código acima crio a interface do DashBoard Cripto.
Adicionei um campo para entrada de um número e um botão para executar a consulta a api de cotação da moeda e por fim adicionei uma área para exibir o resultado retornado pela api.

 

Depois adiciono o css responsável pela estilização da página :

 

*,
*:after,
*:before {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  vertical-align: baseline;
  text-decoration: none;
}
:root {
  --white: #ffffff;
  --dark: rgb(40, 44, 51);
  --green: rgb(166, 247, 80);
  --green2: rgb(142, 211, 69);
  --gray: rgb(85, 89, 95);
  --orange: rgb(255, 216, 98);
  --red: #f46663;
  --contorno: rgba(255, 255, 255, 0.7);
}
body {
  height: 100vh;
  width: 100vw;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #121f32;
  color: var(--white);
  font-family: basic-sans, sans-serif !important;
}
.container {
  width: calc(100% - 2rem);
  padding: 1rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.header {
  width: calc(80% - 2rem);
  padding: 1rem;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
}
.title-container {
  display: flex;
  flex-direction: row;
  align-items: end;
  gap: 0.5rem;
}
.title-container > svg {
  width: 5rem;
  height: 5rem;
  fill: var(--dark);
  stroke: var(--green);
}
.title-container h2 {
  font-size: 3rem;
  line-height: 4rem;
  font-weight: 700;
  font-style: normal;
  color: var(--white);
}
.title-container h2 > span {
  font-size: 3.8rem;
  line-height: 4rem;
  color: var(--green);
}
.search-input {
  min-width: 30%;
  display: flex;
  gap: 0.5rem;
  align-items: center;
  position: relative;
  padding: 0.5rem;
  background: var(--dark);
  border: 1px solid var(--gray);
  border-radius: 4px;
}
.search-input input {
  width: 100%;
  font-size: 1rem;
  color: var(--green);
  position: relative;
  outline: none;
  padding: 0.5rem 1rem;
  background: var(--dark);
  border: 1px solid transparent;
}
.search-input .select-dropdown {
  position: absolute;
  top: 50px;
  left: 0;
  background: var(--dark);
  border: 1px solid var(--gray);
  color: var(--green);
  width: 250px;
  z-index: 1;
  display: none;
}
.search-input .select-dropdown ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
}
.search-input .select-dropdown li {
  padding: 0.5rem;
  cursor: pointer;
}
.search-input .select-dropdown li:hover {
  background-color: var(--green);
  color: var(--dark);
}
.search-input button {
  padding: 0.8rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  text-decoration: none;
  background-color: var(--green);
}
.search-input button:hover {
  background-color: var(--green2);
  scale: 0.9;
}
.search-input button > svg {
  font-size: 1rem;
  fill: var(--gray);
}
.dashBoard {
  width: calc(80% - 2rem);
  padding: 1rem;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}
.card {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 0.5rem;
}
.card p {
  font-size: 0.9rem;
  line-height: 1rem;
  font-weight: 600;
  letter-spacing: 0.0605rem;
  color: var(--orange);
}
.css-text-mask {
  text-align: left;
  font-family: basic-sans, sans-serif;
  font-size: 5rem;
  line-height: 5rem;
  font-weight: 800;
  background-position: 0px 0px;
  animation: animatedBackground 60s linear infinite normal;
  background-clip: text;
  -webkit-text-fill-color: #0000;
  background-size: 50%;
  -webkit-text-stroke-width: 1px;
  -webkit-text-stroke-color: #ffffff;
}
.css-text-mask {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mask-one {
  background-image: url(cripto-azul.jpg);
}
.mask-two {
  background-image: url(cripto-dourado.jpg);
}
.mask-three {
  background-image: url(cripto-verde.webp);
  text-transform: lowercase;
}
.mask-four {
  background-image: url(cripto-roxo.webp);
}
.modal {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  justify-content: center;
  align-items: center;
}
.modal-content {
  padding: 1rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  border: 2px solid var(--gray);
  border-radius: 4px;
  background: var(--dark);
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
  color: var(--green);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.125rem;
}
.loader {
  border: 8px solid var(--gray);
  border-top: 8px solid var(--green);
  border-radius: 50%;
  width: 3rem;
  height: 3rem;
  animation: loader-spin 1s linear infinite;
}
@keyframes loader-spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
@keyframes animatedBackground {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: 500px 0;
  }
}
@keyframes float {
  0% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-10px); /* Move para cima */
  }
  100% {
    transform: translateY(0);
  }
}
@media (max-width: 1800px) {
  .css-text-mask {
    font-size: 4.2rem;
  }
}
@media (max-width: 1020px) {
  .css-text-mask {
    font-size: 3rem;
  }
}
@media (max-width: 768px) {
  .css-text-mask {
    font-size: 1.2rem;
  }
}
@media (max-width: 480px) {
  .css-text-mask {
    font-size: 1rem;
  }
}

 

 

Por ultimo adiciono o script  que irá obter a cotação da moeda:

 

const input = document.getElementById("filter-input");
const dropdown = document.querySelector(".select-dropdown");
const optionsList = document.getElementById("optionsList");
const searchButton = document.getElementById("searchButton");
const dashBoard = document.getElementById("dashBoard");
const loadingModal = document.getElementById("loadingModal");
let selectedCripto = null;
const optionsCripto = [
  { label: "Bitcoin", value: "BTC" },
  { label: "Ethereum", value: "ETH" },
  { label: "Litecoin", value: "LTC" },
  { label: "Ripple", value: "XRP" },
  { label: "Cardano", value: "ADA" },
];
function filterOptions() {
  const filter = input.value.toLowerCase();
  const options = optionsList.getElementsByTagName("li");
  let hasVisibleOption = false;
  Array.from(options).forEach((option) => {
    const optionText = option.textContent || option.innerText;
    if (optionText.toLowerCase().includes(filter)) {
      option.style.display = "";
      hasVisibleOption = true;
    } else {
      option.style.display = "none";
    }
  });
  toggleDropdown(hasVisibleOption);
}
function selectOption(optionText, optionValue) {
  input.value = optionText;
  selectedCripto = optionValue;
  toggleDropdown(false);
}
function toggleDropdown(show) {
  dropdown.style.display = show ? "block" : "none";
}
// Eventos
// Adiciona o evento global de clique para fechar o dropdown ao clicar fora
document.addEventListener("click", function (event) {
  if (!input.contains(event.target) && !dropdown.contains(event.target)) {
    toggleDropdown(false); // Fecha o dropdown
  }
});
// Adiciona evento para filtrar opções
input.addEventListener("input", filterOptions);
// Exibe o dropdown ao focar no input
input.addEventListener("focus", () => toggleDropdown(true));
// Adiciona evento de clique para cada opção da lista
optionsList.addEventListener("click", (event) => {
  if (event.target.tagName === "LI") {
    const optionText = event.target.textContent || event.target.innerText;
    const optionValue = event.target.dataset.value;
    selectOption(optionText, optionValue);
  }
});
searchButton.addEventListener("click", async () => {
  showLoading();
  if (selectedCripto) {
    const criptoInfo = await getCotacao(selectedCripto);
    updateCards(criptoInfo);
  } else {
    alert("Selecione uma criptomoeda antes de buscar a cotação.");
  }
  hideLoading();
});
async function loadOptions() {
  try {
    const optionsHTML = optionsCripto
      .map((option) => `<li data-value="${option.value}">${option.label}</li>`)
      .join("");
    optionsList.innerHTML = optionsHTML;
  } catch (error) {
    console.error("Erro ao carregar opções:", error);
  }
}
loadOptions();
async function fetchData(url) {
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`Erro ao buscar dados: ${response.status}`);
  }
  return await response.json();
}
async function getCotacao(cripto) {
  try {
    const [criptoInfoData, criptoCotacaoData] = await Promise.all([
      fetchData(
        `https://api.mercadobitcoin.net/api/v4/symbols?symbols=${cripto}-BRL`
      ),
      fetchData(
        `https://api.mercadobitcoin.net/api/v4/tickers?symbols=${cripto}-BRL`
      ),
    ]);
    // Extração e formatação dos dados
    const { "base-currency": symbol, description, type } = criptoInfoData;
    const { open, last, vol } = criptoCotacaoData[0];
    const variation =
      ((parseFloat(last) - parseFloat(open)) / parseFloat(open)) * 100;  
    const criptoInfo = {
      symbol: symbol[0],
      description: description[0],
      type: type[0],
      lastValue: last,
      variation: variation,
      volume: vol,
    };
    // Exibe o resultado no console
    console.log("Informações da Criptomoeda:", criptoInfo);
    return criptoInfo;
  } catch (error) {
    console.error("Erro ao buscar dados da criptomoeda:", error);
    return null;
  }
}
const updateCards = (criptoInfo) => {
  const cardData = [
    {
      label: "Ativo Selecionado",
      value: criptoInfo.description,
      maskClass: "mask-one",
    },
    { label: "Ticker", value: criptoInfo.symbol, maskClass: "mask-two" },
    {
      label: "Última cotação em (R$)",
      value: formatNumber(criptoInfo.lastValue),
      maskClass: "mask-three",
    },
    { label: "Segmento", value: criptoInfo.type, maskClass: "mask-three" },
    {
      label: "Variação em 24H",
      value: formatPercent(criptoInfo.variation),
      maskClass: "mask-four",
    },
    {
      label: "Volume Movimentado",
      value: formatNumber(criptoInfo.volume),
      maskClass: "mask-one",
    },
  ];
  const dashBoardCards = cardData
    .map((data) => createCard(data.label, data.value, data.maskClass))
    .join("");
  dashBoard.innerHTML = dashBoardCards;
};
const formatNumber = (number) => {
  number = Number(number);
  if (number >= 1e9) {
    return (number / 1e9).toFixed(0) + "B"; // Bilhões
  } else if (number >= 1e6) {
    return (number / 1e6).toFixed(0) + "M"; // Milhões
  } else if (number >= 1e3) {
    return (number / 1e3).toFixed(0) + "K"; // Milhar
  }
  return formatNumberPTBR(number);
};
const formatPercent = (number) => {
  return `${formatNumberPTBR(number)}%`;
};
const formatNumberPTBR = (number) => {
  const formatter = new Intl.NumberFormat("pt-BR", {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  });
  return formatter.format(number);
};
const createCard = (label, value, maskClass) => {
  return `
    <div class="card">
        <div class="css-text-mask ${maskClass}">${value}</div>
        <p>${label}</p>
    </div>
  `;
};
const showLoading = () => {
  loadingModal.style.display = "flex";
};
const hideLoading = () => {
  loadingModal.style.display = "none";
};

 

Você pode visualizar o componente no link abaixo:

DashBoard Cripto 

 

Deixo aqui um vídeo curto do processo de criação do DashBoard:

 

 

Conclusão

Com esses simples  passos, você consegue de forma rápida criar um Cripto Dashboard, usando apenas HTML e CSS.  Caso necessite você pode personalizar estilizar conforme a sua necessidade.

 

Código fonte do tutorial  do Dashboard em Javascript:

Código Fonte

Referências

Api Mercado Bitcoin

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *