{"id":19875497,"url":"https://github.com/igorcbraz/calculadora","last_synced_at":"2025-05-02T10:32:21.996Z","repository":{"id":135228988,"uuid":"385719889","full_name":"Igorcbraz/Calculadora","owner":"Igorcbraz","description":" 📐 Calculadora simples e intuitiva com suporte a comandos de voz e temas personalizados 📏","archived":false,"fork":false,"pushed_at":"2025-01-24T16:05:58.000Z","size":6072,"stargazers_count":35,"open_issues_count":0,"forks_count":10,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-07T01:11:38.911Z","etag":null,"topics":["calculadora","calculadora-javascript","calculator","calculator-application","calculator-javascript","calculator-js","prefer-color-scheme","responsive","speach-to-text","speech-recognition","web-speech-api"],"latest_commit_sha":null,"homepage":"https://medium.com/@igorcbraz/build-a-feature-rich-calculator-with-pure-javascript-20ce17fbe47d","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Igorcbraz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-13T19:53:02.000Z","updated_at":"2025-03-29T13:41:15.000Z","dependencies_parsed_at":"2023-11-11T16:26:57.431Z","dependency_job_id":"2b84b4c3-72e2-43f9-bfa7-c44beafb3d53","html_url":"https://github.com/Igorcbraz/Calculadora","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Igorcbraz%2FCalculadora","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Igorcbraz%2FCalculadora/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Igorcbraz%2FCalculadora/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Igorcbraz%2FCalculadora/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Igorcbraz","download_url":"https://codeload.github.com/Igorcbraz/Calculadora/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252023392,"owners_count":21682180,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["calculadora","calculadora-javascript","calculator","calculator-application","calculator-javascript","calculator-js","prefer-color-scheme","responsive","speach-to-text","speech-recognition","web-speech-api"],"created_at":"2024-11-12T16:28:30.015Z","updated_at":"2025-05-02T10:32:21.988Z","avatar_url":"https://github.com/Igorcbraz.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e \u003ca href=\"https://calculatorcbraz.netlify.app/\"\u003eCalculadora\u003c/a\u003e \u003c/h1\u003e\n\u003ch3 align=\"center\"\u003e\n  Calculadora completa com comandos de voz, atalhos de teclado e temas adaptáveis utilizando apenas JavaScript puro\n\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/github/stars/Igorcbraz/Calculadora?style=social\" alt=\"GitHub Stars\"/\u003e\n  \u003cimg src=\"https://img.shields.io/github/forks/Igorcbraz/Calculadora\" alt=\"Forks\"/\u003e\n  \u003cimg src=\"https://api.netlify.com/api/v1/badges/344dc66c-0b96-4f11-8a84-87fdfed0b4fd/deploy-status\" alt=\"Netlify Status\"/\u003e\n  \u003cimg src=\"https://img.shields.io/github/license/Igorcbraz/Calculadora\" alt=\"MIT License\"/\u003e  \u003cimg src=\"https://img.shields.io/github/issues/Igorcbraz/Calculadora\" alt=\"Issues\"/\u003e\n  \u003cimg src=\"https://img.shields.io/github/last-commit/Igorcbraz/Calculadora\" alt=\"Last Commit\"/\u003e\n  \u003cimg src=\"https://img.shields.io/github/contributors/Igorcbraz/Calculadora\" alt=\"Contributors\"/\u003e\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg align=\"center\" src=\"./images/apple-touch-icon.png\" alt=\"Logo\"/\u003e\n\u003c/div\u003e\n\n## Sobre\n\n\u003cp align=\"justify\"\u003e\nEste projeto foi criado como parte de um desafio, com o objetivo de desenvolver uma calculadora funcional e responsiva. Durante o processo, o escopo foi ampliado para incluir melhorias na arquitetura, acessibilidade e personalização, transformando o desafio em uma aplicação moderna e repleta de funcionalidades usando apenas html, css e javascript evitando ao máximo libs externas.\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg\n    width=\"584px\"\n    height=\"372px\" \n    src=\"https://user-images.githubusercontent.com/82618164/126012518-19b8e31c-6388-48ad-aa82-610bbab838c3.gif\"\n  /\u003e\n  \u003cbr\u003e\n  \u003cspan\u003e\n    Desafio inicial feito por\n    \u003ca href=\"https://www.frontendmentor.io/challenges/calculator-app-9lteq5N29\"\u003e\n    \u003cem\u003eFrontend Mentor\u003c/em\u003e\n    \u003c/a\u003e\n  \u003c/span\u003e\n\u003c/div\u003e\n\n## Tabela de Conteúdos\n\n- [Funcionalidades](#funcionalidades)\n- [Web Speech API](#web-speech-api)\n- [Prefer color scheme](#prefer-color-scheme)\n- [Projetos relacionados](#sugestoes)\n- [Stars](#stars)\n\n## Funcionalidades\n\n- Realizar operações matemáticas básicas (adição, subtração, multiplicação, divisão)\n- Suporte a comandos de voz para facilitar a interação\n- Temas personalizados para a interface (utilizando prefer-color-scheme)\n- Responsividade para diferentes tamanhos de tela\n- Integração com comandos via teclado\n- Shortcuts dinâmicos para troca de temas\n- Guia automático ensinando a utilizar a calculadora\n\n## Web Speech API\n\n\u003e Para desenvolver o recurso de suporte a comando de voz, sem adicionar bibliotecas externas ao projeto, foi utilizado o recurso \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API\" target=\"_blank\"\u003e\u003ccode\u003eWeb Speech API\u003c/code\u003e\u003c/a\u003e\n\nEssa funcionalidade permite utilizar o recurso de áudio do próprio navegador e receber um ou mais resultados do que foi falado, em uma string.\n\nNo projeto, dentro da pasta JS temos o arquivo chamado `Speak.js` com a implementação necessária para a utilização dos comandos de voz, nele primeiro iremos começar a utilizar a web speech api na função `setup`:\n\n```js\nif (!('webkitSpeechRecognition' in window)) {\n  this.#startBtn.disabled = true\n  console.error('Speech recognition not available')\n  return\n}\n\nthis.#recognition = new webkitSpeechRecognition()\nthis.#recognition.continuous = true\nthis.#recognition.lang = 'pt-BR'\nthis.#recognition.interimResults = true\n\nthis.addListeners() // Adiciona o toggle de escutar ou não o usuário\n```\n\nApós a configuração, podemos começar a processar a fala e tomar algumas ações com o que foi dito, na função `start`: \n\n```js\nthis.#recognition.onresult = (event) =\u003e {\n  const results = Object.values(event.results)\n\n  if (results.length) this.#startBtn.classList.add('listening')\n\n  for (const result of results) {\n    const { transcript } = result[0]\n    const { isFinal } = result\n\n    if (isFinal) this.#calculator.executeVoiceCommand(transcript.trim(), this.getVoiceActions())\n  }\n}\n\nthis.#recognition.start()\n```\n\nNesse caso, estamos iniciado o reconhecimento de fala e processando cada resultado (palavra ou frase dita) esperando até o momento da frase final ser completa, exemplo de resultados para uma frase \"2+2\":\n\n1. \"dois\" ou \"2\"\n2. \"mais\" ou \"+\"\n3. \"dois\" ou \"2\"\n4. ao terminar de falar a frase, entender que o resultado final deve ser \"2+2\"\n\nNo caso, é importante executar o comando de voz apenas com a frase final para ter a garantia do contexto como um todo foi processado e estamos obtendo o resultado mais próximo do desejado\n\nPodemos também, lidar com o caso de erro:\n\n```js\nthis.#recognition.onend = () =\u003e {\n  this.updateListeningState(false)\n}\n```\n\n\u003e A função updateListeningState, tem como objetivo alterar o estilo do botão de escuta.\n\nPor fim, iremos precisar configurar uma função para parar de ouvir o usuário e manipular alguns estilos:\n\n```js\nthis.#recognition.stop()\nthis.updateListeningState(false)\nthis.#startBtn.classList.remove('listening')\n```\n\n## Prefer Color Scheme\n\n\u003e Para auxiliar os 3 diferentes temas da calculadora, foi usado o recurso de mídia \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme\" target=\"_blank\"\u003e\u003ccode\u003eprefer-color-scheme\u003c/code\u003e\u003c/a\u003e.\n\nEsse recurso possibilita o entendimento de qual a preferência do usuário em relação aos temas, assim podendo receber dois valores:\n\n- Light (Claro)\n- Dark (Escuro)\n\nA maneira de aplicar esse recurso, no css, de acordo com a developer.mozilla é da seguinte maneira:\n\n```css\n@media (prefers-color-scheme: dark) {\n  /* Configurações CSS para o tema dark */\n}\n\n@media (prefers-color-scheme: light) {\n  /* Configurações CSS para o tema light */ \n}\n```\n\nMas com esse método o código irá ficar mais verboso e provavelmente com difícil manutenção, pois seria necessário repetir todas as propriedades desejadas com suas novas colorações.\n\n### Então qual a solução ? 🤔\n\nIremos apenas mudar os valores das variáveis do CSS com JS.\n\nPrimeiro iremos, na pasta de constantes, verificar o arquivo `themes.js`:\n\n```js\nexport const themes = {\n  'Default': {\n    id: '1',\n    colors: [ { name: '--background', value: '#3a4764' } ]\n  },\n  'Light': {\n    id: '2',\n    colors: [ { name: '--background', value: '#e6e6e6' } ]\n  },\n  'Dark': {\n    id: '3',\n    colors: [ { name: '--background', value: '#17062a' } ]\n  }\n}\n```\nNote o _Nome dos temas_ e os _id's_ utilizados, eles serão utilizados no arquivo `ThemeManager.js`, na pasta JS, da seguinte forma:\n\n```js\nfunction changeThemeById(themeId) {\n  const theme = Object.values(this.themesConfig).find(theme =\u003e theme.id === themeId)\n  if (!theme) return\n\n  this.#btnTheme.value = theme.id\n  this.applyTheme(theme.colors)\n}\n\nfunction setPreferColorSchemeTheme() {\n  if (!this.#btnTheme || !window.matchMedia) return\n\n  Object.keys(this.themesConfig).forEach(themeName =\u003e {\n    const matchedPreferredScheme = window.matchMedia(`(prefers-color-scheme: ${themeName})`)?.matches\n\n    if (matchedPreferredScheme) this.#btnTheme.value = this.themesConfig[themeName].id\n  })\n\n  this.changeThemeById(this.#btnTheme.value)\n}\n```\n\nO objetivo aqui, está em fazer um código para troca de temas de forma versátil e de fácil manutenção.\nNesse caso, conseguimos buscar a preferência do usuário, através do `window.matchMedia('(prefers-color-scheme: ${themeName})')`, concatenado com o nome do nosso tema (que é igual a nomenclatura desejada)\n\nApós descobrir o tema desejado, podemos enviar o id do tema em questão para função `changeThemeById` com objetivo de obter a nova coloração desejada\n\n\u003e Para entender exatamente o que cada função está fazendo, como a `applyTheme`, acesse o arquivo na pasta JS\n\n### Como é Possível fazer o Teste/Debug ? 🤔\n\nCom a ferramenta de devtools do seu navegador, acesse a aba \"Rendering\" e logo após procure o título \"Emulate CSS media feature prefers-colors-scheme\":\n\n\u003cimg width=\"400px\" height=\"300px\" src=\"images/Debug.jpg\"/\u003e\n\nAlterando os valores padrões pelo devtools, o resultado final será:\n\n\u003cimg width=\"584px\" height=\"372px\" src=\"https://user-images.githubusercontent.com/82618164/126012352-7c19f908-f04b-4c66-a568-191bdfa5d8b8.gif\"/\u003e\n\n\u003ch2 id=\"sugestoes\"\u003eVocê também pode gostar\u003c/h2\u003e\n\n- [Gitfest](https://github.com/Igorcbraz/GitFest) - Gere uma lineup de festival com base nos seus principais repositórios do Github\n- [Enkoji](https://github.com/Igorcbraz/Enkoji) - Site feito para o Enkoji, um templo zen-budista japonês fundado em 1920 no Japão\n\n\u003ch2 id=\"stars\"\u003e⭐ Stars ⭐\u003c/h2\u003e\n\n[![Stargazers repo roster for @Igorcbraz/Calculadora](https://reporoster.com/stars/dark/Igorcbraz/Calculadora)](https://github.com/Igorcbraz/Calculadora/stargazers)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figorcbraz%2Fcalculadora","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Figorcbraz%2Fcalculadora","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figorcbraz%2Fcalculadora/lists"}