<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Lais Golin - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Aprenda a codificar - de graça. Tutoriais de programação em Python, JavaScript, Linux e muito mais. ]]>
        </description>
        <link>https://www.freecodecamp.org/portuguese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Lais Golin - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/portuguese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 07 Jun 2026 04:52:02 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/portuguese/news/author/lais/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Como criar uma rolagem horizontal usando Flexbox ]]>
                </title>
                <description>
                    <![CDATA[ Se você desenvolve sites para web, certamente já precisou criar componentes com rolagem horizontal. Com o Flexbox, criar essa barra de rolagem é muito simples. Basta escrever apenas algumas linhas de código. Vou mostrar para você como fazer isso neste artigo. Layout do projeto Vamos precisar criar um contêiner que ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-criar-uma-rolagem-horizontal-usando-o-flexbox/</link>
                <guid isPermaLink="false">633c03c8ffecac05daeb6c9c</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lais Golin ]]>
                </dc:creator>
                <pubDate>Thu, 03 Nov 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/1_8MiXDWg3C4evyq1WtRWTcw.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/horizontal-scrolling-using-flexbox-f9d16817f742/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to implement horizontal scrolling using Flexbox</a>
      </p><p>Se você desenvolve sites para web, certamente já precisou criar componentes com rolagem horizontal. Com o Flexbox, criar essa barra de rolagem é muito simples. Basta escrever apenas algumas linhas de código. Vou mostrar para você como fazer isso neste artigo.</p><h4 id="layout-do-projeto"><strong>Layout do projeto</strong></h4><p>Vamos precisar criar um contêiner que terá todas as imagens que queremos rolar. Aqui está o código: </p><pre><code class="language-html">&lt;div class="container"&gt;
  &lt;img src="images/bhutan1.jpg" alt="Bhutan" /&gt;
  &lt;img src="images/bhutan2.jpg" alt="Bhutan" /&gt;
  &lt;img src="images/bhutan3.jpg" alt="Bhutan" /&gt;
  &lt;img src="images/bhutan4.jpg" alt="Bhutan" /&gt;
  &lt;img src="images/bhutan5.jpg" alt="Bhutan" /&gt;
  &lt;img src="images/bhutan6.jpg" alt="Bhutan" /&gt;
  &lt;img src="images/bhutan7.jpg" alt="Bhutan" /&gt;
&lt;/div&gt;
</code></pre><h4 id="estiliza-o-do-projeto"><strong>Estilização do projeto</strong></h4><p>O próximo passo é adicionar o estilo para que o contêiner role horizontalmente. Para isso, vamos adicionar <code>display: flex</code> ao contêiner. Além disso, estou definindo o valor <code>overflow-x</code> como auto. Abaixo temos o código pronto já com os estilos:</p><pre><code class="language-css">.container {
  display: flex;
  overflow-x: auto;
}
</code></pre><p>A rolagem horizontal deverá ficar dessa maneira:<br></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/OtTK-LibpJ6mcBOeHSmI2wIcXrlzMzzw5VND" class="kg-image" alt="OtTK-LibpJ6mcBOeHSmI2wIcXrlzMzzw5VND" width="406" height="820" loading="lazy"><figcaption>A versão inicial de nossa rolagem horizontal</figcaption></figure><p>Isso já faz com que nossas imagens rolem horizontalmente. Eu, no entanto, não estou muito satisfeito com a aparência. Há três coisas que quero mudar: </p><ul><li>Adicionar um espaçamento entre as imagens.</li><li>Esconder a barra horizontal.</li><li>Centralizar as imagens na tela.</li></ul><p>Vamos começar adicionando um espaçamento entre as imagens. Para isso, vamos adicionar uma margem à direita de 15px. Aqui está o código do CSS:</p><pre><code class="language-css">.container img {
  margin-right: 15px;
}
</code></pre><p>Em seguida, quero esconder a barra de rolagem horizontal e podemos fazer isso usando o código abaixo:</p><pre><code class="language-css">.container::-webkit-scrollbar {
  display: none;
}
</code></pre><p>A última mudança que quero fazer é centralizar as imagens no centro da tela. Por padrão, a altura do html é a altura de seus elementos. Então, precisamos fazer com que a altura do html seja de 100% da viewport.</p><p>Com o Flexbox, podemos centralizar itens usando a propriedade <code>align-items</code>. Para utilizarmos essa propriedade, precisamos adicionar <code>display: flex</code> no elemento <code>body</code> do nosso html. Aqui está o código que adicionaremos ao nosso body:</p><pre><code class="language-css">body {
  display: flex;
  align-items: center;
  height: 100vh;
}
</code></pre><p>Com essas mudanças, esse será o resultado final da nossa barra de rolagem utilizando o Flexbox e escrevendo apenas algumas linhas de código:<br></p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/qJCD4OP64IdYdHTGPKnFVBKhFLrkiIWDrKSe" class="kg-image" alt="qJCD4OP64IdYdHTGPKnFVBKhFLrkiIWDrKSe" width="410" height="824" loading="lazy"></figure><h3 id="conclus-o"><strong>Conclusão</strong></h3><p>Com o Flexbox, é muito fácil criar uma barra de rolagem horizontal. Muito obrigado por ler até o final! :)</p><p>Aqui temos outros artigos (em inglês) que podem ser de seu interesse:</p><ul><li><a href="https://hackernoon.com/here-are-5-layouts-that-you-can-make-with-flexbox-6ca1e941f33d" rel="noopener"><strong><strong>Here are 5 Layouts That You Can Make With FlexBox</strong></strong></a></li><li><strong><strong><a href="https://www.freecodecamp.org/news/learn-css-border-radius-property-by-building-a-calculator-53497cd8071d">Learn the CSS border-radius property by building a calculator</a></strong></strong></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como converter strings para números inteiros em Python ]]>
                </title>
                <description>
                    <![CDATA[ Do mesmo modo que ocorre com o método integrado str(), o Python também oferece o método int(), que recebe um objeto string como argumento e retorna um objeto de número inteiro. Exemplo de utilização: # Aqui, idade é um objeto de string idade = "18" print(idade) # Converter uma string ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-converter-strings-para-numeros-inteiros-em-python/</link>
                <guid isPermaLink="false">633c039bffecac05daeb6c96</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lais Golin ]]>
                </dc:creator>
                <pubDate>Mon, 31 Oct 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/5f9c9dd6740569d1a4ca39e8.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-convert-strings-into-integers-in-python/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Convert Strings into Integers in Python</a>
      </p><p>Do mesmo modo que ocorre com o método integrado <code>str()</code>, o Python também oferece o método <code>int()</code>, que recebe um objeto string como argumento e retorna um objeto de número inteiro.</p><h4 id="exemplo-de-utiliza-o-"><strong>Exemplo de utilização<strong><strong>:</strong></strong></strong></h4><pre><code class="language-py"># Aqui, idade é um objeto de string
idade = "18"
print(idade)

# Converter uma string em um número inteiro
int_idade = int(idade)
print(int_idade)</code></pre><p><strong>Resultado<strong>:</strong></strong></p><pre><code class="language-py">18
18</code></pre><p>Embora o resultado seja muito parecido visualmente, na primeira linha, temos um objeto do tipo string, enquanto na segunda linha temos um objeto do tipo número inteiro. O exemplo abaixo mostrará isso mais claramente: </p><pre><code class="language-py">idade = "18"
print(idade + 2)</code></pre><p><strong>Resultado<strong>:</strong></strong></p><pre><code class="language-py">Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
TypeError: cannot concatenate 'str' and 'int' objects</code></pre><p>No código acima, o erro deve mostrar que, primeiramente, você deve converter <code>idade</code> que é um objeto string para um número inteiro antes de adicionar algo a ele. </p><pre><code class="language-py">idade = "18"
idade_int = int(idade)
print(idade_int + 2)</code></pre><p><strong>Resultado<strong>:</strong></strong></p><pre><code class="language-py">20</code></pre><p>Tenha em mente algumas exceções:</p><ul><li>Um número decimal como argumento retornará um novo número decimal, que será arredondado para baixo e convertido para o número inteiro mais próximo. Por exemplo: <code>print(int(7.9))</code> retornará <code>7</code>. Por outro lado, <code>print(int("7.9"))</code> retornará um erro, uma vez que um número decimal como uma string não poderá ser convertido em um número inteiro. </li></ul><pre><code class="language-py">Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
ValueError: invalid literal for int() with base 10: '7.9'</code></pre><ul><li>Caso tente converter palavras em números inteiros, o resultado retornará o mesmo erro. Por exemplo, <code>print(int("um"))</code> retornará o seguinte:</li></ul><pre><code class="language-py">Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
ValueError: invalid literal for int() with base 10: 'um'</code></pre> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como usar e criar diretivas personalizadas no Angular ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Gulfam Ansari Após explorar o Angular por algum tempo, finalmente consegui uma explicação compreensível para as diretivas do Angular. Neste artigo, vamos entender o que são as diretivas e como utilizá-las no Angular. Também criaremos nossas próprias diretivas personalizadas. Então, o que estamos esperando? Vamos começar! O que ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-usar-e-criar-diretivas-personalizadas-no-angular/</link>
                <guid isPermaLink="false">62d9269dfea2f10707d669ae</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lais Golin ]]>
                </dc:creator>
                <pubDate>Wed, 12 Oct 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/1_A4-tgMN9OZ6gIoRVFDJj_g.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/angular-directives-learn-how-to-use-or-create-custom-directives-in-angular-c9b133c24442/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to use and create custom directives in Angular</a>
      </p><p>Escrito por: Gulfam Ansari</p><p>Após explorar o Angular por algum tempo, finalmente consegui uma explicação compreensível para as diretivas do Angular. Neste artigo, vamos entender o que são as diretivas e como utilizá-las no Angular. Também criaremos nossas próprias diretivas personalizadas. Então, o que estamos esperando? Vamos começar!</p><h3 id="o-que-uma-diretiva-do-angular">O que é uma diretiva do Angular?</h3><p>As diretivas são as funções que serão executadas sempre que o compilador do Angular as encontrar. Elas aprimoram a capacidade dos elementos do HTML anexando comportamentos personalizados ao DOM.</p><p>A partir do conceito central, as diretrizes do Angular são categorizadas em três categorias.</p><ol><li><strong>Diretivas de atributos</strong></li><li><strong>Diretivas estruturais </strong></li><li><strong>Componentes</strong></li></ol><h4 id="diretivas-de-atributos"><strong>Diretivas de atributos</strong></h4><p>As diretivas de atributos são responsáveis pela manipulação da aparência e do comportamento dos elementos do DOM. Sendo assim, podemos usar essas diretivas para alterar o estilo dos elementos. Essas diretivas também são usadas para ocultar ou mostrar elementos específicos de modo condicional. </p><p>O Angular oferece diversas diretivas de atributo incorporadas. Alguns exemplos são a <strong>NgStyle</strong> e a <strong>NgClass</strong>. Também podemos criar nossas próprias diretivas de atributo personalizadas para a funcionalidade desejada.</p><h4 id="diretivas-estruturais"><strong>Diretivas estruturais</strong></h4><p>As diretivas estruturais são responsáveis por mudar a estrutura do DOM. Elas funcionam adicionando ou removendo os elementos do DOM, ao contrário das diretivas de atributos, que apenas alteram a aparência e o comportamento do elemento.</p><p>Você pode facilmente diferenciar as diretivas estruturais e as diretivas de atributos observando apenas a sintaxe. Quando nomeamos uma diretiva estrutural, ela sempre terá como prefixo um asterisco(*), enquanto a diretiva de atributos não contém nenhum prefixo. As três diretivas estruturais do Angular mais populares são <strong>NgIf</strong>, <strong>NgFor</strong>, e <strong>NgSwitch</strong>. </p><h4 id="componentes"><strong>Componentes</strong></h4><p>Os componentes são diretivas com modelos (<em>templates</em>). Essa é a única diferença entre os componentes e os outros dois tipos de diretivas. As diretivas de atributos e as estruturais não têm modelos. Portanto, podemos dizer que o componente é uma versão mais limpa e mais fácil de usar.</p><h3 id="usando-diretivas-integradas-no-angular">Usando diretivas integradas no Angular </h3><p>No Angular, existem muitas diretivas integradas disponíveis, as quais você pode usar facilmente. Nesta seção, usaremos duas diretivas integradas e que são muito simples.</p><p>A diretiva <strong>NgStyle </strong>é uma diretiva de atributo usada para alterar o estilo de qualquer elemento do DOM com base em alguma condição. </p><pre><code class="language-angular">&lt;p [ngStyle]="{'background': isBlue ? 'blue' : 'red'}"&gt;Eu sou uma diretiva de atributo&lt;/p&gt;</code></pre><blockquote>No código acima, estamos adicionando um fundo azul se o valor da variável <code>isBlue</code> for verdadeiro. &nbsp;Se o valor da variável <code>isBlue</code> for falso, o fundo será vermelho. </blockquote><pre><code class="language-angular">&lt;p *ngIf="show"&gt;Eu sou uma diretiva estrutural&lt;/p&gt;</code></pre><blockquote>No código acima, o parágrafo permanecerá no DOM se o valor da variável <code>show</code> for verdadeiro. Do contrário, ele será iniciado juntamente com o DOM.</blockquote><h3 id="criando-uma-diretiva-de-atributo-personalizada"><strong>Criando uma diretiva de atributo personalizada</strong></h3><p>Criar uma diretiva personalizada é exatamente como criar um componente do Angular. Para criar uma diretiva personalizada, precisamos substituir o <em>decorator </em><code>@Component</code> pelo <em>decorator </em><code>@Directive</code>.</p><p>Vamos começar criando nossa primeira diretiva de atributos personalizados. Nessa diretiva, vamos destacar o elemento do DOM selecionado, definindo a cor de fundo de um elemento. </p><p>Crie um arquivo <code>app-highlight.directive.ts</code> dentro da pasta <code>src/app</code> e adicione o código abaixo.</p><pre><code class="language-angular">import {
  Directive,
  ElementRef
} from '@angular/core';
@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {
  constructor(private eleRef: ElementRef) {
    eleRef.nativeElement.style.background = 'red';
  }
}</code></pre><p>No código acima, estamos importando a <code>Directive</code> e o <code>ElementRef</code> do <em>core</em> do Angular. A <code>Directive</code> fornece a funcionalidade do <em>decorator</em> <code>@Directive</code>, onde fornecemos seu seletor de propriedade para <code>appHighLight</code> para que possamos usar esse seletor em qualquer parte da aplicação. Também estamos importando o <code>ElementRef</code>, que é responsável por acessar o elemento do DOM.</p><p>Agora, para que a diretiva <code>appHighlight</code> funcione, precisamos adicionar nossa diretiva ao conjunto de declarações no arquivo <code>app.module.ts</code>.</p><pre><code class="language-angular">import ...;
import { ChangeThemeDirective } from './app-highlight.directive';
@NgModule({
declarations: [
AppComponent,
ChangeThemeDirective
],
imports: [
...
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }</code></pre><p>Usaremos nossa diretiva personalizada recém-criada. Estou adicionando a diretiva <code>appHightlight</code> dentro do arquivo <code>app.component.html</code>, mas você pode usá-la em qualquer outro lugar da sua aplicação.</p><pre><code>&lt;h1 appHightlight&gt;Highlight Me !&lt;/h1&gt;</code></pre><h3 id="criando-uma-diretiva-estrutural-personalizada">Criando uma diretiva estrutural personalizada</h3><p>Na seção anterior, criamos nossa primeira diretiva de atributo. Usaremos a mesma abordagem para criar a diretiva estrutural. </p><p>Começaremos com a criação da nossa diretriz estrutural. Nessa diretiva, vamos implementar a diretiva <code>*appNot</code>, que funcionará de modo exatamente oposto à diretiva <code>*ngIf</code>.</p><p>Crie um arquivo <code>app-not.directive.ts</code> dentro da pasta <code>src/app</code> e cole o código abaixo.</p><pre><code class="language-angular">import {
  Directive,
  Input,
  TemplateRef,
  ViewContainerRef
} from '@angular/core';
@Directive({
  selector: '[appNot]'
})
export class AppNotDirective {
  constructor(
    private templateRef: TemplateRef &lt; any &gt; ,
    private viewContainer: ViewContainerRef) {}
  @Input() set appNot(condition: boolean) {
    if (!condition) {
      this.viewContainer.createEmbeddedView(this.templateRef);
    } else {
      this.viewContainer.clear();
    }
  }
}</code></pre><p>Como observado no código acima, estamos importando <code>Directive</code>, <code>Input</code>, <code>TemplateRef</code> e <code>ViewContainerRef</code> do <code>@angular/core.</code></p><p>A <code>Directive</code> fornece a mesma funcionalidade para o <em>decorator</em> <code>@Directive</code>. O <em>decorator</em> <code>Input</code> é usado para a comunicação entro os dois componentes. Ele envia dados de um componente para outro usando vinculação de propriedade.</p><p>O <code>TemplateRef</code> representa o modelo incorporado, que é usado para instanciar as visualizações incorporadas. Essas visualizações incorporadas são vinculadas ao modelo que deve ser renderizado.</p><p>O <code>ViewContainerRef</code> é um <em>contêiner </em>em que uma ou mais visualizações podem ser anexadas. Podemos usar a função <code>createEmbeddedView()</code> para anexar os modelos embutidos no <em>contêiner</em>.</p><p>Para que a diretiva <code>appNot</code> funcione, precisamos adicionar nossa diretiva ao <em>array</em> de declarações no arquivo <code>app.module.ts</code>.</p><pre><code class="language-angular">import ...;
import { AppNotDirective } from './app-not.directive';
@NgModule({
declarations: [
AppComponent,
AppNotDirective
],
imports: [
...
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }</code></pre><p>Agora, é hora de usarmos nossa diretiva estrutural que acabamos de criar.</p><p>Estou adicionando a diretiva <code>appNot</code> no <code>app.component.html</code>, mas você pode usá-la em qualquer lugar do aplicativo.</p><pre><code>&lt;h1 *appNot="true"&gt;True&lt;/h1&gt;&lt;h1 *appNot="false"&gt;False&lt;/h1&gt;</code></pre><p>A diretiva <code>*appNot</code> é projetada de modo a anexar o elemento modelo no DOM se o valor <code>*appNot</code> for <code>false</code>, exatamente o oposto da diretiva <code>*ngIf</code>.</p><p>A saída do código acima deve ser parecida com esta. </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/Gq-nb90cSoMpnte266GnWRQb3RuUqVESuRAe.png" class="kg-image" alt="Gq-nb90cSoMpnte266GnWRQb3RuUqVESuRAe" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/10/Gq-nb90cSoMpnte266GnWRQb3RuUqVESuRAe.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/10/Gq-nb90cSoMpnte266GnWRQb3RuUqVESuRAe.png 702w" width="702" height="78" loading="lazy"></figure><p>Espero que este artigo tenha respondido à maioria de suas perguntas sobre as diretivas do Angular. Boa programação para você! :)</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Recuperação da conta do Google: como alterar sua senha do Gmail ]]>
                </title>
                <description>
                    <![CDATA[ Há vários motivos pelos quais você pode querer alterar sua senha do Gmail. Talvez você a tenha esquecido ou talvez sua conta tenha sido invadida. Seja qual for o seu motivo, recuperar sua senha é algo simples de fazer. Este guia mostrará para você o passo a passo para fazer ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/recuperacao-da-conta-do-google-como-alterar-sua-senha-do-gmail/</link>
                <guid isPermaLink="false">629bb9f608b5de06cf9f5780</guid>
                
                    <category>
                        <![CDATA[ gmail ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lais Golin ]]>
                </dc:creator>
                <pubDate>Tue, 14 Jun 2022 17:34:27 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/5f9c9874740569d1a4ca1a1f.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/google-account-recovery-change-gmail-password/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Google Account Recovery: How to Change Your Gmail Password</a>
      </p><p>Há vários motivos pelos quais você pode querer alterar sua senha do Gmail. Talvez você a tenha esquecido ou talvez sua conta tenha sido invadida.</p><p>Seja qual for o seu motivo, recuperar sua senha é algo simples de fazer. Este guia mostrará para você o passo a passo para fazer o login na sua conta Google sem problemas.</p><h2 id="como-alterar-a-sua-senha-do-gmail"><strong>Como alterar a sua senha do Gmail</strong></h2><p>Suponhamos que você saiba sua senha atual, mas queira alterá-la por algum motivo qualquer (provavelmente, por motivos de segurança). Neste caso, basta seguir os passos abaixo para alterar a sua senha.</p><h3 id="passo-1-fa-a-o-login-na-sua-conta-do-google-ou-abra-a-se-j-estiver-conectado-"><strong>Passo 1<strong>: faça</strong> o<strong> login na sua conta do Google (ou abra-a se já estiver conectado).</strong></strong></h3><p>Obs.: este não é o seu Gmail. É a sua conta do Google. Você também pode acessar sua conta através deste <a href="https://myaccount.google.com/">link</a>. Veja como ela se parece abaixo: </p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/google-account-home-page.png" class="kg-image" alt="google-account-home-page" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/06/google-account-home-page.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/06/google-account-home-page.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/06/google-account-home-page.png 1211w" sizes="(min-width: 1200px) 1200px" width="1211" height="711" loading="lazy"></figure><p>Você fará o login usando seu nome de usuário e senha atual.</p><h3 id="passo-2-encontre-as-configura-es-de-seguran-a-e-senha"><strong>Passo 2<strong>: </strong>encontre as configurações de segurança e senha</strong></h3><p>Depois de fazer o login, na sua página inicial, você verá uma barra de menu à esquerda. Encontre a guia "Segurança" e clique nela (como mostrado na foto acima). </p><p>Nas configurações de segurança, você pode rolar para baixo até ver "Como fazer login no Google":</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/signing-into-google-1.png" class="kg-image" alt="signing-into-google-1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/06/signing-into-google-1.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/06/signing-into-google-1.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/06/signing-into-google-1.png 1193w" width="1193" height="675" loading="lazy"></figure><p>Você encontrará uma aba onde diz "Senha" (e a última vez que ela foi alterada). Clicando na aba de "Senha", ela o levará até página de login novamente.</p><h3 id="passo-3-altere-sua-senha"><strong>Passo <strong>3: </strong>altere sua senha</strong></h3><p>Basta fazer o login e então você verá a tela abaixo: </p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/Change-password-screen.png" class="kg-image" alt="Change-password-screen" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/06/Change-password-screen.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/06/Change-password-screen.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/06/Change-password-screen.png 1081w" width="1081" height="632" loading="lazy"></figure><p>Neste passo, será pedido a você que insira uma nova senha — e você também receberá algumas dicas sobre como criar uma senha forte e segura.</p><p>Dica: se você tiver um gerenciador de senhas, como o LastPass ou o 1Password, faça com que ele gere e salve uma senha segura para você.</p><p>Você precisará digitar a senha novamente para confirmar que as duas senhas digitadas são iguais. Em seguida, basta clicar em "Alterar senha" (o botão azul na parte inferior). Pronto, agora você pode fazer login novamente no Gmail, YouTube e em todos os outros serviços relacionados ao Google. </p><h2 id="o-que-fazer-se-voc-esqueceu-sua-senha-do-gmail"><strong>O que fazer se você esqueceu sua senha do Gmail</strong></h2><p>Caso tenha esquecido sua senha do Google, não se preocupe — você pode redefinir sua senha seguindo alguns passos. </p><h3 id="passo-1-informe-ao-google-que-voc-n-o-lembra-a-sua-senha"><strong>Passo <strong>1: </strong>informe ao Google que você não lembra a sua senha</strong></h3><p>O Google precisa ter certeza de que é você que está tentando recuperar sua senha. Caso contrário, qualquer pessoa poderia fazer isso para redefinir sua senha sem sua permissão ou conhecimento. </p><p>Primeiro, após digitar seu endereço de e-mail, o Google perguntará qual foi a sua última senha. Mas, presumivelmente, você não se lembra disso, certo? Já que está tentando recuperar a sua senha. &nbsp;</p><p>Neste caso, você pode clicar em "Tente outra maneira de fazer login":</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/gmail-forgot-password.png" class="kg-image" alt="gmail-forgot-password" width="562" height="603" loading="lazy"></figure><h3 id="passo-2-verifique-sua-identidade"><strong>Passo <strong>2: </strong>verifique sua Identidade</strong></h3><p>Este botão o levará até uma tela de verificação com outro método de comunicação selecionado, geralmente por um dispositivo móvel:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/fix-email-address-visible.png" class="kg-image" alt="fix-email-address-visible" width="532" height="624" loading="lazy"></figure><p>Se você clicar em sim, uma nova tela com um código numérico aparecerá, desta maneira:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/google-verification-code.png" class="kg-image" alt="google-verification-code" width="521" height="631" loading="lazy"></figure><p>Um pop-up aparecerá no seu celular (no meu caso, ele veio por Gmail) pedindo para confirmar seu telefone. Clicando no pop-up (ele aparecerá na sua tela, mesmo que ela esteja bloqueada), ele o levará para esta tela:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/phone-verification.png" class="kg-image" alt="phone-verification" width="405" height="492" loading="lazy"></figure><p>Clique em "Sim" e você verá uma nova tela (em seu telefone) com três números. Um deles deve corresponder ao número da página de recuperação de sua conta:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/fix-email-address-visible-2.png" class="kg-image" alt="fix-email-address-visible-2" width="408" height="491" loading="lazy"></figure><p>No meu caso, o 70 corresponde com o número que apareceu na minha conta do Google. Então, eu só preciso confirmar clicando nele. </p><h3 id="passo-3-fa-a-a-verifica-o-final"><strong>Passo <strong>3: </strong>faça a verificação final</strong></h3><p>Em seguida, você será direcionado para outra tela que solicita outra etapa de verificação (geralmente outro endereço de e-mail para o qual o Google pode enviar um código de verificação):</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/second-verification-email-google.png" class="kg-image" alt="second-verification-email-google" width="476" height="609" loading="lazy"></figure><p>Clique em "Enviar" e, em seguida, você receberá um código em seu outro e-mail. Assim que você receber este outro e-mail, basta abrir o seu Gmail. Será algo parecido com a imagem abaixo (com as suas próprias informações): </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/google-email-six-digit-code.png" class="kg-image" alt="google-email-six-digit-code" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/06/google-email-six-digit-code.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/06/google-email-six-digit-code.png 640w" width="640" height="524" loading="lazy"></figure><p>Pegue esse código de seis dígitos e insira-o onde for solicitado no processo de recuperação de conta do Google:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/verification-code-entered-1.png" class="kg-image" alt="verification-code-entered-1" width="502" height="569" loading="lazy"></figure><h3 id="passo-4-insira-uma-nova-senha"><strong>Passo<strong> 4: </strong>insira uma nova senha</strong></h3><p>Após inserir o código de seis dígitos, clique em "Avançar". Você será levado para uma tela onde precisará inserir (e reinserir) sua nova senha escolhida.</p><p>Novamente, você pode criar um ou usar um gerenciador de senhas para gerar uma senha forte para você.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/create-new-password.png" class="kg-image" alt="create-new-password" width="521" height="629" loading="lazy"></figure><p>Em seguida, clique em Avançar, e você terá uma nova senha salva no Google! Basta voltar ao Gmail, ou qualquer outro local que você esteja tentando acessar, e acessar sua conta usando seu e-mail do gmail e a sua nova senha!</p><h2 id="dica-b-nus-como-alterar-os-m-todos-de-verifica-o-da-sua-conta-do-google">Dica bônus: como alterar os métodos de verificação da sua conta do Google</h2><p>Se você tiver um endereço de e-mail desatualizado definido como seu endereço de e-mail de "backup" ou de recuperação, será necessário alterá-lo.</p><p>Volte para <a href="https://myaccount.google.com/">https://myaccount.google.com/</a> e clique na guia Segurança novamente. Role um pouco para baixo e você verá "Maneiras de verificar sua identidade".</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/change-recovery-info.png" class="kg-image" alt="change-recovery-info" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/06/change-recovery-info.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/06/change-recovery-info.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/06/change-recovery-info.png 1175w" width="1175" height="492" loading="lazy"></figure><p>Se você precisar mudar seu número de telefone e/ou e-mail, basta clicar em uma das opções acima e ela o levará para uma tela onde você poderá atualizar essas informações. Por motivos de segurança, o Google fará com que você faça o login novamente.<br></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como criar seu portfólio com React.js ]]>
                </title>
                <description>
                    <![CDATA[ Depois que meus amigos cancelaram nossos planos para o final de semana, eu estava procurando algo para passar o tempo. Olhando para minha longa lista de coisas a fazer, finalmente tive a ideia de criar um portfólio. Após muitas horas pesquisando tecnologias e modelos, acabei criando este site [https://dhruv34788.github.io/me/] usando ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-criar-seu-portfolio-usando-react-js/</link>
                <guid isPermaLink="false">62797e89357c22053df616dd</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lais Golin ]]>
                </dc:creator>
                <pubDate>Mon, 06 Jun 2022 18:58:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/1_7snm7ve4mLm3kwrPl0r2ig-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/portfolio-app-using-react-618814e35843/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to create your portfolio website using React.js</a>
      </p><p>Depois que meus amigos cancelaram nossos planos para o final de semana, eu estava procurando algo para passar o tempo. Olhando para minha longa lista de coisas a fazer, finalmente tive a ideia de criar um portfólio.</p><p>Após muitas horas pesquisando tecnologias e modelos, acabei criando este <a href="https://dhruv34788.github.io/me/">site</a> usando React.js e as páginas do GitHub. &nbsp;Você pode encontrar o código para o portfólio <a href="https://github.com/Dhruv34788/me">aqui</a> (é tecnicamente chamado de '<strong>web-app</strong>', mas, para este artigo, vou me referir a ele como um "site"... espero que não seja um problema).</p><h2 id="o-que-voc-vai-aprender"><strong>O que você vai aprender</strong></h2><ul><li>Alguns conceitos básicos de React.js</li><li>Como usar o create-react-app a partir de um site HTML</li><li>Como implantar seu portfólio usando as 'páginas do Github '</li></ul><h2 id="alguns-conceitos-que-voc-precisa-saber-antes-de-come-armos-">Alguns conceitos que você precisa saber antes de começarmos...</h2><blockquote><em>Obs.:<em> </em></em>sinta-se à vontade para pular esta parte se você já estiver familiarizado com os conceitos básicos de React.js e React Components.<br><br>Esses pontos apresentarão uma ideia muito básica do mundo do React. Recomendo que você estude mais sobre o React a partir da <a href="https://reactjs.org/docs/getting-started.html">documentação</a> (em inglês) e coloque a mão na massa com a ajuda do <a href="https://www.freecodecamp.org/">freeCodeCamp</a>.</blockquote><h3 id="o-que-o-react-js"><strong>O que é o React.js</strong></h3><p>Por enquanto, basta saber que React.js é uma biblioteca JavaScript usada para construir componentes de Interface do Usuário. Ele foi criado pelos engenheiros do Facebook e hoje em dia, está balançando o mundo JavaScript...</p><h3 id="o-que-um-react-component"><strong>O que é um React Component </strong></h3><p>O React permite definir componentes como uma classe ou uma função. Você pode fornecer entradas opcionais para os componentes chamadas de "<strong><strong>props</strong></strong>".</p><p>Os componentes permitem dividir a Interface do Usuário em seções <strong>independentes</strong>, como cabeçalho, rodapé e corpo. Cada componente funcionará de modo independente para que qualquer componente individual possa ser renderizado independentemente no ReactDOM sem afetar a página inteira.</p><p>Ele também vem com '<strong><strong>lifecycle methods</strong></strong>' <em>(métodos de ciclo de vida, em tradução livre)</em> e que permitem definir blocos de código que você deseja executar de acordo com o estado do componente, como montagem, renderização, atualização e desmontagem.</p><p>Os componentes do React têm suas próprias vantagens e desvantagens. Por exemplo, podemos reutilizar um componente exportando-o para outros componentes, mas às vezes fica confuso lidar com vários componentes conversando e acionando renderizações um para o outro.</p><p>Esta é a aparência de um React Component: </p><pre><code class="language-jsx">import React, { Component } from 'react'

export default class Component-name extends Component {
  render() {
    return (
      &lt;div&gt;
        {código que será renderizado no DOM}
      &lt;/div&gt;
    )
  }
}</code></pre><h3 id="o-que-o-github-pages"><strong>O que é o <a href="https://pages.github.com/" rel="noopener">GitHub Pages</a></strong></h3><p>Com o GitHub Pages, você pode implantar facilmente seu site usando o GitHub gratuitamente e sem a necessidade de configurar nenhuma infraestrutura. Eles forneceram módulos para que você não precise se preocupar com muitas coisas. Se você ler este artigo até o final, verá que funciona como MÁGICA!</p><h2 id="antes-de-prosseguir-certifique-se-de-">Antes de prosseguir, certifique-se de... <br></h2><h3 id="decidir-qual-o-conte-do-que-voc-deseja-colocar-em-seu-site"><strong>Decidir qual o conteúdo que você deseja colocar em seu site </strong></h3><p>Revise seu último currículo (caso você ainda não tenha um, que tal <a href="https://resumegenius.com/resume-templates">criar um agora</a> e adiar este projeto até o próximo fim de semana?). Isso ajudará você a ter uma ideia clara sobre o tipo de informação que deseja colocar no seu portfólio.</p><h3 id="encontrar-inspira-o"><strong>Encontrar inspiração</strong></h3><p>Navegue pelas centenas de modelos de sites de portfólio gratuitos, veja como e o que você pode usar deles - pegue uma caneta e papel e esboce um diagrama para ter uma ideia de como você gostaria que fosse o seu portfólio. Vou usar <a href="https://colorlib.com/preview/#jackson">este modelo</a> para demonstrar.</p><h3 id="selecionar-algumas-fotos-pessoais"><strong>Selecionar algumas fotos pessoais</strong></h3><p>É claro que você não quer parecer mal em seu próprio portfólio. Então, explore seus arquivos para encontrar as fotos perfeitas para o seu site.</p><h3 id="colocar-a-sua-playlist-favorita"><strong>Colocar a sua playlist favorita</strong></h3><p>Diz a lenda que <strong>coisas boas sempre vêm acompanhadas de boa música...</strong> e é claro que você não quer perder a parte boa, não é?</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/1_7snm7ve4mLm3kwrPl0r2ig.png" class="kg-image" alt="1_7snm7ve4mLm3kwrPl0r2ig" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/06/1_7snm7ve4mLm3kwrPl0r2ig.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/06/1_7snm7ve4mLm3kwrPl0r2ig.png 800w" sizes="(min-width: 720px) 720px" width="800" height="500" loading="lazy"><figcaption><a href="https://dbarochiya.github.io/me/" rel="noopener">Uma olhada rápida no site do meu portfólio</a></figcaption></figure><h2 id="vamos-para-a-parte-de-constru-o"><strong>Vamos para a parte de construção</strong></h2><p>Nas seções a seguir, descreverei as etapas para a criação do portfólio, mas você não precisa seguir o mesmo código que eu uso. Concentre-se em aprender os conceitos e mostre alguma criatividade! A leitura complementar foi dividida em três seções.</p><ol><li>Configurando o React-app</li><li>Separando a página HTML em componentes do React</li><li>Implementando seu aplicativo usando as páginas do GitHub</li></ol><h3 id="configurando-o-react-app">Configurando o<strong> React-app</strong></h3><p>Usaremos o <code><a href="https://facebook.github.io/create-react-app/docs/getting-started">create-react-app</a></code> — um módulo fornecido pelo Facebook — que nos ajuda a criar aplicativos React.js com facilidade e sem se preocupar com ferramentas de construção.</p><ul><li>Abra o seu console e execute o seguinte comando <code>npm install create-react-app</code> para instalar este módulo via npm (certifique-se de ter instalado o &nbsp;<code>npm</code> antes de executar o código — caso tenha dúvidas, acesse esse <a href="https://www.rosehosting.com/blog/install-npm-on-ubuntu-16-04/">link</a> para mais informações).</li><li>Execute <code>npm create-react-app ${nome-do-projeto}</code> que buscará scripts de compilação e criará uma estrutura de arquivos parecida com o código abaixo: </li></ul><pre><code>my-portfolio-app
├── README.md (descrição do projeto para o GitHUb)
├── node_modules (armazena todos os módulos de dependências do projeto)
├── package.json (armazena todas as metainformações do projeto, como quais são as dependências, versões, revisões etc.)
├── .gitignore (arquivos declarados aqui serão ignorados ao fazer o upload para o GitHub, como a pasta node_modules 
├── public (aqui, você armazenará todos os arquivos de imagens, JS e CSS) 
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json 
└── src (o código principal do nosso app fica aqui)
    ├── {crie a pasta dos componentes - components - aqui}
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    └── serviceWorker.js</code></pre><p>Criei uma pasta <code>components</code> sob o diretório <code>src</code>. É nela que armazenaremos nossos componentes no futuro.</p><ul><li>Copie todas as imagens, fontes, arquivos HTML e CSS do <code>template</code> HTML com o qual você decidiu trabalhar para a pasta <code>public</code>.</li></ul><p>O diretório do seu projeto deve ficar assim.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/1_IcnlLThnGN65xfgkFpnnBg.png" class="kg-image" alt="1_IcnlLThnGN65xfgkFpnnBg" width="598" height="838" loading="lazy"><figcaption>Estrutura de arquivos</figcaption></figure><ul><li>Execute <code>npm install</code>, que instalará os módulos de dependências no diretório <code>node_modules</code>.</li><li>Se você seguiu todos os passos corretamente até agora, a execução do comando <code>npm start</code> iniciará o aplicativo React no <code>localhost</code>. Digite &nbsp;<a href="https://localhost:3000/" rel="noopener"><code>https://localhost:3000</code></a> no seu navegador e você poderá ver a página inicial do React.</li></ul><h3 id="separando-a-p-gina-html-em-componentes-do-react">Separando a página HTML em componentes do React</h3><p>Lembra da pasta <code>component</code> que criamos no diretório <code>src</code> na etapa anterior? Agora vamos dividir a página do modelo HTML em componentes e combinar esses componentes para criar nosso React-app.</p><ul><li>Primeiro, você precisa identificar quais componentes você pode criar a partir do arquivo HTML — como cabeçalho, rodapé e página/componente de contato. Seja criativo nesta etapa!</li><li>Procure por tags como <em>section/div</em> que não estão aninhadas em alguma outra <em><em>section/div</em></em>. Elas devem conter código sobre essa seção específica da página que é independente de outras seções. Tente dar uma olhada no meu <a href="https://github.com/Dhruv34788/me">repositório do GitHub</a> para ter uma ideia melhor.<br><em>Dica: use a ferramenta <strong>"Inspecionar elemento"</strong> para brincar com o código e observar o efeito das alterações no navegador.</em></li><li>Esses trechos de código HTML serão usados no método <code>render()</code> do componente. O método <code>render()</code> retornará este código sempre que um componente for renderizado no ReactDOM. Dê uma olhada nos blocos de código abaixo para referência.</li></ul><figure class="kg-card kg-code-card"><pre><code class="language-jsx">&lt;section id="colorlib-hero" class="js-fullheight" data-section="home"&gt;
    &lt;div class="flexslider js-fullheight"&gt;
        &lt;ul class="slides"&gt;
        &lt;li style="background-image: url(images/img_bg_1.jpg);"&gt;
            &lt;div class="overlay"&gt;&lt;/div&gt;
            &lt;div class="container-fluid"&gt;
                &lt;div class="row"&gt;
                    &lt;div class="col-md-6 col-md-offset-3 col-md-pull-3 col-sm-12 col-xs-12 js-fullheight slider-text"&gt;
                        &lt;div class="slider-text-inner js-fullheight"&gt;
                            &lt;div class="desc"&gt;
                                &lt;h1&gt;Hi! &lt;br&gt;I'm Jackson&lt;/h1&gt;
                                &lt;h2&gt;100% html5 bootstrap templates Made by &lt;a href="https://colorlib.com/" target="_blank"&gt;colorlib.com&lt;/a&gt;&lt;/h2&gt;
                                    &lt;p&gt;&lt;a class="btn btn-primary btn-learn"&gt;Download CV &lt;em class="icon-download4"&gt;&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
                                &lt;/div&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/li&gt;
        &lt;li style="background-image: url(images/img_bg_2.jpg);"&gt;
            &lt;div class="overlay"&gt;&lt;/div&gt;
            &lt;div class="container-fluid"&gt;
                &lt;div class="row"&gt;
                    &lt;div class="col-md-6 col-md-offset-3 col-md-pull-3 col-sm-12 col-xs-12 js-fullheight slider-text"&gt;
                        &lt;div class="slider-text-inner"&gt;
                            &lt;div class="desc"&gt;
                                &lt;h1&gt;I am &lt;br&gt;a Designer&lt;/h1&gt;
                                    &lt;h2&gt;100% html5 bootstrap templates Made by &lt;a href="https://colorlib.com/" target="_blank"&gt;colorlib.com&lt;/a&gt;&lt;/h2&gt;
                                    &lt;p&gt;&lt;a class="btn btn-primary btn-learn"&gt;View Portfolio &lt;em class="icon-briefcase3"&gt;&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
                                &lt;/div&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/li&gt;
        &lt;/ul&gt;
    &lt;/div&gt;
&lt;/section&gt;</code></pre><figcaption>Seção 'home' do arquivo HTML</figcaption></figure><figure class="kg-card kg-code-card"><pre><code class="language-jsx">import React, { Component } from 'react'

export default class Home extends Component {
  render() {
    return (
      &lt;div&gt;
        &lt;section id="colorlib-hero" className="js-fullheight" data-section="home"&gt;
            &lt;div className="flexslider js-fullheight"&gt;
                &lt;ul className="slides"&gt;
                &lt;li style={{backgroundImage: 'url(images/img_bg_1.jpg)'}}&gt;
                    &lt;div className="overlay" /&gt;
                    &lt;div className="container-fluid"&gt;
                    &lt;div className="row"&gt;
                        &lt;div className="col-md-6 col-md-offset-3 col-md-pull-3 col-sm-12 col-xs-12 js-fullheight slider-text"&gt;
                        &lt;div className="slider-text-inner js-fullheight"&gt;
                            &lt;div className="desc"&gt;
                            &lt;h1&gt;Hi! &lt;br /&gt;I'm Jackson&lt;/h1&gt;
                            &lt;h2&gt;100% html5 bootstrap templates Made by &lt;a href="https://colorlib.com/" target="_blank"&gt;colorlib.com&lt;/a&gt;&lt;/h2&gt;
                            &lt;p&gt;&lt;a className="btn btn-primary btn-learn"&gt;Download CV &lt;em className="icon-download4" /&gt;&lt;/a&gt;&lt;/p&gt;
                            &lt;/div&gt;
                        &lt;/div&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/li&gt;
                &lt;li style={{backgroundImage: 'url(images/img_bg_2.jpg)'}}&gt;
                    &lt;div className="overlay" /&gt;
                    &lt;div className="container-fluid"&gt;
                    &lt;div className="row"&gt;
                        &lt;div className="col-md-6 col-md-offset-3 col-md-pull-3 col-sm-12 col-xs-12 js-fullheight slider-text"&gt;
                        &lt;div className="slider-text-inner"&gt;
                            &lt;div className="desc"&gt;
                            &lt;h1&gt;I am &lt;br /&gt;a Designer&lt;/h1&gt;
                            &lt;h2&gt;100% html5 bootstrap templates Made by &lt;a href="https://colorlib.com/" target="_blank"&gt;colorlib.com&lt;/a&gt;&lt;/h2&gt;
                            &lt;p&gt;&lt;a className="btn btn-primary btn-learn"&gt;View Portfolio &lt;em className="icon-briefcase3" /&gt;&lt;/a&gt;&lt;/p&gt;
                            &lt;/div&gt;
                        &lt;/div&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/li&gt;
                &lt;/ul&gt;
            &lt;/div&gt;
        &lt;/section&gt;
      &lt;/div&gt;
    )
  }
}</code></pre><figcaption>Componente do React criado a partir da seção HTML 'home'</figcaption></figure><p>Dica: se você estiver ficando muito confuso com o React - tente focar no conceito de 'como identificar os componentes desejados a partir da base de código HTML'. Depois de ficar confortável com o React, a implementação será muito fácil.</p><p>Você notou que há algumas mudanças no código HTML? <code>class</code> se tornou <code>className</code>. Estas mudanças são necessárias porque React não suporta HTML ? - eles criaram sua própria sintaxe HTML como JS, que é chamada JSX . Portanto, precisamos alterar algumas partes do código HTML para torná-lo JSX.</p><p>Para facilitar o processo, encontrei este <a href="https://magic.reactjs.net/htmltojsx.htm">conversor de HTML para JSX</a> durante este projeto, que converte o código HTML em JSX automaticamente. Eu recomendo o uso deste em vez de mudar seu código manualmente.</p><p>Depois de algum tempo, você deve encontrar alguns componentes diferentes. Agora o <code>EndGame</code> está próximo! Reuna todos estes diferentes componentes sob um único componente em <code>App.js</code> (SIM! Você pode renderizar um componente de outro componente!) e seu portfólio estará pronto!</p><figure class="kg-card kg-code-card"><pre><code class="language-jsx">import React, { Component } from 'react';
import './App.css';
import Sidebar from './components/sidebar'
import Introduction from './components/introduction'
import About from './components/about'
import Projects from './components/projects'
import Blog from './components/blog'
import Timeline from './components/timeline'

class App extends Component {
  render() {
    return (
      &lt;div id="colorlib-page"&gt;
        &lt;div id="container-wrap"&gt;
		&lt;Sidebar&gt;&lt;/Sidebar&gt;
		&lt;div id="colorlib-main"&gt;
			&lt;Introduction&gt;&lt;/Introduction&gt;
			&lt;About&gt;&lt;/About&gt;
			&lt;Projects&gt;&lt;/Projects&gt;
			&lt;Blog&gt;&lt;/Blog&gt;
			&lt;Timeline&gt;&lt;/Timeline&gt;
          	&lt;/div&gt;
      	&lt;/div&gt;
      &lt;/div&gt;
    );
  }
}

export default App;</code></pre><figcaption>Reunindo todos os componentes em App.js</figcaption></figure><p>Observe no código acima que precisamos primeiro importar os componentes para então usá-los na seção <code>render()</code>. E podemos usar os componentes apenas adicionando a tag <code>&lt;component-name&gt;&lt;/component-name&gt;</code> &nbsp;ou apenas a tag <code>&lt;component-name/&gt;</code> no método render.</p><ul><li>Execute <code>npm start</code> no seu terminal e você poderá ver as alterações refletidas no site. Você não precisa executar este comando novamente se tiver feito mais alterações no código, ele será executado automaticamente quando você salvar essas alterações. Você pode fazer um desenvolvimento extremamente rápido graças ao recurso de <code><a href="https://facebook.github.io/react-native/blog/2016/03/24/introducing-hot-reloading" rel="noopener">hot reload</a></code>.</li><li>Brinque com o HTML e CSS para mudar o conteúdo de acordo com seu currículo e tornar seu portfólio ainda mais legal mudando o conteúdo, experimentando diferentes fontes, mudando as cores e adicionando suas fotos.</li></ul><h2 id="implementando-o-seu-aplicativo-usando-as-p-ginas-do-github">Implementando o seu aplicativo usando as páginas do GitHub</h2><p>Bom, então você sobreviveu até este ponto... aproveite para apreciar seu trabalho duro. Mas você ainda precisa concluir sua implantação para poder compartilhar seu trabalho com seus amigos.</p><ul><li>Primeiro, você precisa instalar a biblioteca npm das páginas do GitHub. Para instalar, execute este comando <code><em><em>npm install gh-pages</em></em></code> no seu terminal. </li></ul><p>Depois de instalada, você precisa fazer as seguintes alterações em seu arquivo <code><em><em>manifest.json</em></em></code>: </p><ul><li>Adicione o campo <code><em><em>homepage</em></em></code> — &nbsp;estará no seguinte formato: <code><a href="https://%7Bgithub_id%7D.github.io/%7Bgithub_repo%7D" rel="noopener">https://{github_id}.github.io/{github_repo}</a></code></li><li>Adicione os arquivos <code><em><em>predeploy</em></em></code> e <code><em><em>deploy</em></em></code> em <code><em><em>scripts</em></em></code></li></ul><p>Agora o seu <code>manifest.json</code> deverá estar parecido com este:</p><figure class="kg-card kg-code-card"><pre><code class="language-json">{
	"name": "portfolio-app",
	"version": "0.1.0",
	"private": true,
	"homepage": "https://Dhruv34788.github.io/me",
	"dependencies": {
		"gh-pages": "^2.0.1",
		"react": "^16.8.3",
		"react-dom": "^16.8.3",
		"react-scripts": "2.1.5",
		"yarn": "^1.13.0"},
	"scripts": {
		"start": "react-scripts start",
		"build": "react-scripts build",
		"predeploy": "yarn run build",
		"deploy": "gh-pages -d build",
		"test": "react-scripts test",
		"eject": "react-scripts eject"},
	"eslintConfig": {
		"extends": "react-app"},
	"browserslist": [
		"&gt;0.2%",
		"not dead",
		"not ie &lt;= 11",
		"not op_mini all"
	]
}</code></pre><figcaption>manifest.json após adicionar o link das gh-pages</figcaption></figure><p>Agora vá para o terminal, execute <code>npm run deploy</code> e espere até que a mágica aconteça! Seu aplicativo será implantado depois que os scripts de implantação forem executados com êxito. Verifique se seu aplicativo foi implantado ou não visitando o link fornecido no campo <code>homepage</code>.</p><p><em><strong>Cuidado:</strong></em> tenha cuidado ao implantar qualquer coisa na web. Realize verificações de segurança, como remover links internos, senhas ou qualquer coisa que você não queira que esteja nas mãos de pessoas inteligentes por aí.</p><h2 id="se-voc-vai-fazer-mudan-as-com-frequ-ncia-">Se você vai fazer mudanças com frequência...</h2><blockquote><em>Obs.: v</em>ocê vai precisar fazer essa implantação cada vez que alterar algo no seu código - e adivinhe quem vai ficar entediado em breve? &nbsp;( Não se preocupe, eu te ajudo :P<em><em>)</em></em><br><br>Você pode automatizar o processo de implantação usando o Travis-CI (ferramenta de automação), de modo que, se você confirmar qualquer coisa na branch master/main, as etapas de implantação serão acionadas e o novo site estará disponível automaticamente. Basta seguir o artigo abaixo.<br><br><a href="https://www.freecodecamp.org/news/learn-how-to-automate-deployment-on-github-pages-with-travis-ci/">https://www.freecodecamp.org/news/learn-how-to-automate-deployment-on-github-pages-with-travis-ci/</a></blockquote><h2 id="li-o-de-casa-"><strong>Lição de casa...</strong></h2><p>Muito bem! Você finalmente criou e implementou seu portfolio usando React! Caso esteja interessado em aperfeiçoar seu portfólio ainda mais, você pode incluir os recursos abaixo: </p><ul><li><strong><strong>Blog:</strong> </strong>você pode criar o seu próprio blog usando Node.js e MongoDB.</li><li><strong>Galeria<strong>:</strong></strong> adicione uma seção onde você pode mostrar suas últimas postagens nas mídias sociais. </li><li><strong>Feed do <strong>Twitter:</strong></strong> você pode criar uma seção onde mostra os seus recentes tuítes.</li><li><strong>Citações aleatórias<strong>:</strong></strong> pode criar uma seção mostrando algumas citações motivacionais aleatórias. </li></ul><p>Se você implementar qualquer uma desses recursos, fique à vontade para compartilhar o seu trabalho comigo. Eu ficaria mais do que feliz em ajudar, se eu puder, é claro. </p><h2 id="concluindo-"><strong>Concluindo... </strong></h2><p>Gostaria de dedicar um momento para reconhecer o trabalho das pessoas que me deram a inspiração e o conhecimento para concluir este artigo..</p><ul><li><a href="https://www.freecodecamp.org/news/portfolio-app-using-react-618814e35843/undefined" rel="noopener"><strong><strong><em><em>Quincy </em></em></strong></strong></a><strong><strong><em><em>Larson, <a href="https://www.freecodecamp.org/news/portfolio-app-using-react-618814e35843/undefined" rel="noopener">Sahat Yalkabov</a> </em></em></strong><em>e toda a </em><strong><em><em>com</em></em></strong><em>unidade</em><strong><em><em>:</em></em></strong></strong> pela a criação do <strong><strong><em><em>freeCodeCamp —</em></em></strong><em> </em></strong>uma plataforma ondevocê pode aprender sobre qualquer assunto relacionado a tecnologia, com tutoriais práticos e totalmente gratuita.</li><li><strong><strong><em><em>Colorlib:</em></em></strong></strong> por fornecer ótimos templates que foram extramente importantes e inspiradores para a criação do meu portfólio. </li><li><a href="https://www.freecodecamp.org/news/portfolio-app-using-react-618814e35843/undefined" rel="noopener"><strong><strong><em><em>Daniel Lo Nigro</em></em></strong></strong></a><strong><strong><em><em> </em></em></strong><em>e</em><strong><em><em> </em></em></strong><em>a comunidade</em><strong><em><em>:</em></em></strong></strong> por criarem o <a href="https://magic.reactjs.net/htmltojsx.htm" rel="noopener"><strong><strong><em><em>HTML to JSX </em></em></strong></strong></a><strong><strong><em><em>Compiler, </em></em></strong></strong>que acabou sendo útil ao converter blocos HTML em código JSX. </li><li><strong><em>Meus queridos amigos</em><strong><em><em>:</em></em></strong></strong> que me ajudaram corrigindo meus erros.</li><li><strong>VOCÊ<strong>:</strong></strong> por ter chegado até aqui. Espero que tenha tido um tempo produtivo e que continue explorando e construindo coisas incríveis!</li></ul><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/06/0_FgSZRsUOdqfFZJBY.jpg" class="kg-image" alt="0_FgSZRsUOdqfFZJBY" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/06/0_FgSZRsUOdqfFZJBY.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/06/0_FgSZRsUOdqfFZJBY.jpg 800w" sizes="(min-width: 720px) 720px" width="800" height="533" loading="lazy"><figcaption>Foto: <a href="https://unsplash.com/@docrowdee?utm_source=medium&amp;utm_medium=referral" rel="noopener">Ruediger Theiselmann</a>, extraída do <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral" rel="noopener">Unsplash</a></figcaption></figure> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como validar formulários reativos no Angular ]]>
                </title>
                <description>
                    <![CDATA[ Introdução Neste artigo, aprenderemos sobre a validação de formulários reativos em Angular. Criaremos um formulário simples de registro de usuário e implementaremos algumas validações integradas nele. Juntamente com as validações integradas, também vamos implementar algumas validações personalizadas para o formulário reativo. Consideraremos as seguintes validações personalizadas para esta demonstração:  ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-validar-formularios-reativos-no-angular/</link>
                <guid isPermaLink="false">6254277a6daab205304b1029</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lais Golin ]]>
                </dc:creator>
                <pubDate>Tue, 12 Apr 2022 19:53:45 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/5f9c9e95740569d1a4ca3de6.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-validate-angular-reactive-forms/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Validate Angular Reactive Forms</a>
      </p><h3 id="introdu-o">Introdução</h3><p>Neste artigo, aprenderemos sobre a validação de formulários reativos em Angular. Criaremos um formulário simples de registro de usuário e implementaremos algumas validações integradas nele. Juntamente com as validações integradas, também vamos implementar algumas validações personalizadas para o formulário reativo.</p><p>Consideraremos as seguintes validações personalizadas para esta demonstração:</p><ul><li>Verificar a disponibilidade do nome do usuário</li><li>Validar o padrão de senha</li><li>Validar a senha digitada em dois campos diferentes</li></ul><p>Veja a aplicação em ação:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/reactiveFormValidation.gif" class="kg-image" alt="reactiveFormValidation" width="650" height="648" loading="lazy"></figure><h2 id="pr-requisitos">Pré-requisitos</h2><ul><li>Instalar o Visual Studio Code por este <a href="https://code.visualstudio.com/">link</a></li><li>Instalar a versão mais atualizada da Angular CLI por este <a href="https://cli.angular.io/">link</a> </li></ul><h2 id="c-digo-fonte"><strong>Código-fonte </strong></h2><p>Obtenha o código-fonte pelo <a href="https://github.com/AnkitSharma-007/angular-forms-validation">GitHub</a>.</p><h2 id="criando-a-aplica-o-em-angular"><strong>Criando a aplicação em Angular</strong></h2><p>Navegue até a pasta onde deseja criar seu arquivo de projeto. Abra uma janela de comando e execute o comando mostrado abaixo:</p><pre><code>ng new angular-forms-validation --routing=false --style=scss</code></pre><p>Estamos especificando o comando para criar uma nova aplicação em Angular. A opção de criar o módulo de roteamento é definida como falsa e a extensão de arquivos de estilo é definida como <code>scss</code>. Este comando criará o projeto em Angular com o nome de <code>angular-forms-validation</code>.</p><p>Altere os diretórios, vá para o novo projeto e abra-o no Visual Studio Code usando os comandos mostrados abaixo:</p><pre><code>cd angular-forms-validation 
code .</code></pre><h2 id="instalando-o-bootstrap"><strong>Instalando o Bootstrap</strong></h2><p>Execute o comando abaixo para instalar a biblioteca do Bootstrap na pasta do projeto:</p><pre><code>npm install bootstrap --save</code></pre><p>Adicione a seguinte definição de importação no arquivo <code>styles.scss</code>:</p><pre><code>@import "~bootstrap/dist/css/bootstrap.css";</code></pre><h2 id="criando-o-servi-o-de-valida-o"><strong>Criando o serviço de validação</strong></h2><p>Execute o comando abaixo para criar um novo serviço: </p><pre><code>ng g s services\customvalidation</code></pre><p>Este comando criará uma pasta nomeada serviços com dois arquivos — <code>customvalidation.service.ts</code> e <code>customvalidation.service.spec.ts</code>. Abra o arquivo <code>customvalidation.service.ts</code> e cole o código abaixo:</p><pre><code class="language-js">import { Injectable } from '@angular/core';
import { ValidatorFn, AbstractControl } from '@angular/forms';
import { FormGroup } from '@angular/forms';

@Injectable({
  providedIn: 'root'
})
export class CustomvalidationService {

  patternValidator(): ValidatorFn {
    return (control: AbstractControl): { [key: string]: any } =&gt; {
      if (!control.value) {
        return null;
      }
      const regex = new RegExp('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9]).{8,}$');
      const valid = regex.test(control.value);
      return valid ? null : { invalidPassword: true };
    };
  }

  MatchPassword(password: string, confirmPassword: string) {
    return (formGroup: FormGroup) =&gt; {
      const passwordControl = formGroup.controls[password];
      const confirmPasswordControl = formGroup.controls[confirmPassword];

      if (!passwordControl || !confirmPasswordControl) {
        return null;
      }

      if (confirmPasswordControl.errors &amp;&amp; !confirmPasswordControl.errors.passwordMismatch) {
        return null;
      }

      if (passwordControl.value !== confirmPasswordControl.value) {
        confirmPasswordControl.setErrors({ passwordMismatch: true });
      } else {
        confirmPasswordControl.setErrors(null);
      }
    }
  }

  userNameValidator(userControl: AbstractControl) {
    return new Promise(resolve =&gt; {
      setTimeout(() =&gt; {
        if (this.validateUserName(userControl.value)) {
          resolve({ userNameNotAvailable: true });
        } else {
          resolve(null);
        }
      }, 1000);
    });
  }

  validateUserName(userName: string) {
    const UserList = ['ankit', 'admin', 'user', 'superuser'];
    return (UserList.indexOf(userName) &gt; -1);
  }
}</code></pre><p>O método <code>patternValidator</code> é usado para validar o padrão de senha em nosso formulário. O parâmetro para este método é o tipo <code>AbstractControl</code>, que é uma classe base para <code>FormControl</code>.</p><p>Usaremos uma expressão regular para validar a senha. Validaremos as quatro condições a seguir usando a expressão regular:</p><ul><li>A senha deve ter um mínimo de oito caracteres.</li><li>Precisa ter pelo menos uma letra minúscula.</li><li>Precisa ter pelo menos uma letra maiúscula.</li><li>Precisa ter pelo menos um número.</li></ul><p>Se a senha falhar na verificação pela regex, definiremos a propriedade <code>invalidPassword</code> como verdadeira.</p><p>O método <code>MatchPassword</code> é usado para comparar as senhas em dois campos. Este método aceitará dois parâmetros do tipo String. Estes parâmetros representam o nome dos campos a serem correspondidos. Pegaremos o &nbsp;<code>FormControl</code> para esses dois campos e, em seguida, igualaremos os valores neles. Se os valores não coincidirem, definiremos a propriedade <code>passwordMismatch</code> como verdadeira.</p><p>O método <code>userNameValidator</code> é usado para verificar se o nome de usuário já foi usado anteriormente ou não. Este método aceitará um parâmetro do tipo <code>AbstractControl</code>. Verificaremos se o valor deste campo está presente em um array estático, <code>UserList</code>. Se o valor inserido pelo usuário já estiver presente, definiremos a &nbsp;propriedade <code>userNameNotAvailable</code> como verdadeira.</p><p>Estamos usando a função <code>setTimeout</code> para executar esta verificação a cada dois segundos. Isso garantirá que o erro será acionado após dois segundos a partir do momento em que o usuário parar de digitar no campo.</p><blockquote>Para simplificar este artigo, estamos usando um array estático para pesquisar a disponibilidade de nomes de usuário. Idealmente, deveria ser uma chamada de serviço ao servidor para pesquisar o valor em um banco de dados.</blockquote><h2 id="criando-o-componente-reactive-form"><strong>Criando o componente</strong> reactive-form</h2><p>Execute o seguinte comando para criar o componente &nbsp;reactive-form: </p><pre><code>ng g c reactive-form</code></pre><p>Abra <code>reactive-form.component.ts</code> e cole o código abaixo:</p><pre><code class="language-js">import { Component, OnInit } from '@angular/core';
import { Validators, FormGroup, FormBuilder } from '@angular/forms';
import { CustomvalidationService } from '../services/customvalidation.service';

@Component({
  selector: 'app-reactive-form',
  templateUrl: './reactive-form.component.html',
  styleUrls: ['./reactive-form.component.scss']
})
export class ReactiveFormComponent implements OnInit {

  registerForm: FormGroup;
  submitted = false;

  constructor(
    private fb: FormBuilder,
    private customValidator: CustomvalidationService
  ) { }

  ngOnInit() {
    this.registerForm = this.fb.group({
      name: ['', Validators.required],
      email: ['', [Validators.required, Validators.email]],
      username: ['', [Validators.required], this.customValidator.userNameValidator.bind(this.customValidator)],
      password: ['', Validators.compose([Validators.required, this.customValidator.patternValidator()])],
      confirmPassword: ['', [Validators.required]],
    },
      {
        validator: this.customValidator.MatchPassword('password', 'confirmPassword'),
      }
    );
  }

  get registerFormControl() {
    return this.registerForm.controls;
  }

  onSubmit() {
    this.submitted = true;
    if (this.registerForm.valid) {
      alert('Form Submitted succesfully!!!\n Check the values in browser console.');
      console.table(this.registerForm.value);
    }
  }
}</code></pre><p>Criaremos a variável <code>registerForm</code> do tipo <code>FormGroup</code>. No método <code>ngOnInit</code>, estabeleceremos os controles para o formulário usando a classe <code>FormBuilder</code>. Todos os campos são definidos como um campo obrigatório para este formulário. Chamaremos o método <code>userNameValidator</code> do serviço usando a função <code>bind</code>.</p><p>Para o campo de senha, usaremos o método de composição para mesclar em vários validadores em uma única função. Também invocaremos o método <code>MatchPassword</code> e passaremos o nome de <code>password</code> e <code>confirmPassword</code> como parâmetros.</p><p>A propriedade <code>registerFormControl</code> retornará os controles de formulário. O método <code>onSubmit</code> imprimirá o conteúdo do formulário no console se o formulário for válido e enviado com sucesso.</p><p>Agora, abra <code>reactive-form.component.html</code> e cole nele o código a seguir:</p><pre><code class="language-html">&lt;div class="container"&gt;
    &lt;div class="row"&gt;
        &lt;div class="col-md-8 mx-auto"&gt;
            &lt;div class="card"&gt;
                &lt;div class="card-header"&gt;
                    &lt;h3&gt;Angular Reactive Form&lt;/h3&gt;
                &lt;/div&gt;
                &lt;div class="card-body"&gt;
                    &lt;form class="form" [formGroup]="registerForm" (ngSubmit)="onSubmit()"&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;Name&lt;/label&gt;
                            &lt;input type="text" class="form-control" formControlName="name"&gt;
                            &lt;span class="text-danger"
                                *ngIf="(registerFormControl.name.touched || submitted) &amp;&amp; registerFormControl.name.errors?.required"&gt;
                                Name is required
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;Email&lt;/label&gt;
                            &lt;input type="text" class="form-control" formControlName="email"&gt;
                            &lt;span class="text-danger"
                                *ngIf="(registerFormControl.email.touched || submitted) &amp;&amp; registerFormControl.email.errors?.required"&gt;
                                Email is required
                            &lt;/span&gt;
                            &lt;span class="text-danger"
                                *ngIf="registerFormControl.email.touched &amp;&amp; registerFormControl.email.errors?.email"&gt;
                                Enter a valid email address
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;User Name&lt;/label&gt;
                            &lt;input type="text" class="form-control" formControlName="username"&gt;
                            &lt;span class="text-danger"
                                *ngIf="(registerFormControl.username.touched || submitted) &amp;&amp; registerFormControl.username.errors?.required"&gt;
                                User Name is required
                            &lt;/span&gt;
                            &lt;span class="text-danger"
                                *ngIf="registerFormControl.username.touched &amp;&amp; registerFormControl.username.errors?.userNameNotAvailable"&gt;
                                User Name is not available
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;Password&lt;/label&gt;
                            &lt;input type="password" class="form-control" formControlName="password"&gt;
                            &lt;span class="text-danger"
                                *ngIf="(registerFormControl.password.touched || submitted) &amp;&amp; registerFormControl.password.errors?.required"&gt;
                                Password is required
                            &lt;/span&gt;
                            &lt;span class="text-danger"
                                *ngIf="registerFormControl.password.touched &amp;&amp; registerFormControl.password.errors?.invalidPassword"&gt;
                                Password should have minimum 8 characters, at least 1 uppercase letter, 1 lowercase
                                letter and 1 number
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;label&gt;Confirm Password&lt;/label&gt;
                            &lt;input type="password" class="form-control" formControlName="confirmPassword"&gt;
                            &lt;span class="text-danger"
                                *ngIf="(registerFormControl.confirmPassword.touched || submitted)&amp;&amp; registerFormControl.confirmPassword.errors?.required"&gt;
                                Confirm Password is required
                            &lt;/span&gt;
                            &lt;span class="text-danger"
                                *ngIf="registerFormControl.confirmPassword.touched &amp;&amp; registerFormControl.confirmPassword.errors?.passwordMismatch"&gt;
                                Passwords doesnot match
                            &lt;/span&gt;
                        &lt;/div&gt;
                        &lt;div class="form-group"&gt;
                            &lt;button type="submit" class="btn btn-success"&gt;Register&lt;/button&gt;
                        &lt;/div&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</code></pre><p>Criaremos um reactive-form e usaremos o card do Bootstrap para a estilização. O cabeçalho do nosso card terá um título, enquanto o corpo terá os campos do formulário. Vincularemos a propriedade <code>formGroup</code> da tag &nbsp;<code>&lt;form&gt;</code> ao nome do nosso formulário, que é <code>registerForm</code>. O método <code>onSubmit</code> será invocado ao enviar o formulário. Também vincularemos a &nbsp;propriedade <code>formControlName</code> de cada campo de entrada ao nome de controle do nosso <code>FormGroup</code>. Verificaremos se há erros nos controles do formulário e, em seguida, exibiremos a mensagem de erro de validação apropriada na tela. </p><p>Execute o seguinte comando para criar o componente nav-bar:</p><pre><code>ng g c nav-bar</code></pre><p>Abra <code>nav-bar.component.html</code> e cole o código abaixo:</p><pre><code class="language-html">&lt;nav class="navbar navbar-expand-sm navbar-dark bg-dark fixed-top"&gt;
    &lt;a class="navbar-brand" [routerLink]='["/"]'&gt;Form Validation Demo&lt;/a&gt;
    &lt;div class="collapse navbar-collapse"&gt;
        &lt;ul class="navbar-nav mr-auto"&gt;
            &lt;li class="nav-item"&gt;
                &lt;a class="nav-link" [routerLink]='["/reactive-form"]'&gt;Reactive Form&lt;/a&gt;
            &lt;/li&gt;
        &lt;/ul&gt;
    &lt;/div&gt;
&lt;/nav&gt;</code></pre><p>Estamos adicionando o link de navegação ao componente da reactive-form na barra de navegação. </p><h2 id="atualizando-o-componente-do-aplica-o"><strong>Atualizando o componente do aplicação</strong></h2><p>Abra o arquivo <code>app.component.html</code> e cole nele o código abaixo:</p><pre><code class="language-html">&lt;app-nav-bar&gt;&lt;/app-nav-bar&gt;
&lt;div class="container"&gt;
  &lt;router-outlet&gt;&lt;/router-outlet&gt;
&lt;/div&gt;</code></pre><h2 id="atualizando-o-m-dulo-da-aplica-o"><strong>Atualizando o módulo da aplicação</strong></h2><p>Adicione o código a seguir no arquivo <code>app.module.ts</code>. Vamos importar o módulo de formulários e definir o roteamento para nossa aplicação. Você pode consultar <a href="https://github.com/AnkitSharma-007/angular-forms-validation/blob/master/src/app/app.module.ts">GitHub</a> para obter o código-fonte completo deste arquivo.</p><pre><code class="language-js">import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from  '@angular/forms';

@NgModule({
  ...    
  imports: [
    ...
    ReactiveFormsModule,
    RouterModule.forRoot([
      { path: '', component: ReactiveFormComponent },
      { path: 'reactive-form', component: ReactiveFormComponent }
    ]),
  ],
})</code></pre><h2 id="demonstra-o-da-execu-o"><strong>Demonstração da execução</strong></h2><p>Usaremos o comando abaixo para iniciar o servidor:</p><pre><code>ng serve -o</code></pre><p>Este comando iniciará a aplicação no seu navegador. Caso não abra automaticamente, você pode digitar <code>http://localhost:4200/</code> na barra do seu navegador. Você pode realizar todas as validações de formulário que vimos aqui.</p><p>Esta aplicação também está hospedada em <a href="https://ng-forms-validation.herokuapp.com/">https://ng-forms-validation.herokuapp.com/</a>. Navegue até o link e faça alguns testes para uma melhor compreensão.</p><h2 id="resumo"><strong>Resumo</strong></h2><p>Criamos um modelo de formulário de registro de usuário utilizando a abordagem reactive-form no Angular. Também implementamos as validações integradas e personalizadas no formulário. Por fim, utilizamos a biblioteca do Bootstrap para a estilização. </p><p>Você pode obter o código-fonte no <a href="https://github.com/AnkitSharma-007/angular-forms-validation">GitHub</a> e fazer alguns testes para uma melhor compreensão.</p><p>Você pode encontrar outras publicações como esta no blog do autor, <a href="https://ankitsharmablogs.com/">Ankit Sharma</a> <em>(em inglês)</em>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como construir uma calculadora HTML do zero usando JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ Este é um artigo épico onde você aprende a construir uma calculadora do zero. Vamos nos concentrar no JavaScript que você precisa escrever — como pensar em construir a calculadora, como escrever o código e, por fim, como limpar seu código. Até o final do artigo, você deve obter uma ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-construir-uma-calculadora-html-do-zero-usando-javascript/</link>
                <guid isPermaLink="false">623ae7126a6ca90519acf52c</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lais Golin ]]>
                </dc:creator>
                <pubDate>Mon, 04 Apr 2022 19:54:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/03/0_7GfUdSILXBLyAbQy.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-build-an-html-calculator-app-from-scratch-using-javascript-4454b8714b98/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to build an HTML calculator app from scratch using JavaScript</a>
      </p><p>Este é um artigo épico onde você aprende a construir uma calculadora do zero. Vamos nos concentrar no JavaScript que você precisa escrever — como pensar em construir a calculadora, como escrever o código e, por fim, como limpar seu código.</p><p>Até o final do artigo, você deve obter uma calculadora que funcione exatamente como a do iPhone (sem as funcionalidades +/- e porcentagem). </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/Cw7jNVIhWFV4NSNY8-Lv8uX4583Hr5LvzYFq.gif" class="kg-image" alt="Cw7jNVIhWFV4NSNY8-Lv8uX4583Hr5LvzYFq" width="800" height="719" loading="lazy"></figure><h3 id="pr-requisitos"><strong>Pré-requisitos</strong></h3><p>Antes de começar o tutorial, certifique-se que tenha um bom domínio de JavaScript. No mínimo, você precisa conhecer: </p><ol><li><a href="https://zellwk.com/blog/js-if-else" rel="noopener">Instruções if/else</a> (texto explicativo em inglês)</li><li><a href="https://zellwk.com/blog/js-for-loops" rel="noopener">Laços for</a> (texto explicativo em inglês)</li><li><a href="https://zellwk.com/blog/js-functions" rel="noopener">Funções em JavaScript</a> (texto explicativo em inglês)</li><li><a href="https://zellwk.com/blog/es6/#arrow-functions" rel="noopener">Arrow functions</a> (texto explicativo em inglês)</li><li><code>&amp;&amp;</code> e <code>||</code> operadores</li><li>Como alterar o texto com a propriedade <code>textContent</code></li><li>Como adicionar <code>eventListeners</code> com o padrão de delegação de evento. </li></ol><h3 id="antes-de-come-ar"><strong>Antes de começar</strong></h3><p>Eu recomendo que você tente construir a calculadora sozinho antes de seguir o tutorial. É uma boa prática, porque você treinará pensar como um desenvolvedor. </p><p>Volte para o tutorial após ter tentado por uma hora (não importa se você teve sucesso ou não). Quando você tenta, você pensa, e isso o ajudará a absorver o tutorial duas vezes mais rápido. </p><p>Bom, vamos começar a entender como funciona uma calculadora. </p><h3 id="construindo-a-calculadora"><strong>Construindo a calculadora</strong></h3><p>Primeiro, vamos construir a calculadora. &nbsp;</p><p>A calculadora consiste em duas partes: o display e &nbsp;as teclas. </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/rfV0r9RtFghhau8sZU5CzOFMuJAT1H48tFeL.png" class="kg-image" alt="rfV0r9RtFghhau8sZU5CzOFMuJAT1H48tFeL" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/rfV0r9RtFghhau8sZU5CzOFMuJAT1H48tFeL.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/rfV0r9RtFghhau8sZU5CzOFMuJAT1H48tFeL.png 800w" sizes="(min-width: 720px) 720px" width="800" height="738" loading="lazy"></figure><pre><code class="language-html">&lt;div class=”calculator”&gt;
  &lt;div class=”calculator__display”&gt;0&lt;/div&gt;
  &lt;div class=”calculator__keys”&gt; … &lt;/div&gt;
&lt;/div&gt;</code></pre><p>Podemos usar o CSS Grid para criar as teclas, uma vez que elas já estão dispostas em um formato de grade. Isto já foi criado no arquivo inicial. Você pode encontrar o arquivo inicial <a href="https://codepen.io/zellwk/pen/pLgmGL">neste link</a>. </p><pre><code class="language-css">.calculator__keys { 
  display: grid; 
  /* o resto do CSS necessário */ 
}</code></pre><p>Para identificarmos os operadores, chaves decimais, limpador de tela e sinal de igual, vamos criar um atributo de ação de dados que descreve o que eles fazem. </p><pre><code class="language-html">&lt;div class="calculator__keys"&gt;
  &lt;button class="key--operator" data-action="add"&gt;+&lt;/button&gt;
  &lt;button class="key--operator" data-action="subtract"&gt;-&lt;/button
  &lt;button class="key--operator" data-action="multiply"&gt;&amp;times;&lt;/button&gt;
  &lt;button class="key--operator" data-action="divide"&gt;÷&lt;/button
  &lt;button&gt;7&lt;/button&gt;
  &lt;button&gt;8&lt;/button&gt;
  &lt;button&gt;9&lt;/button&gt;
  &lt;button&gt;4&lt;/button&gt;
  &lt;button&gt;5&lt;/button&gt;
  &lt;button&gt;6&lt;/button&gt;
  &lt;button&gt;1&lt;/button&gt;
  &lt;button&gt;2&lt;/button&gt;
  &lt;button&gt;3&lt;/button&gt;
  &lt;button&gt;0&lt;/button&gt;
  &lt;button data-action="decimal"&gt;.&lt;/button&gt;
  &lt;button data-action="clear"&gt;AC&lt;/button&gt;
  &lt;button class="key--equal" data-action="calculate"&gt;=&lt;/button&gt;
&lt;/div&gt;</code></pre><h3 id="ouvindo-as-teclas"><strong>Ouvindo as teclas</strong></h3><p>Cinco coisas que podem acontecer quando alguém pega uma calculadora. Elas podem apertar:</p><ol><li>um número (0–9)</li><li>um operador (+, -, ×, ÷)</li><li>uma tecla decimal</li><li>a tecla de igual </li><li>a tecla para limpar</li></ol><p>Os primeiros passos para construir a calculadora são: &nbsp;(1) ouvir todas as teclas (2) determinar quais teclas foram pressionadas. Neste caso, podemos usar um padrão de delegação de eventos para ouvir as teclas, já que todas as teclas são filhas de <code>.calculator__keys</code>.</p><pre><code class="language-js">const calculator = document.querySelector(‘.calculator’)
const keys = calculator.querySelector(‘.calculator__keys’)

keys.addEventListener(‘click’, e =&gt; {
 if (e.target.matches(‘button’)) {
   // Fazer algo
 }
})</code></pre><p>Em seguida, &nbsp;podemos usar o atributo <code>data-action</code> para determinar qual tecla foi clicada.</p><pre><code class="language-js">const key = e.target
const action = key.dataset.action</code></pre><p>Se a tecla não tiver um atributo <code>data-action</code>, ela deve ser uma tecla numérica.</p><figure class="kg-card kg-code-card"><pre><code class="language-js">if (!action) {
  console.log('number key!')
}</code></pre><figcaption>O console.log informará que foi pressionada uma tecla numérica</figcaption></figure><p>Se a tecla tiver um atributo <code>data-action</code> que seja <code>add</code>, <code>subtract</code>, <code>multiply</code> ou <code>divide</code>, sabemos que a tecla é um operador.</p><figure class="kg-card kg-code-card"><pre><code class="language-js">if (
  action === 'add' ||
  action === 'subtract' ||
  action === 'multiply' ||
  action === 'divide'
) {
  console.log('operator key!')
}</code></pre><figcaption>O console.log informará que foi pressionada uma tecla de operação</figcaption></figure><p>Se a tecla <code>data-action</code> for <code>decimal</code>, sabemos que o usuário clicou sobre a chave decimal.</p><p>Seguindo o mesmo pensamento, se a tecla <code>data-action</code> for <code>clear</code>, sabemos que o usuário clicou na tecla de limpar (aquela que diz AC). Se a chave <code>data-action</code> for <code>calculate</code>, sabemos que o usuário clicou na tecla de iguais.</p><figure class="kg-card kg-code-card"><pre><code class="language-js">if (action === 'decimal') {
  console.log('decimal key!')
}

if (action === 'clear') {
  console.log('clear key!')
}

if (action === 'calculate') {
  console.log('equal key!')
}</code></pre><figcaption>O console.log informará que foi pressionada a tecla do decimal, de limpeza da tela e do sinal de igual, respectivamente</figcaption></figure><p>Neste momento, você deve conseguir visualizar pelo <code>console.log</code>, uma resposta para cada tecla clicada.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/lbXTncsu2Ni5V-Ejx6RYCO-kW8XJm7f5woGC" class="kg-image" alt="lbXTncsu2Ni5V-Ejx6RYCO-kW8XJm7f5woGC" width="800" height="450" loading="lazy"></figure><h3 id="construindo-o-caminho-ideal"><strong>Construindo o caminho ideal</strong></h3><p>Vamos considerar o que um usuário comum faria quando pegasse um calculadora. <strong>Esse "o que um usuário comum faria" é chamado de caminho ideal</strong>.</p><p>Vamos chamar nosso usuário de Mary.</p><p>Quando Mary pega a calculadora, ela pode clicar em qualquer uma dessas teclas: </p><ol><li>uma tecla numérica (0–9)</li><li>uma tecla de operador (+, -, ×, ÷)</li><li>uma tecla decimal</li><li>a tecla do sinal de igual</li><li>a tecla para limpar (AC)</li></ol><p>Pode ser muito pensar nas cinco teclas clicadas de uma só vez, então vamos passo a passo.</p><h3 id="quando-o-usu-rio-clica-em-uma-tecla-num-rica"><strong>Quando o usuário clica em uma tecla numérica</strong></h3><p>Neste ponto, se a calculadora mostrar 0 (o número padrão), o número clicado deve substituir zero.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/mpr4JFLSU-MHaq8LPMedsaDxnU5Y-MTx56SU.gif" class="kg-image" alt="mpr4JFLSU-MHaq8LPMedsaDxnU5Y-MTx56SU" width="800" height="709" loading="lazy"></figure><p>Se a calculadora mostrar um número diferente de zero, o número clicado deve ser incluído no número exibido. </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/PNfa-nAlgIBtFt1MaVEDvuzisaIps6Kdb482.gif" class="kg-image" alt="PNfa-nAlgIBtFt1MaVEDvuzisaIps6Kdb482" width="800" height="709" loading="lazy"></figure><p>Agora, precisamos saber de duas coisas:</p><ol><li>Qual tecla foi clicada</li><li>O número atual exibido </li></ol><p>Podemos obter esses dois valores através da propriedade <code>textContent</code> da tecla clicada e <code>.calculator__display</code>, respectivamente.</p><pre><code class="language-js">const display = document.querySelector('.calculator__display')

keys.addEventListener('click', e =&gt; {
  if (e.target.matches('button')) {
    const key = e.target
    const action = key.dataset.action
    const keyContent = key.textContent
    const displayedNum = display.textContent
    // ...
  }
})</code></pre><p><strong>Se a calculadora mostrar 0, queremos substituir o visor da calculadora pela tecla clicada.</strong> Podemos fazer isso substituindo o texto do visor por uma propriedade textContent.</p><pre><code class="language-js">if (!action) {
  if (displayedNum === '0') {
    display.textContent = keyContent
  }
}</code></pre><p><strong>Se a calculadora mostrar um número diferente de zero, queremos incluir a tecla clicada ao número exibido. </strong>Para incluir um número, concatenaremos uma string.</p><pre><code class="language-js">if (!action) {
  if (displayedNum === '0') {
    display.textContent = keyContent
  } else {
    display.textContent = displayedNum + keyContent
  }
}</code></pre><p>Neste momento, Mary pode clicar em qualquer uma destas teclas:</p><ol><li>Uma tecla decimal</li><li>Uma tecla de operador</li></ol><p>Suponhamos que Mary clicou em uma tecla decimal.</p><h3 id="quando-um-usu-rio-aperta-a-tecla-decimal"><strong>Quando um usuário aperta a tecla decimal </strong></h3><p>Quando Mary aperta a tecla decimal, um decimal deve aparecer no visor. Se Mary aperta qualquer outro número decimal, ele deverá ser exibido no visor. </p><p>Para criar este efeito, podemos concatenar <code>.</code> ao número exibido. </p><pre><code class="language-js">if (action === 'decimal') {
  display.textContent = displayedNum + '.'
}</code></pre><p>Em seguida, suponhamos que Mary continua seu cálculo apertando a tecla de algum operador.</p><h3 id="quando-o-usu-rio-aperta-uma-tecla-de-opera-o"><strong>Quando o usuário aperta uma tecla de operação &nbsp;</strong></h3><p>Se Mary apertar uma tecla de operação, ele deverá ser destacado, desta maneira, Mary sabe que este operador está ativo. </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/VarwRgJGrN0mwcgYGpX1Zw54QRfbXdMmQNEG.gif" class="kg-image" alt="VarwRgJGrN0mwcgYGpX1Zw54QRfbXdMmQNEG" width="800" height="709" loading="lazy"></figure><p>Para isso, podemos adicionar a classe <code>is-depressed</code> a tecla do operador.</p><pre><code class="language-js">if (
  action === 'add' ||
  action === 'subtract' ||
  action === 'multiply' ||
  action === 'divide'
) {
  key.classList.add('is-depressed')
}</code></pre><p>Uma vez que Mary tenha clicado em uma tecla do operador, ela clicará outra tecla numérica.</p><h3 id="quando-o-usu-rio-clica-em-um-n-mero-ap-s-selecionar-um-operador"><strong>Quando o usuário clica em um número após selecionar um operador</strong></h3><p>Quando Mary selecionar um novo número, o número que estava no visor deverá ser substituído pelo novo número selecionado. A tecla do operador também deve liberar seu estado de pressão.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/GDuLfupPob7rW0UWTH6RqI5CuQX36vcILKwo.gif" class="kg-image" alt="GDuLfupPob7rW0UWTH6RqI5CuQX36vcILKwo" width="800" height="709" loading="lazy"></figure><p>Para liberar a tecla do operador selecionado, retiramos a classe <code>is-depressed</code> de todos os <code>forEach</code> loops:</p><pre><code class="language-js">keys.addEventListener('click', e =&gt; {
  if (e.target.matches('button')) {
    const key = e.target
    // ...
    
    // Remove a classe .is-depressed de todas as teclas
    Array.from(key.parentNode.children)
      .forEach(k =&gt; k.classList.remove('is-depressed'))
  }
})</code></pre><p>A seguir, queremos atualizar o visor para a tecla selecionada. Antes de fazermos isso, precisamos verificar se a tecla anterior é uma tecla de operador. </p><p>Uma maneira de fazer isso é através de um atributo personalizado. Chamaremos esse atributo personalizado de <code>data-previous-key-type</code>.</p><pre><code class="language-js">const calculator = document.querySelector('.calculator')
// ...

keys.addEventListener('click', e =&gt; {
  if (e.target.matches('button')) {
    // ...
    
    if (
      action === 'add' ||
      action === 'subtract' ||
      action === 'multiply' ||
      action === 'divide'
    ) {
      key.classList.add('is-depressed')
      // Adiciona um atributo personalizado
      calculator.dataset.previousKeyType = 'operator'
    }
  }
})</code></pre><p>Se o <code>previousKeyType</code> é um operador, queremos substituir o número exibido por um número clicado.</p><pre><code class="language-js">const previousKeyType = calculator.dataset.previousKeyType

if (!action) {
  if (displayedNum === '0' || previousKeyType === 'operator') {
    display.textContent = keyContent
  } else {
    display.textContent = displayedNum + keyContent
  }
}</code></pre><p>Em seguida, suponhamos que Mary decide completar seu cálculo, apertando a tecla do sinal de igual (=). </p><h3 id="quando-um-usu-rio-aperta-a-tecla-do-sinal-de-igual"><strong>Quando um usuário aperta a tecla do sinal de igual</strong></h3><p>Quando Mary pressiona a tecla do sinal de igual (=), a calculadora deveria calcular um resultado que depende de três valores: </p><ol><li>O <strong>primeiro número</strong> inserido na calculadora</li><li>O <strong>operador</strong></li><li>O <strong>segundo número</strong> inserido na calculadora</li></ol><p>Após o cálculo, o resultado deve substituir o valor exibido. </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/56105259-5aea-4a51-bfff-495aedc8a099.gif" class="kg-image" alt="56105259-5aea-4a51-bfff-495aedc8a099" width="800" height="709" loading="lazy"></figure><p>Neste momento, &nbsp;sabemos apenas o <strong>segundo número</strong> — ou seja, o número que está sendo exibido atualmente.</p><pre><code class="language-js">if (action === 'calculate') {
  const secondValue = displayedNum
  // ...
}</code></pre><p>Para obter o <strong>primeiro número</strong>, precisamos armazenar o valor exibido da calculadora antes de limpá-la. Uma maneira de salvar este primeiro número é adicioná-lo a um atributo personalizado quando o botão do operador for clicado.</p><p>Para obter o <strong>operador</strong>, também podemos utilizar a mesma técnica.</p><pre><code class="language-js">if (
  action === 'add' ||
  action === 'subtract' ||
  action === 'multiply' ||
  action === 'divide'
) {
  // ...
  calculator.dataset.firstValue = displayedNum
  calculator.dataset.operator = action
}</code></pre><p>Assim que tivermos os três valores necessários, podemos fazer um cálculo. Eventualmente, queremos que o código se pareça com algo assim:</p><pre><code class="language-js">if (action === 'calculate') {
  const firstValue = calculator.dataset.firstValue
  const operator = calculator.dataset.operator
  const secondValue = displayedNum
  
  display.textContent = calculate(firstValue, operator, secondValue)
}</code></pre><p>Isso significa que precisamos criar uma função <code>calculate</code>. Ela deve ter três parâmetros: o primeiro número, o operador, e o segundo número.</p><pre><code class="language-js">const calculate = (n1, operator, n2) =&gt; {
  // Realizar um cálculo e retornar o valor calculado
}</code></pre><p>Se o operador for <code>add</code>, queremos somar os dois valores. Se o operador for <code>subtract</code>, queremos subtrair os valores, e assim por diante.</p><pre><code class="language-js">const calculate = (n1, operator, n2) =&gt; {
  let result = ''
  
  if (operator === 'add') {
    result = n1 + n2
  } else if (operator === 'subtract') {
    result = n1 - n2
  } else if (operator === 'multiply') {
    result = n1 * n2
  } else if (operator === 'divide') {
    result = n1 / n2
  }
  
  return result
}</code></pre><p>Lembre-se de que <code>firstValue</code> e <code>secondValue</code> são strings. Se juntar os dois valores, você vai concatená-los (<code>1 + 1 = 11</code>).</p><p>Portanto, antes de calcular o resultado, queremos converter strings em números. Podemos fazer isso com as funções <code>parseInt</code> e <code>parseFloat</code>.</p><ul><li><code>parseInt</code> converte uma string em um número <strong>inteiro</strong>.</li><li><code>parseFloat</code> converte uma string em um <strong>um número de ponto flutuante</strong> (um número com casas decimais).</li></ul><p>Para uma calculadora, precisamos de um número com casas decimais.</p><pre><code class="language-js">const calculate = (n1, operator, n2) =&gt; {
  let result = ''
  
  if (operator === 'add') {
    result = parseFloat(n1) + parseFloat(n2)
  } else if (operator === 'subtract') {
    result = parseFloat(n1) - parseFloat(n2)
  } else if (operator === 'multiply') {
    result = parseFloat(n1) * parseFloat(n2)
  } else if (operator === 'divide') {
    result = parseFloat(n1) / parseFloat(n2)
  }
  
  return result
}</code></pre><p>Isso é tudo para o <em>caminho ideal</em>!</p><p>Você pode pegar o código fonte para o <em>caminho ideal</em> através <a href="http://zellwk.com/blog/calculator-part-1">deste link</a> (texto em inglês - role até o final e digite seu nome e endereço de e-mail, que o código fonte será enviado diretamente para o seu e-mail).</p><h3 id="casos-mais-extremos"><strong>Casos mais extremos</strong></h3><p>O <em>caminho ideal </em>não é o suficiente. Para construir uma calculadora robusta, é necessário tornar a sua calculadora resistente a padrões de entrada estranhos. Para fazer isso, você deve imaginar um arruaceiro que tenta quebrar sua calculadora, batendo as teclas na ordem errada. Vamos chamar este arruaceiro de Tim. </p><p>Tim pode clicar nessas teclas em qualquer ordem: </p><ol><li>Uma tecla numérica (0–9)</li><li>Uma tecla de operador (+, -, ×, ÷)</li><li>Um número decimal</li><li>A tecla de sinal de igual (=)</li><li>A tecla para limpar (AC)</li></ol><h3 id="o-que-acontece-se-o-tim-clicar-na-tecla-decimal"><strong>O que acontece se o Tim clicar na tecla decimal </strong></h3><p>Se o Tim clicar em uma tecla decimal quando o visor já mostrar um ponto decimal, nada deve acontecer.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/Lbvc-ZcYHO2iWjXIjdYiOVJcmPTmtwkknBw5" class="kg-image" alt="Lbvc-ZcYHO2iWjXIjdYiOVJcmPTmtwkknBw5" width="800" height="709" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/Orj4wS6vgnPAMYFq1xI3DEYXBMS4PWLlSw8a" class="kg-image" alt="Orj4wS6vgnPAMYFq1xI3DEYXBMS4PWLlSw8a" width="800" height="709" loading="lazy"></figure><p>Aqui podemos ver que o numero exibido contém um <code>.</code> com o método &nbsp;<code>includes</code>.</p><p><code>includes</code> verifica strings para uma determinada correspondência. Se uma string não for encontrada, ela retornará <code>true</code>; caso contrário, retornará <code>false</code>.</p><p><strong>Observação</strong>: <code>includes</code> faz distinção entre maiúsculas e minúsculas.</p><pre><code class="language-js">// Exemplo do funcionamento de includes.
const string = 'The hamburgers taste pretty good!'
const hasExclamation = string.includes('!')
console.log(hasExclamation) // true</code></pre><p>Para verificar se a string já possui um ponto, fazemos assim:</p><pre><code class="language-js">// Não fazer nada se a string já tiver um ponto
if (!displayedNum.includes('.')) {
  display.textContent = displayedNum + '.'
}</code></pre><p>Em seguida, se Tim pressionar a tecla decimal depois de pressionar uma tecla de operador, o visor deverá mostrar <code>0.</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/fLLhOqkyFZqsOZIxgMPAkpezrUisGpDKFEsw.gif" class="kg-image" alt="fLLhOqkyFZqsOZIxgMPAkpezrUisGpDKFEsw" width="800" height="709" loading="lazy"></figure><p>Agora precisamos saber se a tecla anterior é um operador. Podemos dizer verificando o atributo personalizado, <code>data-previous-key-type</code>, que definimos na lição anterior.</p><p><code>data-previous-key-type</code> ainda não está completo. Para identificar corretamente se <code>previousKeyType</code> é um operador, precisamos atualizar <code>previousKeyType</code> para cada tecla clicada.</p><pre><code class="language-js">if (!action) {
  // ...
  calculator.dataset.previousKey = 'number'
}

if (action === 'decimal') {
  // ...
  calculator.dataset.previousKey = 'decimal'
}

if (action === 'clear') {
  // ...
  calculator.dataset.previousKeyType = 'clear'
}

if (action === 'calculate') {
 // ...
  calculator.dataset.previousKeyType = 'calculate'
}</code></pre><p>Assim que tivermos o <code>previousKeyType</code> correto, podemos usá-lo para verificar se a tecla anterior é um operador.</p><pre><code class="language-js">if (action === 'decimal') {
  if (!displayedNum.includes('.')) {
    display.textContent = displayedNum + '.'
  } else if (previousKeyType === 'operator') {
    display.textContent = '0.'
  }
  
calculator.dataset.previousKeyType = 'decimal'
}</code></pre><h3 id="o-que-acontece-se-tim-apertar-uma-tecla-de-operador"><strong>O que acontece se Tim apertar uma tecla de operador</strong></h3><p>Se Tim apertar uma tecla de operador primeiro, a tecla deve acender (já abordamos esse caso extremo, mas como? Veja se você consegue identificar o que fizemos).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/q3D72rgBjtPOPUltYm1MMIN06dvxGOKyJyUs.gif" class="kg-image" alt="q3D72rgBjtPOPUltYm1MMIN06dvxGOKyJyUs" width="800" height="709" loading="lazy"></figure><p>Em segundo lugar, nada deve acontecer se Tim pressionar a mesma tecla de operador várias vezes (já cobrimos este caso extremo também).</p><p><strong>Observação<strong>:</strong></strong> se você quiser fornecer um UX melhor, você pode mostrar o operador sendo clicado repetidamente com algumas alterações de CSS. Nós não fizemos isso aqui, mas veja se você consegue programar isso sozinho como um desafio extra de codificação.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/IXW7zY77RWE7tNQ6HZMYma73hsxW44EjWg0n.gif" class="kg-image" alt="IXW7zY77RWE7tNQ6HZMYma73hsxW44EjWg0n" width="800" height="709" loading="lazy"></figure><p>Terceiro, se Tim pressionar outra tecla de operador depois de pressionar a primeira tecla de operador, a primeira tecla de operador deve ser liberada. Em seguida, a segunda tecla do operador deve ser pressionada (também cobrimos esse caso extremo - mas como?).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/Rez20RY9AcS6ORFWIIumk69YWzwTyv8qseM7.gif" class="kg-image" alt="Rez20RY9AcS6ORFWIIumk69YWzwTyv8qseM7" width="800" height="709" loading="lazy"></figure><p>Quarto, se Tim acertar um número, um operador, um número e outro operador, nessa ordem, o display deve ser atualizado para um valor calculado.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/MAMWFTkNu6Ho8tlMGyJlTfjCbeYq8rO0bQyR.gif" class="kg-image" alt="MAMWFTkNu6Ho8tlMGyJlTfjCbeYq8rO0bQyR" width="800" height="709" loading="lazy"></figure><p>Isso significa que precisamos usar a função <code>calculate</code> quando <code>firstValue</code>, <code>operator</code> e <code>secondValue</code> existirem.</p><pre><code class="language-js">if (
  action === 'add' ||
  action === 'subtract' ||
  action === 'multiply' ||
  action === 'divide'
) {
  const firstValue = calculator.dataset.firstValue
  const operator = calculator.dataset.operator
  const secondValue = displayedNum
  
// Obs: basta verificar firstValue e o operador, pois o secondValue existe sempre
  if (firstValue &amp;&amp; operator) {
    display.textContent = calculate(firstValue, operator, secondValue)
  }
  
key.classList.add('is-depressed')
  calculator.dataset.previousKeyType = 'operator'
  calculator.dataset.firstValue = displayedNum
  calculator.dataset.operator = action
}</code></pre><p>Embora possamos calcular um valor quando a tecla do operador é clicada pela segunda vez, também introduzimos um bug neste ponto - cliques adicionais na tecla do operador calculam um valor quando não deveriam.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/8ktjtHeYaRTEn-lPbOM3fhEg3qrvDl5WfOVY.gif" class="kg-image" alt="8ktjtHeYaRTEn-lPbOM3fhEg3qrvDl5WfOVY" width="800" height="711" loading="lazy"></figure><p>Para evitar que a calculadora execute um cálculo em cliques subsequentes na tela do operador, precisamos verificar se o <code>previousKeyType</code> é um operador. Se for, não realizamos o cálculo. </p><pre><code class="language-js">if (
  firstValue &amp;&amp;
  operator &amp;&amp;
  previousKeyType !== 'operator'
) {
  display.textContent = calculate(firstValue, operator, secondValue)
}</code></pre><p>Quinto, após a tecla do operador calcular um número, se Tim pressionar um número, seguido por um outro operador, o operador deve continuar com o cálculo, dessa maneira: <code>8 - 1 = 7</code>, <code>7 - 2 = 5</code>, <code>5 - 3 = 2</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/RSsXyuKJe0biqkH-WPDdrGLhFBWmyZ2R1J2Y.gif" class="kg-image" alt="RSsXyuKJe0biqkH-WPDdrGLhFBWmyZ2R1J2Y" width="800" height="711" loading="lazy"></figure><p>No momento, nossa calculadora não pode fazer cálculos consecutivos. O segundo valor calculado está errado. Isso é o que temos: <code>99 - 1 = 98</code>, <code>98 - 1 = 0</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/0r9I8Gu7J9pMbfzUG4hL6tU7RCP-cDhsaGp1.gif" class="kg-image" alt="0r9I8Gu7J9pMbfzUG4hL6tU7RCP-cDhsaGp1" width="800" height="740" loading="lazy"></figure><p>O segundo valor é calculado incorretamente, porque colocamos valores errados na função <code>calculate</code>. Vamos ver algumas imagens para entender o que nosso código faz.</p><h3 id="entendendo-nossa-fun-o-de-c-lculo"><strong>Entendendo nossa função de cálculo</strong></h3><p>Primeiro, digamos que um usuário clique em um número, 99. Nesse momento, nada é registrado na calculadora.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/0hH4Cz5kOEaDOcTQ2PMPmkDl26a8JHSXNrJ7.png" class="kg-image" alt="0hH4Cz5kOEaDOcTQ2PMPmkDl26a8JHSXNrJ7" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/0hH4Cz5kOEaDOcTQ2PMPmkDl26a8JHSXNrJ7.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/0hH4Cz5kOEaDOcTQ2PMPmkDl26a8JHSXNrJ7.png 800w" sizes="(min-width: 720px) 720px" width="800" height="261" loading="lazy"></figure><p>Segundo, digamos que o usuário clique no operador de subtração. Depois que o usuário clica no operador de subtração, definimos <code>firstValue</code> como 99. Também definimos o <code>operator</code> para subtrair.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/0K-KPTzdCBgfVvVaDNcVDYSjXfUO8p5LRs2v.png" class="kg-image" alt="0K-KPTzdCBgfVvVaDNcVDYSjXfUO8p5LRs2v" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/0K-KPTzdCBgfVvVaDNcVDYSjXfUO8p5LRs2v.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/0K-KPTzdCBgfVvVaDNcVDYSjXfUO8p5LRs2v.png 800w" sizes="(min-width: 720px) 720px" width="800" height="260" loading="lazy"></figure><p>Terceiro, digamos que o usuário em um segundo valor - desta vez será 1. Neste momento, o número exibido é atualizado para 1, mas nosso <code>firstValue</code>, <code>operator</code> e <code>secondValue</code> permanecem inalterados.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/0MacG-A5Tl7rZeB6NLeNvghVyBpmSqaZQkn9.png" class="kg-image" alt="0MacG-A5Tl7rZeB6NLeNvghVyBpmSqaZQkn9" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/0MacG-A5Tl7rZeB6NLeNvghVyBpmSqaZQkn9.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/0MacG-A5Tl7rZeB6NLeNvghVyBpmSqaZQkn9.png 800w" sizes="(min-width: 720px) 720px" width="800" height="259" loading="lazy"></figure><p>Quarto, o usuário clica em subtrair novamente. Logo após clicar em subtrair, antes de calcularmos o resultado, definimos <code>secondValue</code> como o número exibido.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/RgDMKK92og4djxxmaYO1HUYiVoetKDK9x0j7.png" class="kg-image" alt="RgDMKK92og4djxxmaYO1HUYiVoetKDK9x0j7" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/RgDMKK92og4djxxmaYO1HUYiVoetKDK9x0j7.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/RgDMKK92og4djxxmaYO1HUYiVoetKDK9x0j7.png 800w" sizes="(min-width: 720px) 720px" width="800" height="263" loading="lazy"></figure><p>Quinto, realizarmos o cálculo com <code>firstValue</code> 99, <code>operator</code> subtrair e <code>secondValue</code> 1. O resultado é 98.</p><p>Assim que o resultado é calculado, definimos a exibição para o resultado. Em seguida, configuramos o operado <code>operator</code> para subtrair e <code>firstValue</code> para o número exibido anteriormente.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/X3VFJ5ar--k84pP3pM5VDVODvYlX4fCwHcnS.png" class="kg-image" alt="X3VFJ5ar--k84pP3pM5VDVODvYlX4fCwHcnS" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/X3VFJ5ar--k84pP3pM5VDVODvYlX4fCwHcnS.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/X3VFJ5ar--k84pP3pM5VDVODvYlX4fCwHcnS.png 800w" sizes="(min-width: 720px) 720px" width="800" height="268" loading="lazy"></figure><p>Bem, isso está muito errado! Se quisermos continuar com o cálculo, precisamos atualizar <code>firstValue</code> com o valor calculado.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/gp-lkqhUOjoo46fIwx-7oLtbV7CP7jZwzc9y.png" class="kg-image" alt="gp-lkqhUOjoo46fIwx-7oLtbV7CP7jZwzc9y" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/gp-lkqhUOjoo46fIwx-7oLtbV7CP7jZwzc9y.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/gp-lkqhUOjoo46fIwx-7oLtbV7CP7jZwzc9y.png 800w" sizes="(min-width: 720px) 720px" width="800" height="260" loading="lazy"></figure><pre><code class="language-js">const firstValue = calculator.dataset.firstValue
const operator = calculator.dataset.operator
const secondValue = displayedNum

if (
  firstValue &amp;&amp;
  operator &amp;&amp;
  previousKeyType !== 'operator'
) {
  const calcValue = calculate(firstValue, operator, secondValue)
  display.textContent = calcValue
  
// Atualizar o valor calculado como firstValue
  calculator.dataset.firstValue = calcValue
} else {
  // Se não houver cálculo, definir displayedNum como o firstValue
  calculator.dataset.firstValue = displayedNum
}

key.classList.add('is-depressed')
calculator.dataset.previousKeyType = 'operator'
calculator.dataset.operator = action</code></pre><p>Com isso corrigido, os cálculos consecutivos feitos pelas teclas do operador devem agora estar corretos.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/tKZ-VlIHo7dRNHDR2BBxZChE1cgqIuMU0Uh-.gif" class="kg-image" alt="tKZ-VlIHo7dRNHDR2BBxZChE1cgqIuMU0Uh-" width="800" height="740" loading="lazy"></figure><h3 id="o-que-acontece-se-tim-apertar-a-tecla-de-sinal-de-igual">O que acontece se Tim apertar a tecla de sinal de igual<strong><strong>?</strong></strong></h3><p>Primeiro, nada deve acontecer se Tim apertar a tecla de sinal de igual antes de qualquer tecla de operador.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/FBvnFZadNPXTllID0R7JfAkrsDb5SLcWTUhV.gif" class="kg-image" alt="FBvnFZadNPXTllID0R7JfAkrsDb5SLcWTUhV" width="800" height="709" loading="lazy"></figure><p>Sabemos que as teclas do operador ainda não foram clicadas se <code>firstValue</code> não estiver definido como um número. Podemos usar esse conhecimento para evitar que a tecla de sinal de igual seja calculada.</p><pre><code class="language-js">if (action === 'calculate') {
  const firstValue = calculator.dataset.firstValue
  const operator = calculator.dataset.operator
  const secondValue = displayedNum
  
if (firstValue) {
    display.textContent = calculate(firstValue, operator, secondValue)
  }
  
calculator.dataset.previousKeyType = 'calculate'
}</code></pre><p>Segundo, se Tim acertar um número, seguido por um operador, seguido por um igual, a calculadora deve calcular o resultado de tal forma que:</p><ol><li><code>2 + =</code> —&gt; <code>2 + 2 = 4</code></li><li><code>2 - =</code> —&gt; <code>2 - 2 = 0</code></li><li><code>2 × =</code> —&gt; <code>2 × 2 = 4</code></li><li><code>2 ÷ =</code> —&gt; <code>2 ÷ 2 = 1</code></li></ol><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/MUgIi0ck8OJRV18hfJ-kdn8k7Ydyy5mDvV6z.gif" class="kg-image" alt="MUgIi0ck8OJRV18hfJ-kdn8k7Ydyy5mDvV6z" width="800" height="711" loading="lazy"></figure><p>Já levamos essa estranha entrada em consideração. Você consegue entender o porquê? :)</p><p>Terceiro, se Tim pressionar a tecla de sinal de igual após a conclusão de um cálculo, outro cálculo deverá ser realizado novamente. Veja como o cálculo deve ser lido:</p><ol><li>Tim aperta as teclas 5–1</li><li>Tim aperta o sinal de igual. O valor calculado é <code>5 - 1 = 4</code></li><li>Tim aperta o sinal de igual. O valor calculado é <code>4 - 1 = 3</code></li><li>Tim aperta o sinal de igual. O valor calculado é <code>3 - 1 = 2</code></li><li>Tim aperta o sinal de igual. O valor calculado é <code>2 - 1 = 1</code></li><li>Tim aperta o sinal de igual. O valor calculado é <code>1 - 1 = 0</code></li></ol><p>Infelizmente, nossa calculadora se atrapalha nesse cálculo. Veja o que nossa calculadora mostra:</p><ol><li>Tim aperta as teclas 5–1</li><li>Tim aperta o sinal de igual. O valor calculado é <code>4</code></li><li>Tim aperta o sinal de igual. O valor calculado é <code>1</code></li></ol><h3 id="corrigindo-o-c-lculo"><strong>Corrigindo o cálculo</strong></h3><p>Primeiro, suponhamos que o usuário clique no número 5. Neste momento, nada está registrado na calculadora ainda.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/2vf5VGXNZ0vjGkyaY0y22PRTqqHDwgEKvCC3.png" class="kg-image" alt="2vf5VGXNZ0vjGkyaY0y22PRTqqHDwgEKvCC3" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/2vf5VGXNZ0vjGkyaY0y22PRTqqHDwgEKvCC3.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/2vf5VGXNZ0vjGkyaY0y22PRTqqHDwgEKvCC3.png 800w" sizes="(min-width: 720px) 720px" width="800" height="263" loading="lazy"></figure><p>Segundo, suponhamos que o usuário clique no operador de subtração. Depois que ele clicar no operador de subtração, definimos o <code>firstValue</code> para 5. Também definimos o <code>operator</code> para subtrair.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/Fc-QupYbv3HInXqv1vHFCc1avhDe3iyEErhs.png" class="kg-image" alt="Fc-QupYbv3HInXqv1vHFCc1avhDe3iyEErhs" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/Fc-QupYbv3HInXqv1vHFCc1avhDe3iyEErhs.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/Fc-QupYbv3HInXqv1vHFCc1avhDe3iyEErhs.png 800w" sizes="(min-width: 720px) 720px" width="800" height="273" loading="lazy"></figure><p>Terceiro, o usuário clica em um segundo valor. Digamos que seja 1. Nesse momento, o número exibido é atualizado para 1, mas nosso <code>firstValue</code>, <code>operator</code> e <code>secondValue</code> permanecem inalterados.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/lW3CtoXJ1gxpUS5SZM3zh3zmqSB-ksM6E0vr.png" class="kg-image" alt="lW3CtoXJ1gxpUS5SZM3zh3zmqSB-ksM6E0vr" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/lW3CtoXJ1gxpUS5SZM3zh3zmqSB-ksM6E0vr.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/lW3CtoXJ1gxpUS5SZM3zh3zmqSB-ksM6E0vr.png 800w" sizes="(min-width: 720px) 720px" width="800" height="266" loading="lazy"></figure><p>Quarto, o usuário clica na tecla do sinal de igual. Logo após clicar no sinal de igual, mas antes do cálculo, definimos <code>secondValue</code> como <code>displayedNum</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/yeQCYcu0ecbNbJlHa9aqEZopHj-FyTqXuRmw.png" class="kg-image" alt="yeQCYcu0ecbNbJlHa9aqEZopHj-FyTqXuRmw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/yeQCYcu0ecbNbJlHa9aqEZopHj-FyTqXuRmw.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/yeQCYcu0ecbNbJlHa9aqEZopHj-FyTqXuRmw.png 800w" sizes="(min-width: 720px) 720px" width="800" height="273" loading="lazy"></figure><p>Quinto, a calculadora calcula o resultado de <code>5 - 1</code> e dá <code>4</code>. O resultado é atualizado para o visor. <code>firstValue</code> e <code>operator</code> são transportados para o próximo cálculo, pois não o atualizaremos.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/YOsfq7AWCs0YbABkiebax-oaQVGc5tWsNyXJ.png" class="kg-image" alt="YOsfq7AWCs0YbABkiebax-oaQVGc5tWsNyXJ" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/YOsfq7AWCs0YbABkiebax-oaQVGc5tWsNyXJ.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/YOsfq7AWCs0YbABkiebax-oaQVGc5tWsNyXJ.png 800w" sizes="(min-width: 720px) 720px" width="800" height="279" loading="lazy"></figure><p>Sexto, quando o usuário clicar em igual novamente, definimos <code>secondValue</code> como <code>displayedNum</code> antes do cálculo.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/BF7tBEUHJN4gnIwQqUTq9ctHIUIVcYM026Ro.png" class="kg-image" alt="BF7tBEUHJN4gnIwQqUTq9ctHIUIVcYM026Ro" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/BF7tBEUHJN4gnIwQqUTq9ctHIUIVcYM026Ro.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/BF7tBEUHJN4gnIwQqUTq9ctHIUIVcYM026Ro.png 800w" sizes="(min-width: 720px) 720px" width="800" height="271" loading="lazy"></figure><p>Você pode dizer o que está errado aqui. </p><p>Ao invés de <code>secondValue</code>, queremos definir <code>firstValue</code> como o número exibido.</p><pre><code class="language-js">if (action === 'calculate') {
  let firstValue = calculator.dataset.firstValue
  const operator = calculator.dataset.operator
  const secondValue = displayedNum
  
if (firstValue) {
    if (previousKeyType === 'calculate') {
      firstValue = displayedNum
    }
    
display.textContent = calculate(firstValue, operator, secondValue)
  }
  
calculator.dataset.previousKeyType = 'calculate'
}</code></pre><p>Também queremos levar o <code>secondValue</code> anterior para o novo cálculo. Para que <code>secondValue</code> persista no próximo cálculo, precisamos armazená-lo em outro atributo personalizado. Chamaremos esse atributo personalizado de <code>modValue</code> (significa valor do modificador).</p><pre><code class="language-js">if (action === 'calculate') {
  let firstValue = calculator.dataset.firstValue
  const operator = calculator.dataset.operator
  const secondValue = displayedNum
  
if (firstValue) {
    if (previousKeyType === 'calculate') {
      firstValue = displayedNum
    }
    
display.textContent = calculate(firstValue, operator, secondValue)
  }
  
// Definir o atributo modValue
  calculator.dataset.modValue = secondValue
  calculator.dataset.previousKeyType = 'calculate'
}</code></pre><p>Se o <code>previousKeyType</code> é <code>calculate</code>, sabemos que podemos usar <code>calculator.dataset.modValue</code> como <code>secondValue</code>. Uma vez que sabemos disso, podemos fazer o cálculo.</p><pre><code class="language-js">if (firstValue) {
  if (previousKeyType === 'calculate') {
    firstValue = displayedNum
    secondValue = calculator.dataset.modValue
  }
  
display.textContent = calculate(firstValue, operator, secondValue)
}</code></pre><p>Com isso, temos o cálculo correto quando a tecla do sinal de igual é clicada consecutivamente.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/sjYX-ImohfhbFFbw1-FqmKagBvfFQKm0PzAu.gif" class="kg-image" alt="sjYX-ImohfhbFFbw1-FqmKagBvfFQKm0PzAu" width="800" height="711" loading="lazy"></figure><h3 id="voltando-para-a-tecla-do-sinal-de-igual"><strong>Voltando para a tecla do sinal de igual</strong></h3><p>Quarto, se o Tim clicar em uma tecla decimal ou uma tecla numérica após a tecla da calculadora, o visor deve ser substituído por <code>0.</code> ou pelo novo número, respectivamente.</p><p>Ao invés de apenas verificar se o <code>previousKeyType</code> é <code>operator</code>, também precisamos verificar se é <code>calculate</code>.</p><pre><code class="language-js">if (!action) {
  if (
    displayedNum === '0' ||
    previousKeyType === 'operator' ||
    previousKeyType === 'calculate'
  ) {
    display.textContent = keyContent
  } else {
    display.textContent = displayedNum + keyContent
  }
  calculator.dataset.previousKeyType = 'number'
}

if (action === 'decimal') {
  if (!displayedNum.includes('.')) {
    display.textContent = displayedNum + '.'
  } else if (
    previousKeyType === 'operator' ||
    previousKeyType === 'calculate'
  ) {
    display.textContent = '0.'
  }
  
calculator.dataset.previousKeyType = 'decimal'
}</code></pre><p>Quinto, se Tim apertar uma tecla de operador logo após a tecla de sinal de igual, a calculadora <strong>não </strong>deve calcular.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/uuifuJ41Oo86NXMsPj44RSQf7ExULROc2GaI.gif" class="kg-image" alt="uuifuJ41Oo86NXMsPj44RSQf7ExULROc2GaI" width="800" height="740" loading="lazy"></figure><p>Para fazer isso, vamos verificar se o &nbsp;<code>previousKeyType</code> é <code>calculate</code> antes de realizar cálculos com as teclas do operador.</p><pre><code class="language-js">if (
  action === 'add' ||
  action === 'subtract' ||
  action === 'multiply' ||
  action === 'divide'
) {
  // ...
  
if (
    firstValue &amp;&amp;
    operator &amp;&amp;
    previousKeyType !== 'operator' &amp;&amp;
    previousKeyType !== 'calculate'
  ) {
    const calcValue = calculate(firstValue, operator, secondValue)
    display.textContent = calcValue
    calculator.dataset.firstValue = calcValue
  } else {
    calculator.dataset.firstValue = displayedNum
  }
  
// ...
}</code></pre><p>A chave para limpar (AC) tem dois usos:</p><ol><li>All Clear (denotado por <code>AC</code>) limpa tudo e restabelece a calculadora para seu estado inicial.</li><li>Clear entry (denotado por <code>CE</code>) limpa a entrada atual. Mantém os números anteriores na memória.</li></ol><p>Quando a calculadora estiver em seu estado padrão, deve ser mostrado <code>AC</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/22fj2VLJJ1SPexybqdWIqPRkj9JkrlI3AAYl.png" class="kg-image" alt="22fj2VLJJ1SPexybqdWIqPRkj9JkrlI3AAYl" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/04/22fj2VLJJ1SPexybqdWIqPRkj9JkrlI3AAYl.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/04/22fj2VLJJ1SPexybqdWIqPRkj9JkrlI3AAYl.png 800w" sizes="(min-width: 720px) 720px" width="800" height="738" loading="lazy"></figure><p>Primeiro, se o Tim clicar uma tecla (qualquer uma, exceto a de limpar), <code>AC</code> deve ser mudado para <code>CE</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/Hs9tjp3JQIYOaAgh8KDnxj5QShScU0nMkDa7.gif" class="kg-image" alt="Hs9tjp3JQIYOaAgh8KDnxj5QShScU0nMkDa7" width="800" height="709" loading="lazy"></figure><p>Fazemos isso verificando se <code>data-action</code> está <code>clear</code>. Caso não esteja <code>clear</code>, procuramos o botão clear e alteraremos seu <code>textContent</code>.</p><pre><code class="language-js">if (action !== 'clear') {
  const clearButton = calculator.querySelector('[data-action=clear]')
  clearButton.textContent = 'CE'
}</code></pre><p>Em segundo lugar, se Tim apertar <code>CE</code>, o visor deve mostrar 0. Ao mesmo tempo, <code>CE</code> deverá ser revertido para <code>AC</code> para que Tim possa repor a calculadora em seu estado inicial.**</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/04/Dv6SFw5LY8wB0WqTFQBe46-QoraBiq8TvpdY.gif" class="kg-image" alt="Dv6SFw5LY8wB0WqTFQBe46-QoraBiq8TvpdY" width="800" height="711" loading="lazy"></figure><pre><code class="language-js">if (action === 'clear') {
  display.textContent = 0
  key.textContent = 'AC'
  calculator.dataset.previousKeyType = 'clear'
}</code></pre><p>Terceiro, se Tim pressionar <code>AC</code>, a calculadora deverá ser redefinida para seu estado inicial.</p><p>Para redefinir a calculadora para seu estado inicial, precisamos limpar todos os atributos personalizados que definimos.</p><pre><code class="language-js">if (action === 'clear') {
  if (key.textContent === 'AC') {
    calculator.dataset.firstValue = ''
    calculator.dataset.modValue = ''
    calculator.dataset.operator = ''
    calculator.dataset.previousKeyType = ''
  } else {
    key.textContent = 'AC'
  }
  
display.textContent = 0
  calculator.dataset.previousKeyType = 'clear'
}</code></pre><p>Então é isso — pelo menos para os casos mais extremos!</p><p>Você pode pegar o código fonte para a parte de casos extremos <a href="http://zellwk.com/blog/calculator-part-2">neste link</a> (texto em inglês - role para baixo e digite seu endereço de e-mail, o código fonte será enviado diretamente para o seu e-mail).</p><p>Até agora, o código que criamos juntos é bastante confuso. Você provavelmente se perderá se tentar ler o código por conta própria. Vamos refatorá-lo para torná-lo mais limpo.</p><h3 id="refatorando-o-c-digo"><strong>Refatorando o código</strong></h3><p>Quando você refatorar, muitas vezes você começará com as melhorias mais óbvias. Neste caso, vamos começar com <code>calculate</code>.</p><p>Antes de continuar, certifique-se de conhecer essas práticas/recursos de JavaScript. Vamos usá-los no refatoramento.</p><ol><li><a href="http://blog.timoxley.com/post/47041269194/avoid-else-return-early" rel="noopener">Returns antecipados</a> (texto explicativo em inglês)</li><li><a href="https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">Operadores ternários</a></li><li><a href="https://medium.com/@jamesjefferyuk/javascript-what-are-pure-functions-4d4d5392d49c" rel="noopener">Funções puras</a> (texto explicativo em inglês)</li><li><a href="https://zellwk.com/blog/es6#destructuring" rel="noopener">Desestruturação da ES6</a> (texto explicativo em inglês)</li></ol><p>Com isso, vamos começar!</p><h3 id="refatorando-a-fun-o-de-c-lculo"><strong>Refatorando a função de cálculo</strong></h3><p>Eis o que temos até agora.</p><pre><code class="language-js">const calculate = (n1, operator, n2) =&gt; {
  let result = ''
  if (operator === 'add') {
    result = parseFloat(n1) + parseFloat(n2)
  } else if (operator === 'subtract') {
    result = parseFloat(n1) - parseFloat(n2)
  } else if (operator === 'multiply') {
    result = parseFloat(n1) * parseFloat(n2)
  } else if (operator === 'divide') {
    result = parseFloat(n1) / parseFloat(n2)
  }
  
  return result
}</code></pre><p>Você aprendeu que devemos reduzir o máximo possível as reatribuições. Aqui, podemos remover as tarefas se devolvermos o resultado do cálculo dentro das declarações de <code>if</code> e <code>else if</code>:</p><pre><code class="language-js">const calculate = (n1, operator, n2) =&gt; {
  if (operator === 'add') {
    return firstNum + parseFloat(n2)
  } else if (operator === 'subtract') {
    return parseFloat(n1) - parseFloat(n2)
  } else if (operator === 'multiply') {
    return parseFloat(n1) * parseFloat(n2)
  } else if (operator === 'divide') {
    return parseFloat(n1) / parseFloat(n2)
  }
}</code></pre><p>Como retornamos todos os valores, podemos utilizar <strong>early r<strong>eturns</strong> </strong>(ou <em>retornos antecipados</em>, em tradução literal). Se o fizermos, não há necessidade das condições de <code>else if</code>.</p><pre><code class="language-js">const calculate = (n1, operator, n2) =&gt; {
  if (operator === 'add') {
    return firstNum + parseFloat(n2)
  }
  
  if (operator === 'subtract') {
    return parseFloat(n1) - parseFloat(n2)
  }
  
  if (operator === 'multiply') {
    return parseFloat(n1) * parseFloat(n2)
  }
  
  if (operator === 'divide') {
    return parseFloat(n1) / parseFloat(n2)
  }
}</code></pre><p>E como temos uma declaração com a condição <code>if</code>, podemos remover os colchetes (embora alguns desenvolvedores afirmem que precisamos deles). Veja como ficaria o código:</p><pre><code class="language-js">const calculate = (n1, operator, n2) =&gt; {
  if (operator === 'add') return parseFloat(n1) + parseFloat(n2)
  if (operator === 'subtract') return parseFloat(n1) - parseFloat(n2)
  if (operator === 'multiply') return parseFloat(n1) * parseFloat(n2)
  if (operator === 'divide') return parseFloat(n1) / parseFloat(n2)
}</code></pre><p>Chamamos <code>parseFloat</code> oito vezes na função. Podemos simplificá-lo criando duas variáveis para conter valores decimais:</p><pre><code class="language-js">const calculate = (n1, operator, n2) =&gt; {
  const firstNum = parseFloat(n1)
  const secondNum = parseFloat(n2)
  if (operator === 'add') return firstNum + secondNum
  if (operator === 'subtract') return firstNum - secondNum
  if (operator === 'multiply') return firstNum * secondNum
  if (operator === 'divide') return firstNum / secondNum
}</code></pre><p>Terminamos <code>calculate</code>. Não acha que está mais fácil de ler em comparação com o código que tínhamos antes?</p><h3 id="refatorando-o-event-listener-ouvinte-de-eventos-">Refatorando o<strong><strong> event listener</strong> <em>(ouvinte de eventos)</em></strong></h3><p>O código que criamos para o ouvinte de eventos<em> (event listener)</em> é enorme. Veja o que temos no momento:</p><pre><code class="language-js">keys.addEventListener('click', e =&gt; {
  if (e.target.matches('button')) {
  
    if (!action) { /* ... */ }
    
    if (action === 'add' ||
      action === 'subtract' ||
      action === 'multiply' ||
      action === 'divide') {
      /* ... */
    }
    
    if (action === 'clear') { /* ... */ }
    if (action !== 'clear') { /* ... */ }
    if (action === 'calculate') { /* ... */ }
  }
})</code></pre><p>Como você começaria a refatorar esse pedaço de código? Se você não conhece nenhuma prática recomendada de programação, pode ficar tentado a refatorar dividindo cada tipo de ação em uma função menor:</p><pre><code class="language-js">// Não faça isso!
const handleNumberKeys = (/* ... */) =&gt; {/* ... */}
const handleOperatorKeys = (/* ... */) =&gt; {/* ... */}
const handleDecimalKey = (/* ... */) =&gt; {/* ... */}
const handleClearKey = (/* ... */) =&gt; {/* ... */}
const handleCalculateKey = (/* ... */) =&gt; {/* ... */}</code></pre><p>Não faça isso. Isso não ajuda, porque você está apenas dividindo blocos de código. Quando você faz isso, a função fica mais difícil de ler.</p><p>Uma maneira melhor é dividir o código em funções puras e impuras. Se fizer isso, você obterá um código parecido com este:</p><pre><code class="language-js">keys.addEventListener('click', e =&gt; {
  // Função pura
  const resultString = createResultString(/* ... */)
  
  // Cálculo "impuro"
  display.textContent = resultString
  updateCalculatorState(/* ... */)
})</code></pre><p>Na código acima, <code>createResultString</code> é uma função pura que retorna o que precisa ser exibido na calculadora. <code>updateCalculatorState</code> é uma função impura que altera a aparência visual e os atributos personalizados da calculadora.</p><h3 id="criando-createresultstring"><strong>Criando <strong>createResultString</strong></strong></h3><p>Como mencionado anteriormente, <code>createResultString</code> deve retornar o valor que precisa ser exibido na calculadora.<br>Você pode obter esses valores através de partes do código que diz <code>display.textContent = 'some value</code>.</p><pre><code class="language-js">display.textContent = 'some value'</code></pre><p>Ao invés de <code>display.textContent = 'some value'</code>, queremos retornar cada valor para que possamos usá-lo mais tarde.</p><pre><code class="language-js">// substitua o que temos acima por isso
return 'some value'</code></pre><p>Vamos fazer um passo a passo, começando com as teclas numéricas.</p><h3 id="criando-a-string-de-resultado-para-teclas-num-ricas">Criando a string de resultado para teclas numéricas</h3><p>Este é o código que temos para as teclas numéricas:</p><pre><code class="language-js">if (!action) {
  if (
    displayedNum === '0' ||
    previousKeyType === 'operator' ||
    previousKeyType === 'calculate'
  ) {
    display.textContent = keyContent
  } else {
    display.textContent = displayedNum + keyContent
  }
  calculator.dataset.previousKeyType = 'number'
}</code></pre><p>O primeiro passo é copiar as partes que dizem <code>display.textContent = 'some value'</code> em<code>createResultString</code>. Ao fazer isso, certifique-se de mudar o <code>display.textContent =</code> em <code>return</code>.</p><pre><code class="language-js">const createResultString = () =&gt; {
  if (!action) {
    if (
      displayedNum === '0' ||
      previousKeyType === 'operator' ||
      previousKeyType === 'calculate'
    ) {
      return keyContent
    } else {
      return displayedNum + keyContent
    }
  }
}</code></pre><p>Em seguida, podemos converter a declaração <code>if/else</code> para um operador ternário:</p><pre><code class="language-js">const createResultString = () =&gt; {
  if (action!) {
    return displayedNum === '0' ||
      previousKeyType === 'operator' ||
      previousKeyType === 'calculate'
      ? keyContent
      : displayedNum + keyContent
  }
}</code></pre><p>Quando você refatorar, lembre-se de anotar uma lista de variáveis que você precisa. Voltaremos à lista mais tarde.</p><pre><code class="language-js">const createResultString = () =&gt; {
  // As variáveis necessárias são:
  // 1. keyContent
  // 2. displayedNum
  // 3. previousKeyType
  // 4. action
  
  if (action!) {
    return displayedNum === '0' ||
      previousKeyType === 'operator' ||
      previousKeyType === 'calculate'
      ? keyContent
      : displayedNum + keyContent
  }
}</code></pre><h3 id="criando-a-string-de-resultado-para-a-tecla-decimal">Criando a string de resultado para a tecla decimal</h3><p>Aqui está o código que temos para a tecla decimal:</p><pre><code class="language-js">if (action === 'decimal') {
  if (!displayedNum.includes('.')) {
    display.textContent = displayedNum + '.'
  } else if (
    previousKeyType === 'operator' ||
    previousKeyType === 'calculate'
  ) {
    display.textContent = '0.'
  }
  
  calculator.dataset.previousKeyType = 'decimal'
}</code></pre><p>Assim como antes, queremos mover qualquer coisa que mude o <code>display.textContent</code> para <code>createResultString</code>.</p><pre><code class="language-js">const createResultString = () =&gt; {
  // ...
  
  if (action === 'decimal') {
    if (!displayedNum.includes('.')) {
      return = displayedNum + '.'
    } else if (previousKeyType === 'operator' || previousKeyType === 'calculate') {
      return = '0.'
    }
  }
}</code></pre><p>Como queremos retornar todos os valores, podemos converter a declaração <code>else if</code> para <strong>early returns</strong> <em>(retornos antecipados, em tradução livre)</em>.</p><pre><code class="language-js">const createResultString = () =&gt; {
  // ...
  
  if (action === 'decimal') {
    if (!displayedNum.includes('.')) return displayedNum + '.'
    if (previousKeyType === 'operator' || previousKeyType === 'calculate') return '0.'
  }
}</code></pre><p>Um erro comum aqui é esquecer de retornar o número exibido no momento quando nenhuma condição é correspondida. Precisamos disso porque substituiremos <code>display.textContent</code> pelo valor retornado de <code>createResultString</code>. Se falharmos, <code>createResultString</code> retornará <code>undefined</code>, o que não é o que desejamos.</p><pre><code class="language-js">const createResultString = () =&gt; {
  // ...
  
  if (action === 'decimal') {
    if (!displayedNum.includes('.')) return displayedNum + '.'
    if (previousKeyType === 'operator' || previousKeyType === 'calculate') return '0.'
    return displayedNum
  }
}</code></pre><p>Como sempre, observe as variáveis que são necessárias. Neste momento, as variáveis necessárias permanecem as mesmas de antes:</p><pre><code class="language-js">const createResultString = () =&gt; {
  // As variáveis necessárias são:
  // 1. keyContent
  // 2. displayedNum
  // 3. previousKeyType
  // 4. action
}</code></pre><h3 id="criando-a-string-de-resultados-para-as-teclas-do-operador">Criando a string de resultados para as teclas do operador</h3><p>Esse é o código que escrevemos para as teclas do operador.</p><pre><code class="language-js">if (
  action === 'add' ||
  action === 'subtract' ||
  action === 'multiply' ||
  action === 'divide'
) {
  const firstValue = calculator.dataset.firstValue
  const operator = calculator.dataset.operator
  const secondValue = displayedNum
  
  if (
    firstValue &amp;&amp;
    operator &amp;&amp;
    previousKeyType !== 'operator' &amp;&amp;
    previousKeyType !== 'calculate'
  ) {
    const calcValue = calculate(firstValue, operator, secondValue)
    display.textContent = calcValue
    calculator.dataset.firstValue = calcValue
  } else {
    calculator.dataset.firstValue = displayedNum
  }
  
  key.classList.add('is-depressed')
  calculator.dataset.previousKeyType = 'operator'
  calculator.dataset.operator = action
}</code></pre><p>Você já sabe o que fazer: queremos mover tudo o que altera <code>display.textContent</code> para<code>createResultString</code>. Isso é o que precisa ser movido:</p><pre><code class="language-js">const createResultString = () =&gt; {
  // ...
  if (
    action === 'add' ||
    action === 'subtract' ||
    action === 'multiply' ||
    action === 'divide'
  ) {
    const firstValue = calculator.dataset.firstValue
    const operator = calculator.dataset.operator
    const secondValue = displayedNum
    
    if (
      firstValue &amp;&amp;
      operator &amp;&amp;
      previousKeyType !== 'operator' &amp;&amp;
      previousKeyType !== 'calculate'
    ) {
      return calculate(firstValue, operator, secondValue)
    }
  }
}</code></pre><p>Lembre-se: a <code>createResultString</code> precisa retornar o valor a ser exibido na calculadora. Se a condição <code>if</code> não corresponder, ainda assim queremos retornar o número exibido.</p><pre><code class="language-js">const createResultString = () =&gt; {
  // ...
  if (
    action === 'add' ||
    action === 'subtract' ||
    action === 'multiply' ||
    action === 'divide'
  ) {
    const firstValue = calculator.dataset.firstValue
    const operator = calculator.dataset.operator
    const secondValue = displayedNum
    
    if (
      firstValue &amp;&amp;
      operator &amp;&amp;
      previousKeyType !== 'operator' &amp;&amp;
      previousKeyType !== 'calculate'
    ) {
      return calculate(firstValue, operator, secondValue)
    } else {
      return displayedNum
    }
  }
}</code></pre><p>Podemos então refatorar a declaração <code>if/else</code> em um operador ternário:</p><pre><code class="language-js">const createResultString = () =&gt; {
  // ...
  if (
    action === 'add' ||
    action === 'subtract' ||
    action === 'multiply' ||
    action === 'divide'
  ) {
    const firstValue = calculator.dataset.firstValue
    const operator = calculator.dataset.operator
    const secondValue = displayedNum
    
    return firstValue &amp;&amp;
      operator &amp;&amp;
      previousKeyType !== 'operator' &amp;&amp;
      previousKeyType !== 'calculate'
      ? calculate(firstValue, operator, secondValue)
      : displayedNum
  }
}</code></pre><p>Se você olhar com atenção, perceberá que não há necessidade de armazenar uma variável <code>secondValue</code>. Podemos usar <code>displayedNum</code> diretamente na função <code>calculate</code>.</p><pre><code class="language-js">const createResultString = () =&gt; {
  // ...
  if (
    action === 'add' ||
    action === 'subtract' ||
    action === 'multiply' ||
    action === 'divide'
  ) {
    const firstValue = calculator.dataset.firstValue
    const operator = calculator.dataset.operator
    
    return firstValue &amp;&amp;
      operator &amp;&amp;
      previousKeyType !== 'operator' &amp;&amp;
      previousKeyType !== 'calculate'
      ? calculate(firstValue, operator, displayedNum)
      : displayedNum
  }
}</code></pre><p>Por fim, tome nota das variáveis e propriedades necessárias. Desta vez, precisamos <code>calculator.dataset.firstValue</code> e <code>calculator.dataset.operator</code>.</p><pre><code class="language-js">const createResultString = () =&gt; {
  // As variáveis e propriedades necessárias são:
  // 1. keyContent
  // 2. displayedNum
  // 3. previousKeyType
  // 4. action
  // 5. calculator.dataset.firstValue
  // 6. calculator.dataset.operator
}</code></pre><h3 id="criando-a-string-de-resultado-para-a-tecla-de-limpar">Criando a string de resultado para a tecla de limpar</h3><p>Escrevemos o código abaixo para controlar a tecla <code>clear</code>.</p><pre><code class="language-js">if (action === 'clear') {
  if (key.textContent === 'AC') {
    calculator.dataset.firstValue = ''
    calculator.dataset.modValue = ''
    calculator.dataset.operator = ''
    calculator.dataset.previousKeyType = ''
  } else {
    key.textContent = 'AC'
  }
  
  display.textContent = 0
  calculator.dataset.previousKeyType = 'clear'
}</code></pre><p>Como acima, queremos mover tudo o que muda o <code>display.textContent</code> para <code>createResultString</code>.</p><pre><code class="language-js">const createResultString = () =&gt; {
  // ...
  if (action === 'clear') return 0
}</code></pre><h3 id="construindo-a-string-de-resultado-para-a-tecla-de-igual">Construindo a string de resultado para a tecla de igual</h3><p>Aqui está o código que temos para a tecla de igual:</p><pre><code class="language-js">if (action === 'calculate') {
  let firstValue = calculator.dataset.firstValue
  const operator = calculator.dataset.operator
  let secondValue = displayedNum
  
  if (firstValue) {
    if (previousKeyType === 'calculate') {
      firstValue = displayedNum
      secondValue = calculator.dataset.modValue
    }
    
    display.textContent = calculate(firstValue, operator, secondValue)
  }
  
  calculator.dataset.modValue = secondValue
  calculator.dataset.previousKeyType = 'calculate'
}</code></pre><p>Como acima, queremos copiar tudo o que muda o <code>display.textContent</code> para <code>createResultString</code>. Abaixo o que precisa ser copiado:</p><pre><code class="language-js">if (action === 'calculate') {
  let firstValue = calculator.dataset.firstValue
  const operator = calculator.dataset.operator
  let secondValue = displayedNum
  
  if (firstValue) {
    if (previousKeyType === 'calculate') {
      firstValue = displayedNum
      secondValue = calculator.dataset.modValue
    }
    display.textContent = calculate(firstValue, operator, secondValue)
  }
}</code></pre><p>Ao copiar o código para <code>createResultString</code>, certifique-se de retornar valores para todos os cenários possíveis:</p><pre><code class="language-js">const createResultString = () =&gt; {
  // ...
  
  if (action === 'calculate') {
    let firstValue = calculator.dataset.firstValue
    const operator = calculator.dataset.operator
    let secondValue = displayedNum
    
    if (firstValue) {
      if (previousKeyType === 'calculate') {
        firstValue = displayedNum
        secondValue = calculator.dataset.modValue
      }
      return calculate(firstValue, operator, secondValue)
    } else {
      return displayedNum
    }
  }
}</code></pre><p>Em seguida, queremos reduzir reatribuições. Podemos fazer isso passando os valores corretos para <code>calculate</code> por meio de um operador ternário.</p><pre><code class="language-js">const createResultString = () =&gt; {
  // ...
  
  if (action === 'calculate') {
    const firstValue = calculator.dataset.firstValue
    const operator = calculator.dataset.operator
    const modValue = calculator.dataset.modValue
    
    if (firstValue) {
      return previousKeyType === 'calculate'
        ? calculate(displayedNum, operator, modValue)
        : calculate(firstValue, operator, displayedNum)
    } else {
      return displayedNum
    }
  }
}</code></pre><p>É possível simplificar ainda mais o código acima com outro operador ternário se você se sentir confortável com ele:</p><pre><code class="language-js">const createResultString = () =&gt; {
  // ...
  
  if (action === 'calculate') {
    const firstValue = calculator.dataset.firstValue
    const operator = calculator.dataset.operator
    const modValue = calculator.dataset.modValue
    
    return firstValue
      ? previousKeyType === 'calculate'
        ? calculate(displayedNum, operator, modValue)
        : calculate(firstValue, operator, displayedNum)
      : displayedNum
  }
}</code></pre><p>Agora, queremos anotar novamente as propriedades e variáveis necessárias:</p><pre><code class="language-js">const createResultString = () =&gt; {
  // As variáveis e propriedades necessárias são:
  // 1. keyContent
  // 2. displayedNum
  // 3. previousKeyType
  // 4. action
  // 5. calculator.dataset.firstValue
  // 6. calculator.dataset.operator
  // 7. calculator.dataset.modValue
}</code></pre><h3 id="passando-as-vari-veis-necess-rias"><strong>Passando as variáveis necessárias</strong></h3><p>Precisamos de sete propriedades/variáveis em <code>createResultString</code>:</p><ol><li><code>keyContent</code></li><li><code>displayedNum</code></li><li><code>previousKeyType</code></li><li><code>action</code></li><li><code>firstValue</code></li><li><code>modValue</code></li><li><code>operator</code></li></ol><p>Podemos obter <code>keyContent</code> e <code>action</code> a partir de <code>key</code>. Também podemos obter <code>firstValue</code>, <code>modValue</code>, <code>operator</code> e <code>previousKeyType</code> a partir de <code>calculator.dataset</code>.</p><p>Isso significa que a função <code>createResultString</code> precisa de três variáveis — <code>key</code>, <code>displayedNum</code> e <code>calculator.dataset</code>. Como <code>calculator.dataset</code> representa o estado da calculadora, vamos usar uma variável chamada <code>state</code>.</p><pre><code class="language-js">const createResultString = (key, displayedNum, state) =&gt; {
  const keyContent = key.textContent
  const action = key.dataset.action
  const firstValue = state.firstValue
  const modValue = state.modValue
  const operator = state.operator
  const previousKeyType = state.previousKeyType
  // ... Refatore conforme seja necessário
}

// Usando createResultString
keys.addEventListener('click', e =&gt; {
  if (e.target.matches('button')) return
  const displayedNum = display.textContent
  const resultString = createResultString(e.target, displayedNum, calculator.dataset)
  
  // ...
})</code></pre><p>Sinta-se à vontade para desestruturar variáveis, se desejar:</p><pre><code class="language-js">const createResultString = (key, displayedNum, state) =&gt; {
  const keyContent = key.textContent
  const { action } = key.dataset
  const {
    firstValue,
    modValue,
    operator,
    previousKeyType
  } = state
  
  // ...
}</code></pre><h3 id="consist-ncia-nas-declara-es-if">Consistência nas declarações if</h3><p>Em <code>createResultString</code>, usamos as seguintes condições para testar o tipo de teclas que foram clicadas:</p><pre><code class="language-js">// Se a tecla for numérica
if (!action) { /* ... */ }

// Se a tecla for decimal
if (action === 'decimal') { /* ... */ }

// Se a tecla for um operador
if (
  action === 'add' ||
  action === 'subtract' ||
  action === 'multiply' ||
  action === 'divide'
) { /* ... */}

// Se a tecla for a de limpar
if (action === 'clear') { /* ... */ }

// Se a tecla for um calcular
if (action === 'calculate') { /* ... */ }</code></pre><p>Eles não são consistentes, por isso são difíceis de ler. Se possível, queremos torná-las consistentes para que possamos escrever algo assim:</p><pre><code class="language-js">if (keyType === 'number') { /* ... */ }
if (keyType === 'decimal') { /* ... */ }
if (keyType === 'operator') { /* ... */}
if (keyType === 'clear') { /* ... */ }
if (keyType === 'calculate') { /* ... */ }</code></pre><p>Para isso, podemos criar uma função chamada <code>getKeyType</code>. Essa função deve retornar o tipo de tecla que foi clicada.</p><pre><code class="language-js">const getKeyType = (key) =&gt; {
  const { action } = key.dataset
  if (!action) return 'number'
  if (
    action === 'add' ||
    action === 'subtract' ||
    action === 'multiply' ||
    action === 'divide'
  ) return 'operator'
  // Para todo o resto, retorne a ação (action)
  return action
}</code></pre><p>Veja como você usaria a função: </p><pre><code class="language-js">const createResultString = (key, displayedNum, state) =&gt; {
  const keyType = getKeyType(key)
  
  if (keyType === 'number') { /* ... */ }
  if (keyType === 'decimal') { /* ... */ }
  if (keyType === 'operator') { /* ... */}
  if (keyType === 'clear') { /* ... */ }
  if (keyType === 'calculate') { /* ... */ }
}</code></pre><p>Terminamos com a função <code>createResultString</code>. Vamos continuar com <code>updateCalculatorState</code>.</p><h3 id="construindo-updatecalculatorstate">Construindo <strong><strong>updateCalculatorState</strong></strong></h3><p><code>updateCalculatorState</code> é uma função que altera a aparência visual e os atributos personalizados da calculadora.</p><p>Assim como <code>createResultString</code>, precisamos verificar qual tecla foi clicada. Nesse caso, vamos reutilizar a função <code>getKeyType</code>.</p><pre><code class="language-js">const updateCalculatorState = (key) =&gt; {
  const keyType = getKeyType(key)
  
  if (keyType === 'number') { /* ... */ }
  if (keyType === 'decimal') { /* ... */ }
  if (keyType === 'operator') { /* ... */}
  if (keyType === 'clear') { /* ... */ }
  if (keyType === 'calculate') { /* ... */ }
}</code></pre><p>Se você observar o código restante, poderá notar que mudamos os dados <code>data-previous-key-type</code> para cada tipo de tecla. Veja abaixo como o código se parece:</p><pre><code class="language-js">const updateCalculatorState = (key, calculator) =&gt; {
  const keyType = getKeyType(key)
  
  if (!action) {
    // ...
    calculator.dataset.previousKeyType = 'number'
  }
  
  if (action === 'decimal') {
    // ...
    calculator.dataset.previousKeyType = 'decimal'
  }
  
  if (
    action === 'add' ||
    action === 'subtract' ||
    action === 'multiply' ||
    action === 'divide'
  ) {
    // ...
    calculator.dataset.previousKeyType = 'operator'
  }
  
  if (action === 'clear') {
    // ...
    calculator.dataset.previousKeyType = 'clear'
  }
  
  if (action === 'calculate') {
    calculator.dataset.previousKeyType = 'calculate'
  }
}</code></pre><p>Isso é redundante porque já conhecemos o tipo de tecla com o <code>getKeyType</code>. Podemos refatorar o código acima para: </p><pre><code class="language-js">const updateCalculatorState = (key, calculator) =&gt; {
  const keyType = getKeyType(key)
  calculator.dataset.previousKeyType = keyType
    
  if (keyType === 'number') { /* ... */ }
  if (keyType === 'decimal') { /* ... */ }
  if (keyType === 'operator') { /* ... */}
  if (keyType === 'clear') { /* ... */ }
  if (keyType === 'calculate') { /* ... */ }
}</code></pre><h3 id="construindo-updatecalculatorstate-para-teclas-de-operador"><strong>Construindo <strong><code>updateCalculatorState</code> </strong>para teclas de operador</strong></h3><p>Visualmente, precisamos garantir que todas as teclas liberem seu estado deprimido. Abaixo, podemos copiar e colar o código que tínhamos antes:</p><pre><code class="language-js">const updateCalculatorState = (key, calculator) =&gt; {
  const keyType = getKeyType(key)
  calculator.dataset.previousKeyType = keyType
  
  Array.from(key.parentNode.children).forEach(k =&gt; k.classList.remove('is-depressed'))
}</code></pre><p>Aqui está o que sobrou do que escrevemos para as teclas de operador, depois de mover as partes relacionadas a <code>display.textContent</code> para <code>createResultString</code>.</p><pre><code class="language-js">if (keyType === 'operator') {
  if (firstValue &amp;&amp;
      operator &amp;&amp;
      previousKeyType !== 'operator' &amp;&amp;
      previousKeyType !== 'calculate'
  ) {
    calculator.dataset.firstValue = calculatedValue
  } else {
    calculator.dataset.firstValue = displayedNum
  }
  
  key.classList.add('is-depressed')
  calculator.dataset.operator = key.dataset.action
}</code></pre><p>Você pode perceber que podemos encurtar o código com um operador ternário:</p><pre><code class="language-js">if (keyType === 'operator') {
  key.classList.add('is-depressed')
  calculator.dataset.operator = key.dataset.action
  calculator.dataset.firstValue = firstValue &amp;&amp;
    operator &amp;&amp;
    previousKeyType !== 'operator' &amp;&amp;
    previousKeyType !== 'calculate'
    ? calculatedValue
    : displayedNum
}</code></pre><p>Como anteriormente, observe as variáveis e propriedades que você precisa. Aqui, nós vamos precisar de <code>calculatedValue</code> e <code>displayedNum</code>.</p><pre><code class="language-js">const updateCalculatorState = (key, calculator) =&gt; {
  // Variáveis e propriedades necessárias
  // 1. key
  // 2. calculator
  // 3. calculatedValue
  // 4. displayedNum
}</code></pre><h3 id="construindo-updatecalculatorstate-para-a-tecla-de-limpar-ac-"><strong>Construindo <strong><code>updateCalculatorState</code> </strong>para a tecla de limpar (AC)</strong></h3><p>Aqui está o código restante para a tecla de limpeza:</p><pre><code class="language-js">if (action === 'clear') {
  if (key.textContent === 'AC') {
    calculator.dataset.firstValue = ''
    calculator.dataset.modValue = ''
    calculator.dataset.operator = ''
    calculator.dataset.previousKeyType = ''
  } else {
    key.textContent = 'AC'
  }
}

if (action !== 'clear') {
  const clearButton = calculator.querySelector('[data-action=clear]')
  clearButton.textContent = 'CE'
}</code></pre><p>Não há muito o que possamos refatorar aqui. Sinta-se à vontade para copiar e colar tudo em <code>updateCalculatorState</code>.</p><h3 id="construindo-updatecalculatorstate-para-a-tecla-de-sinal-de-igual"><strong>Construindo <strong><code>updateCalculatorState</code> </strong>para a tecla de sinal de igual</strong></h3><p>Abaixo o código que escrevemos para a chave de igual: </p><pre><code class="language-js">if (action === 'calculate') {
  let firstValue = calculator.dataset.firstValue
  const operator = calculator.dataset.operator
  let secondValue = displayedNum
  
  if (firstValue) {
    if (previousKeyType === 'calculate') {
      firstValue = displayedNum
      secondValue = calculator.dataset.modValue
    }
    
    display.textContent = calculate(firstValue, operator, secondValue)
  }
  
  calculator.dataset.modValue = secondValue
  calculator.dataset.previousKeyType = 'calculate'
}</code></pre><p>Eis o que nos resta se removermos tudo o que diz respeito a <code>display.textContent</code>.</p><pre><code class="language-js">if (action === 'calculate') {
  let secondValue = displayedNum
  
  if (firstValue) {
    if (previousKeyType === 'calculate') {
      secondValue = calculator.dataset.modValue
    }
  }
  
  calculator.dataset.modValue = secondValue
}</code></pre><p>Podemos refatorar isto para o seguinte:</p><pre><code class="language-js">if (keyType === 'calculate') {
  calculator.dataset.modValue = firstValue &amp;&amp; previousKeyType === 'calculate'
    ? modValue
    : displayedNum
}</code></pre><p>Como sempre, anote as propriedades e variáveis usadas:</p><pre><code class="language-js">const updateCalculatorState = (key, calculator) =&gt; {
  // Variáveis e propriedades necessárias
  // 1. key
  // 2. calculator
  // 3. calculatedValue
  // 4. displayedNum
  // 5. modValue
}</code></pre><h3 id="passando-vari-veis-necess-rias">Passando variáveis necessárias</h3><p>Sabemos que precisamos de cinco propriedades/variáveis para <code>updateCalculatorState</code>:</p><ol><li><code>key</code></li><li><code>calculator</code></li><li><code>calculatedValue</code></li><li><code>displayedNum</code></li><li><code>modValue</code></li></ol><p>Como o <code>modValue</code> pode ser acessado de <code>calculator.dataset</code>, &nbsp;só precisamos passar quatro valores: </p><pre><code class="language-js">const updateCalculatorState = (key, calculator, calculatedValue, displayedNum) =&gt; {
  // ...
}

keys.addEventListener('click', e =&gt; {
  if (e.target.matches('button')) return
  
  const key = e.target
  const displayedNum = display.textContent
  const resultString = createResultString(key, displayedNum, calculator.dataset)
  
  display.textContent = resultString
  
  // Passe os valores necessários
  updateCalculatorState(key, calculator, resultString, displayedNum)
})</code></pre><h3 id="refatorando-updatecalculatorstate-novamente"><strong>Refatorando <strong>updateCalculatorState </strong>novamente</strong></h3><p>Mudamos três tipos de valores em <code>updateCalculatorState</code>:</p><ol><li><code>calculator.dataset</code></li><li>A classe para operadores pressionados/despressionados</li><li><code>AC</code> para <code>CE</code> </li></ol><p>Se quiser tornar ainda mais claro, você pode dividir (2) e (3) em outra função — <code>updateVisualState</code>. Veja como pode ficar o &nbsp;<code>updateVisualState</code>:</p><pre><code class="language-js">const updateVisualState = (key, calculator) =&gt; {
  const keyType = getKeyType(key)
  Array.from(key.parentNode.children).forEach(k =&gt; k.classList.remove('is-depressed'))
  
  if (keyType === 'operator') key.classList.add('is-depressed')
  
  if (keyType === 'clear' &amp;&amp; key.textContent !== 'AC') {
    key.textContent = 'AC'
  }
  
  if (keyType !== 'clear') {
    const clearButton = calculator.querySelector('[data-action=clear]')
    clearButton.textContent = 'CE'
  }
}</code></pre><h3 id="finalizando"><strong>Finalizando</strong></h3><p>O código fica muito mais limpo após a refatoração. Se você examinar o ouvinte de eventos (<em>event listener</em>), saberá o que cada função faz. Abaixo, está a versão final do ouvinte de eventos (<em>event listener</em>):</p><pre><code class="language-js">keys.addEventListener('click', e =&gt; {
  if (e.target.matches('button')) return
  const key = e.target
  const displayedNum = display.textContent
  
  // Funções puras
  const resultString = createResultString(key, displayedNum, calculator.dataset)
  
  // Estados (states) atualizados
  display.textContent = resultString
  updateCalculatorState(key, calculator, resultString, displayedNum)
  updateVisualState(key, calculator)
})</code></pre><p>Você pode pegar o código fonte para a parte de refatoração através <a href="http://zellwk.com/blog/calculator-part-1"></a><a href="https://zellwk.com/blog/calculator-part-3">deste link</a> (texto em inglês - role até o final e digite seu nome e endereço de e-mail, que o código fonte será enviado diretamente para o seu e-mail).</p><p>Espero que tenha gostado deste artigo. Caso tenha gostado, talvez se interesse por <a href="https://learnjavascript.today/">Learn JavaScript</a> <em>("Aprenda Javascript", em inglês)</em> —um curso onde mostrarei como construir 20 componentes, passo a passo, da mesma maneira que construímos essa calculadora.</p><p>Observação: podemos melhorar ainda mais a calculadora adicionando suporte ao teclado e recursos de acessibilidade, como regiões, ao vivo. Quer saber como? Confira em <a href="https://learnjavascript.today/">Learn JavaScript</a> <em>(em inglês)</em> :)</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 4 razões para o z-index não estar funcionando (e como corrigi-las) ]]>
                </title>
                <description>
                    <![CDATA[ A propriedade z-index do CSS permite posicionar elementos em camadas uns sobre os outros. Ela é muito útil e, honestamente, uma ferramenta muito importante que você deve saber como usar no CSS. Infelizmente, o z-index é uma daquelas propriedades que nem sempre se comporta de maneira intuitiva. A princípio, ela ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/4-razoes-para-o-z-index-nao-estar-funcionando-e-como-corrigi-las/</link>
                <guid isPermaLink="false">61fb350053557304fa19e611</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lais Golin ]]>
                </dc:creator>
                <pubDate>Sun, 13 Mar 2022 10:33:56 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/03/1_Nm4AWKx-ezJBFLGShJCVAw.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/4-reasons-your-z-index-isnt-working-and-how-to-fix-it-coder-coder-6bc05f103e6c/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">4 reasons your z-index isn’t working (and how to fix it)</a>
      </p><p>A propriedade z-index do CSS permite posicionar elementos em camadas uns sobre os outros. Ela é muito útil e, honestamente, uma ferramenta muito importante que você deve saber como usar no CSS.</p><p>Infelizmente, o z-index é uma daquelas propriedades que nem sempre se comporta de maneira intuitiva. A princípio, ela parece simples — um número com o z-index mais alto significa que o elemento estará em cima dos elementos com números de z-index mais baixos. Mas existem algumas regras adicionais que tornam as coisas mais complicadas. E nem sempre é possível consertar as coisas ajustando o z-index para 999999!</p><p>Este artigo explicará em detalhes quatro das razões mais comuns para o z-index não funcionar, e como você pode resolvê-las. </p><p>Vamos passar por alguns exemplos reais de código. Após ler este artigo, você será capaz de entender e evitar essas armadilhas comuns do z-index!</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/qYi-OLf5q5g?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><p>Vamos verificar o primeiro motivo: </p><h3 id="1-os-elementos-no-mesmo-contexto-de-empilhamento-ser-o-exibidos-na-ordem-em-que-aparecem-com-os-ltimos-elementos-em-cima-dos-primeiros-"><strong><strong>1. </strong>Os elementos no mesmo contexto de empilhamento serão exibidos na ordem em que aparecem<strong>,</strong> com os últimos elementos em cima dos primeiros.</strong></h3><p>Em nosso primeiro exemplo, temos um layout relativamente simples que inclui 3 elementos principais:</p><ul><li>Uma imagem de um gato</li><li>Um bloco branco com um texto</li><li>Outra imagem do mesmo gato</li></ul><p>Aqui está o HTML do nosso exemplo: </p><pre><code class="language-html">&lt;div class="cat-top"&gt;&lt;/div&gt; 

&lt;div class="content__block"&gt; Meow meow meow... &lt;/div&gt; 

&lt;div class="cat-bottom"&gt;&lt;/div&gt;</code></pre><p>Neste layout, queremos que o bloco branco com o texto esteja em cima dos dois gatos. </p><p>Para tentarmos conseguir isso, adicionamos margens negativas ao CSS para ambas as imagens de gatos, de modo que elas se sobreponham um pouco sobre o bloco branco: </p><pre><code class="language-css">.cat-top { 
   margin-bottom: -110px; 
} 

.cat-bottom { 
   float: right; 
   margin-top: -120px; 
}</code></pre><p>No entanto, esta é a aparência: </p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_XQEyeX" src="https://codepen.io/thecodercoder/embed/preview/XQEyeX?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=XQEyeX" title="Z-index: #1: set position, #2: natural stacking order, #3: CSS properties" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><p>O primeiro gato está de fato posicionado sob o bloco de conteúdo branco, exatamente como nós queremos., mas a imagem do segundo gato está posicionada acima do bloco!</p><p>Por que isso ocorre?</p><p>O motivo para esse comportamento é a <strong>ordem n<strong>atural </strong>de empilhamento</strong> na página da web. Essas diretrizes basicamente determinam quais elementos estarão acima e quais estarão abaixo.</p><p>Mesmo que os elementos não tenham o z-index definido, há sempre um motivo para algum deles estar acima.</p><p>Em nosso caso, nenhum dos elementos tem um valor de z-index. Assim, sua ordem de empilhamento é determinada pela ordem de aparecimento. De acordo com essa regra, elementos que aparecem depois na sequência de marcação estarão acima dos elementos que vêm antes (você pode ler mais sobre as diretrizes da ordem de empilhamento na Mozilla Developer Network <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context" rel="noopener">aqui</a> - texto em inglês).</p><p>No nosso exemplo, com os gatos e o bloco branco, eles estão obedecendo essa regra. É por isso que o primeiro gato está abaixo do elemento do bloco branco e o bloco branco está abaixo do segundo gato.</p><p>Certo, a ordem de empilhamento está ok, mas como consertamos o CSS de modo que o segundo gato fique abaixo do bloco branco?</p><p>Vamos dar uma olhada no segundo motivo:</p><h3 id="2-o-elemento-n-o-tem-sua-posi-o-definida"><strong><strong>2. </strong>O elemento não tem sua posição definida</strong></h3><p>Uma das outras orientações que determinam a ordem de empilhamento é o fato de o elemento ter ou não a propriedade <em>position</em> definida.</p><p>Para definir a propriedade <em>position</em> de um elemento, adicione <code>position</code> ao seu CSS com qualquer valor que não seja <code>static</code>, como <code>relative</code> ou <code>absolute</code> (você pode ler mais sobre isso <a href="https://coder-coder.com/css-position-layout/" rel="noopener">neste artigo</a> que eu escrevi - texto em inglês).</p><p>De acordo com essa regra, os elementos posicionados serão exibidos acima dos elementos não posicionados.</p><p>Desse modo, definir o bloco branco de modo que tenha a propriedade <code>position: relative</code> e deixar os dois elementos com gatos sem posicionamento fará com que o bloco branco fique acima dos gatos na ordem de empilhamento.</p><p>Essa será a aparência – você também pode brincar com o Codepen acima.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/03/NlDhNhhBXrXmR35aZCt4XCGbfBCt4bRPLHzK.png" class="kg-image" alt="NlDhNhhBXrXmR35aZCt4XCGbfBCt4bRPLHzK" srcset="https://www.freecodecamp.org/portuguese/news/content/images/2022/03/NlDhNhhBXrXmR35aZCt4XCGbfBCt4bRPLHzK.png 600w" width="600" height="561" loading="lazy"></figure><p>U-húuuuu!</p><p>Agora, a próxima coisa a fazer é girar o gato de baixo ao contrário, usando a propriedade <code>transform</code>. Desse modo, os dois gatos estarão abaixo do bloco branco, mas somente com suas cabeças aparecendo.</p><p>Fazer isso, no entanto, causará mais uma confusão relacionada com o <code>z-index</code>. Trataremos do problema e da solução na próxima parte.</p><h3 id="3-definir-algumas-propriedades-do-css-como-opacity-ou-transform-colocar-o-elemento-em-um-novo-contexto-de-empilhamento-"><strong><strong>3. </strong>Definir algumas propriedades do<strong> CSS</strong>, como<strong> opacity o</strong>u<strong> transform</strong>,<strong> </strong>colocará o elemento em um novo contexto de empilhamento<strong>.</strong></strong></h3><p>Como acabamos de mencionar, queremos girar o gato de baixo ao contrário. Para conseguir isso, adicionamos <code>transform: rotate(180deg)</code>.</p><pre><code class="language-css">.cat-bottom { 
   float: right; 
   margin-top: -120px; 
   transform: rotate(180deg); 
}</code></pre><p>Isso, porém, faz com que o gato de baixo seja exibido acima do bloco branco novamente!</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/03/GTJjexmzYUkJa37hDuIUALqGngUjSl0wxFcE.png" class="kg-image" alt="GTJjexmzYUkJa37hDuIUALqGngUjSl0wxFcE" srcset="https://www.freecodecamp.org/portuguese/news/content/images/2022/03/GTJjexmzYUkJa37hDuIUALqGngUjSl0wxFcE.png 600w" width="600" height="558" loading="lazy"></figure><p><em>O que está acontecendo aqui<em>?</em></em></p><p>Você pode não encontrar esse problema com frequência, mas um outro aspecto da ordem de empilhamento é o fato de que algumas propriedades do CSS, como <code>transform</code> e <code>opacity</code>, colocarão o elemento em um novo <a href="https://www.w3.org/TR/css-color-3/#transparency" rel="noopener">contexto de empilhamento</a> (texto em inglês) próprio.</p><p>Isso significa que adicionar a propriedade <code>transform</code> ao elemento <code>.cat-bottom</code> faz com que ele se comporte como se tivesse um <code>z-index</code> de 0, mesmo que não tenhamos definido sua <code>position</code> nem seu <code>z-index</code>! A W3.org tem uma <a href="https://www.w3.org/TR/css-color-3/#transparency" rel="noopener">documentação informativa</a>, embora bastante densa, sobre como funciona a propriedade <code>opacity</code>.</p><p>Lembre-se, em nenhum momento adicionamos o valor <code>z-index</code> ao bloco branco, somente <code>position: relative</code>. Isso foi o suficiente para posicionar o bloco branco acima dos gatos não posicionados.</p><p>Porém, como o elemento <code>.bottom-cat</code> está agindo como se estivesse posicionado relativamente com <code>z-index: 0</code>, transformá-lo posicionou o gato acima do bloco branco.</p><p>A solução para isso é definir <code>position: relative</code> e definir explicitamente <code>z-index</code> pelo menos no bloco branco. Você pode ir um pouco mais longe e definir <code>position: relative</code> e um <code>z-index</code> menor para os elementos dos gatos, simplesmente por garantia.</p><pre><code class="language-css">.content__block { 
   position: relative; 
   z-index: 2; 
} 

.cat-top, .cat-bottom { 
   position: relative; z-index: 1; 
}</code></pre><p>Na minha opinião, fazer isso resolverá a maioria, se não todas as questões mais básicas relacionadas ao z-index.</p><p>Bem, vamos passar agora ao último motivo pelo qual o <code>z-index</code> pode não funcionar. Este é um pouco mais complexo, pois envolve elementos pais e filhos.</p><h3 id="4-o-elemento-est-em-um-contexto-de-empilhamento-menor-devido-ao-n-vel-de-z-index-do-elemento-pai"><strong><strong>4. </strong>O elemento está em um contexto de empilhamento menor devido ao nível de <strong>z-index </strong>do elemento pai</strong></h3><p>Vamos conferir nosso exemplo de código para isso:</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_qwYdZw" src="https://codepen.io/thecodercoder/embed/preview/qwYdZw?default-tabs=html%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=qwYdZw" title="Z-index: #4 different stacking contexts" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><p>Eis o que temos: uma página da web simples com conteúdo normal, e uma guia lateral rosa dizendo "Send Feedback" (Enviar feedback), posicionada acima do conteúdo.</p><p>Então, quando você clica na foto do gato, uma janela de modal se abre com um fundo cinza transparente de sobreposição.</p><p>Porém, mesmo quando a janela modal está aberta, a guia lateral segue acima da sobreposição cinza. Queremos que a sobreposição seja exibida sobre tudo, incluindo a guia lateral.</p><p>Vamos dar uma olhada no CSS dos elementos em questão:</p><pre><code class="language-css">.content { 
   position: relative; 
   z-index: 1; 
} 

.modal { 
   position: fixed; 
   z-index: 100; 
} 

.side-tab { 
   position: fixed; 
   z-index: 5; 
}</code></pre><p>Todos os elementos têm suas posições definidas. A guia lateral tem um <code>z-index</code> de 5, que a posiciona sobre o elemento do conteúdo, que tem um <code>z-index: 1</code>.</p><p>Em seguida, temos o modal, com <code>z-index: 100</code>, o que <em>deveria</em> colocá-lo acima da guia lateral, com <code>z-index: 5</code>. Em vez disso, a sobreposição do modal fica abaixo da guia lateral.</p><p>Por que isso ocorre?</p><p>Anteriormente, tratamos de alguns fatores que são importantes para o contexto de empilhamento, como o elemento ter sua posição definida e sua ordem na marcação.</p><p><strong>Existe, contudo, outro aspecto da ordem de empilhamento:<strong> </strong>o elemento filho é limitado ao contexto de empilhamento de seu pai<strong>.</strong></strong></p><p>Vamos examinar mais a fundo os três elementos em questão.</p><p>Aqui vemos a marcação:</p><pre><code class="language-css">&lt;section class="content"&gt;            
    &lt;div class="modal"&gt;&lt;/div&gt;
&lt;/section&gt;

&lt;div class="side-tab"&gt;&lt;/div&gt;</code></pre><p>Olhando para ela, podemos ver que os elementos <em>content</em> (conteúdo) e <em>side-tab</em> (guia lateral) são irmãos, ou seja, que eles existem no mesmo nível da marcação (o que é diferente do nível do <em>z-index</em>). Também vemos que o modal é um elemento filho do elemento <em>content</em>.</p><p>Como o modal está dentro do elemento <em>content</em>, seu <code>z-index</code> de 100 tem efeito apenas dentro do pai, o elemento <em>content</em>. Por exemplo, se houvesse outros elementos filhos de <em>content</em> e irmãos do modal, seus valores de <code>z-index</code> os colocariam acima ou abaixo uns dos outros.</p><p>O valor de <code>z-index</code> desses elementos filhos, no entanto, não significam nada fora do pai, pois o elemento pai <em>content</em> tem um <code>z-index</code> definido como 1.</p><p>Assim, seus filhos, incluindo o modal, não conseguem sair daquele nível do <code>z-index</code>.</p><p>Você pode se lembrar desta regra por meio de uma metáfora levemente deprimente: um filho pode estar limitado ao seus pais e não conseguir se libertar deles.</p><p>Existem algumas soluções para esse problema:</p><h3 id="solu-o-mover-o-modal-para-fora-do-elemento-pai-content-e-coloc-lo-no-contexto-de-empilhamento-principal-da-p-gina-"><strong><strong>Solu</strong>ção<strong>: </strong>mover o <strong>modal </strong>para fora do elemento pai<strong> <em>content</em> </strong>e colocá-lo no contexto de empilhamento principal da página<strong>.</strong></strong></h3><p>A marcação correta teria, então, esta aparência:</p><pre><code class="language-css">&lt;section class="content"&gt;&lt;/section&gt;

&lt;div class="modal"&gt;&lt;/div&gt;

&lt;div class="side-tab"&gt;&lt;/div&gt;</code></pre><p>Agora, o elemento modal é irmão dos outros dois elementos. Isso coloca os três elementos no mesmo contexto de empilhamento. Assim, seus níveis de z-index afetarão uns aos outros.</p><p>Nesse novo contexto de empilhamento, os elementos serão exibidos na seguinte ordem, de cima para baixo:</p><ul><li>modal (<code>z-index: 100</code>)</li><li>guia lateral (<code>z-index: 5</code>)</li><li>conteúdo (<code>z-index: 1</code>)</li></ul><h3 id="solu-o-alternativa-remover-o-posicionamento-de-content-para-que-ele-n-o-limite-o-z-index-do-modal-"><strong>Solução alternativa<strong>: </strong>r<strong>emove</strong>r<strong> </strong>o posicionamento de <em>content</em><strong>, </strong>para que ele não limite o<strong> z-index</strong> do modal<strong>.</strong></strong></h3><p>Se não quiser ou não puder mudar a marcação, você pode resolver o problema removendo a configuração de <code>position</code> do elemento <em>content</em>:</p><pre><code class="language-css">.content { 
   // Sem posição definida
} 

.modal { 
   position: absolute; 
   z-index: 100; 
} 

.side-tab { 
   position: absolute; 
   z-index: 5; 
}</code></pre><p>Como o elemento <em>content</em> agora não está posicionado, ele não limitará mais o valor de <code>z-index</code> do modal. Assim, o modal aberto será posicionado acima do elemento da guia lateral, devido ao seu <code>z-index</code> maior, de 100.</p><p>Embora isso dê certo, pessoalmente, eu prefiro a primeira solução, pois se, por alguma razão no futuro, você tiver de posicionar o elemento <em>content</em>, ele limitará novamente a ordem do modal no contexto de empilhamento.</p><h3 id="em-resumo"><strong>Em resumo</strong><br></h3><p>Espero que você tenha achado útil este tutorial! Para resumir, a maioria dos problemas com o z-index pode ser resolvida seguindo essas duas orientações:</p><ol><li>Verificar se os elementos têm a propriedade <em>position</em> definida e os valores de <em>z-index</em> na ordem correta.</li><li>Verificar se não há elementos pai limitando o nível de <code>z-index</code> de seus filhos.</li></ol><h4 id="quer-mais-informa-es"><strong>Quer mais informações<strong>?</strong></strong></h4><p>A autora está criando um curso sobre design responsivo! <a href="https://coder-coder.com/responsive-design-beginners/">Inscreva-se aqui</a> para receber um e-mail quando o curso for publicado (site em inglês).</p><p>A autora escreve tutoriais sobre desenvolvimento para a web em seu blog, <a href="https://coder-coder.com/" rel="noopener">coder-coder.com</a>, publica minidicas no <a href="https://www.instagram.com/thecodercoder/" rel="noopener">Instagram</a> e tutoriais de programação no <a href="https://www.youtube.com/c/codercodertv">YouTube</a>.<br></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ O comando Git Push explicado ]]>
                </title>
                <description>
                    <![CDATA[ O comando git push permite que você envie (ou em tradução literal, empurre) os commits de sua branch e repositório Git local para o seu repositório remoto.  Para poder fazer um git push para seu repositório remoto, você deve garantir que  todas as suas alterações no repositório local ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/o-comando-git-push-explicado/</link>
                <guid isPermaLink="false">6205b500cfef2204db7eda9e</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lais Golin ]]>
                </dc:creator>
                <pubDate>Sat, 05 Mar 2022 14:45:55 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/02/5f9c9e41740569d1a4ca3c2d.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/the-git-push-command-explained/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">The Git Push Command Explained</a>
      </p><p>O comando <code>git push</code> permite que você envie (ou em tradução literal, empurre) os commits de sua branch e repositório Git local para o seu repositório remoto. </p><p>Para poder fazer um <code>git push</code> para seu repositório remoto, você deve garantir que <strong>todas as suas alterações no repositório local sejam confirmadas.</strong></p><p>A sintaxe deste comando é a seguinte: </p><pre><code class="language-bash">git push &lt;nome do repositório&gt; &lt;nome da branch&gt;</code></pre><p>Existem várias opções diferentes que você pode passar com o comando. Você pode aprender mais sobre elas na <a href="https://git-scm.com/docs/git-push#_options_a_id_options_a">documentação</a> oficial (em inglês) do Git ou executar <code>git push --help</code>.</p><h3 id="enviar-para-um-reposit-rio-remoto-e-branch-espec-ficos"><strong><strong>Enviar para um repositório remoto e branch específicos</strong></strong></h3><p>Para fazer um push (em tradução livre: empurrar), primeiro você deve clonar um repositório para sua máquina local. </p><pre><code class="language-bash"># Quando um repositório é clonado, você trabalhará dentro da branch padrão (o padrão é `master` ou `main`)
git clone https://github.com/&lt;usuario-do-git&gt;/&lt;nome-do-repositorio&gt; &amp;&amp; cd &lt;nome-do-repositorio&gt;
# faça alterações e coloque seus arquivos em staging (repita o comando `git add` para cada arquivo, ou use `git add .` para fazer o staging de todos)
git add &lt;nome do arquivo&gt;
# agora faça o commit de seu código
git commit -m "added some changes to my repo!"
# faça o push das alterações na branch `master`\`main` no github
git push origin master</code></pre><p>Para aprender mais sobre as branches, confira os links abaixo (textos em inglês): </p><ul><li><a href="https://github.com/renington/guides/blob/master/src/pages/git/git-checkout/index.md">git checkout</a></li><li><a href="https://github.com/renington/guides/blob/master/src/pages/git/git-branch/index.md">git branch</a></li></ul><h3 id="fazer-o-push-para-um-reposit-rio-remoto-espec-fico-e-todas-as-suas-branches"><strong>Fazer o <strong>push para um repositório remoto específico e todas as suas branches </strong></strong></h3><p>Se quiser fazer o push de todas as suas mudanças e todas suas branches para o repositório remoto, você pode usar: </p><pre><code class="language-bash">git push --all &lt;NOME-DO-REPOSITÓRIO-REMOTO&gt;</code></pre><p>em que:</p><ul><li><code>--all</code> é o sinalizador que indica que você deseja enviar todas as branches para o repositório remoto. </li><li><code>NOME-DO-REPOSITÓRIO-REMOTO</code> é o nome do repositório remoto para o qual você deseja fazer o push.</li></ul><h3 id="fazer-o-push-para-uma-branch-espec-fica-com-o-par-metro-force"><strong>Fazer o p<strong>ush para uma branch específica com </strong>o <strong>parâmetro force </strong></strong></h3><p>Se quiser ignorar no Github as mudanças locais feitas no repositório do Git (que é o que a maioria dos desenvolvedores faz para uma correção no servidor de desenvolvimento), é possível usar o comando --force para enviar ignorando essas informações. </p><pre><code class="language-bash">git push --force &lt;NOME-DO-REPOSITÓRIO-REMOTO&gt; &lt;NOME-DA-BRANCH&gt;</code></pre><p>em que:</p><ul><li><code>NOME-DO-REPOSITÓRIO-REMOTO</code> é o nome do repositório remoto para o qual você deseja enviar as informações. </li><li><code>NOME-DA-BRANCH</code> é o nome da branch remota para a qual você deseja enviar as alterações. </li></ul><h3 id="fazer-o-push-ignorando-o-hook-pr-push-do-git">Fazer o push ignorando o hook pré-push do Git</h3><p>Por padrão, <code>git push</code> acionará o modo <code>--verify</code>. Isso significa que o git executará qualquer script pré-push do lado do client que possa ter sido configurado. Se os scripts de pré-push falharem, o git push também falhará. Hooks (gancho, em inglês) anteriores ao push são bons para fazer coisas como verificar se as mensagens de commit batem com os padrões da empresa, executar testes, entre outras. No fim, você poderá ignorar esse comportamento padrão. Um exemplo disso: em certo cenário, você deseja enviar suas alterações para a branch de um recurso para que outro colaborador faça o pull, mas suas alterações ao trabalho em andamento estão quebrando as unidades de teste. Para que o hook seja ignorado, basta inserir o comando push e adicionar o sinalizador <code>--no-verify</code></p><pre><code class="language-bash">git push --no-verify</code></pre><h3 id="mais-informa-es-em-ingl-s-"><strong><strong>Mais informações</strong> (em inglês)<strong><strong>:</strong></strong></strong></h3><ul><li><a href="https://git-scm.com/docs/git-push">Documentação do Git - push</a></li><li><a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">Git hooks</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Imagem de segundo plano no CSS — como adicionar um URL de imagem em uma div ]]>
                </title>
                <description>
                    <![CDATA[ Suponhamos que você queira colocar uma ou mais imagens em uma página da web. Uma maneira de fazer isso é utilizando a propriedade do CSS background-image. Essa propriedade aplica uma ou mais imagens de fundo a um elemento, como a <div> , conforme explicado na documentação [https://developer.mozilla.org/en-US/docs/Web/CSS/background-image] (link em inglês). ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/imagem-de-segundo-plano-no-css-como-adicionar-um-url-de-imagem-em-uma-div/</link>
                <guid isPermaLink="false">61f1bf9053557304fa19bde4</guid>
                
                    <category>
                        <![CDATA[ Propriedades do CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lais Golin ]]>
                </dc:creator>
                <pubDate>Mon, 31 Jan 2022 23:17:44 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/01/w-qjCHPZbeXCQ-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-add-an-image-url-to-your-div/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">CSS Background Image – How to Add an Image URL to Your Div</a>
      </p><p>Suponhamos que você queira colocar uma ou mais imagens em uma página da web. Uma maneira de fazer isso é utilizando a propriedade do CSS <strong><strong><code>background-image</code></strong>.</strong></p><p>Essa propriedade aplica uma ou mais imagens de fundo a um elemento, como a <strong><code>&lt;div&gt;</code>, </strong>conforme explicado na <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-image">documentação</a><em> (link em inglês). </em>Ela pode ser usada por motivos estéticos, como adicionando um plano de fundo texturizado para sua página da web.</p><h1 id="adicionando-uma-imagem"><strong>Adicionando uma imagem</strong></h1><p>É muito simples adicionar uma imagem usando a propriedade <code>background-image</code>. Basta informar o caminho da imagem no valor de <code>url()</code>.</p><p>Conforme mostrado no exemplo abaixo, o caminho da imagem pode ser um link passado por um URL:</p><pre><code class="language-css">div {
   /* Background pattern from Toptal Subtle Patterns */
   background-image: url("https://amymhaddad.s3.amazonaws.com/morocco-blue.png");
   height: 400px;
   width: 100%;
}
</code></pre><p>Também pode ser um caminho local. Aqui está mais um exemplo: </p><pre><code class="language-css">body {
   /* Background pattern from Toptal Subtle Patterns */
   height: 400px;
   width: 100%;
   background-image: url("./images/oriental-tiles.png");
}
</code></pre><h1 id="adicionando-v-rias-imagens"><strong>Adicionando </strong>várias imagens</h1><p>Também é possível adicionar várias imagens na propriedade <code>background-image.</code></p><pre><code class="language-css">div {
/* Background pattern from Toptal Subtle Patterns */
   height: 400px;
   width: 100%;
   background-image: 
       url("https://amymhaddad.s3.amazonaws.com/morocco-blue.png"),
       url("https://amymhaddad.s3.amazonaws.com/oriental-tiles.png");
   background-repeat: no-repeat, no-repeat;
   background-position: right, left; 
}
</code></pre><p>É muito código! Então, vamos por partes. </p><p>Vamos separar cada valor de <code>url()</code> das imagens com uma vírgula. </p><pre><code class="language-css">background-image: 
    url("https://amymhaddad.s3.amazonaws.com/morocco-blue.png"),
    url("https://amymhaddad.s3.amazonaws.com/oriental-tiles.png");
</code></pre><p>Agora posicione e destaque suas imagens aplicando propriedades adicionais.</p><pre><code class="language-css">background-repeat: no-repeat, no-repeat;
background-position: right, left; 
</code></pre><p>Existem diversas <a href="https://developer.mozilla.org/pt-BR/docs/Web/CSS/CSS_Backgrounds_and_Borders/Using_multiple_backgrounds">subpropriedades</a> que você pode adicionar às suas imagens de plano de fundo, como <strong><strong><code>background-repeat</code></strong></strong> e/ou <strong><strong><code>background-position</code></strong></strong>, que usamos no exemplo acima. Você também pode adicionar <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/gradient">gradientes</a> <em>(link em inglês)</em> em uma imagem de fundo.</p><p>Veja como fica quando adicionamos todas as propriedades. </p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_VwLqWbm" src="https://codepen.io/amymhaddad/embed/preview/VwLqWbm?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=VwLqWbm" title="background_image" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><h1 id="a-ordem-importa"><strong>A ordem importa</strong></h1><p>A ordem em que as imagens são listadas importa devido ao empilhamento. Conforme a <a href="https://www.w3.org/TR/css-backgrounds-3/#layering">documentação</a> <em>(link em inglês)</em>, isto significa que a primeira imagem listada está mais próxima do usuário. A segunda vêm logo após a primeira, ficando por trás da primeira imagem, e assim por diante. </p><p>Aqui está um exemplo: </p><pre><code class="language-css">div {
/* Background pattern from Toptal Subtle Patterns */
   height: 400px;
   width: 100%;
   background-image: 
       url("https://amymhaddad.s3.amazonaws.com/morocco-blue.png"),
       url("https://amymhaddad.s3.amazonaws.com/oriental-tiles.png");
   background-repeat: no-repeat, no-repeat;
}
</code></pre><p>No código acima, foram listadas duas imagens. A primeira imagem (morocco-blue.png) ficará na frente da segunda (oriental-tiles.png). As duas imagens são do mesmo tamanho e não possuem opacidade. Portanto, só vemos a primeira imagem. </p><p>No entanto, se movermos a segunda imagem (oriental-tiles.png) 200px para a direita, será possível ver uma parte dela (o restante permanecerá oculto).</p><p>Vejamos abaixo o que acontece quando colocamos tudo junto: </p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_oNXrXMo" src="https://codepen.io/amymhaddad/embed/preview/oNXrXMo?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=oNXrXMo" title="image_stacking_order" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe></figure><h2 id="quando-usar-a-imagem-de-fundo"><strong>Quando usar a imagem de fundo? </strong></h2><p>Existem diversas vantagens em usar a propriedade <code>background-image</code>. Porém, há uma desvantagem: </p><p>Conforme informado na <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-image">documentação</a> <em>(link em inglês)</em>, a imagem pode não ser acessível a todos os usuários, como àqueles que utilizam leitores de tela. </p><p>Isso acontece porque não é possível adicionar <strong>informações textuais</strong> na propriedade <code>background-image</code>. Desta forma, a imagem será perdida pelos leitores de tela.</p><p>Utilize a propriedade <code>background-image</code> apenas quando precisar adicionar alguma decoração à sua página. Caso utilize uma imagem com algum propósito ou significado na sua página da web, é melhor utilizar o elemento HTML <strong><code>&lt;img&gt;</code></strong>, conforme mencionado na <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-image">documentação</a> <em>(link em inglês)</em>.</p><p>Desta forma, é possível adicionar um texto descritivo à imagem utilizando o atributo <code><strong>alt</strong></code>. O texto fornecido no atributo será captado pelos leitores de tela. </p><pre><code class="language-html">&lt;img class="house" 
       src="./images/farnsworth_house.jpeg"
       alt="A glass house designed by Ludwig Mies van der Rohe located in Plano, Illinois."&gt;
</code></pre><p>Pense assim: <code>background-image</code> é uma propriedade do CSS, e o CSS foca na apresentação ou no estilo; já o HTML foca na semântica ou no significado.</p><p>Quando falamos de imagens, existem diversas opções. Se a imagem for apenas decorativa, então a propriedade <code>background-image</code> pode ser uma boa escolha para você.</p><p><em>A autora escreve sobre programação e sobre as melhores maneiras de programar<em><em><em> (</em></em></em>site da autora: <a href="https://amymhaddad.com/" rel="noopener nofollow">amymhaddad.com</a>).</em></p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
