Autor: admin

  • API do Whatsapp: Como quebrar linhas e passar parâmetros em links

    API do Whatsapp: Como quebrar linhas e passar parâmetros em links

    Quase todo site, sistema, ou app, hoje, precisa ter um botão para compartilhamento via Whatsapp. Para facilitar todo esse processo, o Whatsapp disponibiliza uma API própria para facilitar o processo para desenvolvedores.

    Porém, para o trabalho mais básico, um simples link de interação com um início de conversa, a documentação não é muito clara quanto a caracteres especiais e links.

    Criando um link para iniciar a conversa

    Para você criar um link para iniciar uma conversa, basta usar a URL https://api.whatsapp.com/send e passar os parâmetros específicos.

    Na prática, você poderia passar algo como:

    <a href="https://api.whatsapp.com/send?phone=55XX9XXXXXXXX;text=TextoParaEnviar">Enviar Mensagem</a>

    Importante: O telefone deve conter DDI e DDD e ser apenas número. Por exemplo, você vai mandar uma mensagem para alguém de Recife/PE – Brasil, o telefone precisa ser: 5581numero_do_celular.

    Até aí é bem simples. O problema está quando você quer enviar um parâmetro em um link, ou quando você quer enviar caracteres especiais como quebra de texto. O que vai acontecer é que a API do Whatsapp simplesmente irá remover qualquer tipo de código que ele considerar inseguro, através de um processo chamado de Sanitização.

    O Whatsapp, entretanto, utiliza-se de uma versão própria de parâmetros simples para tratar richtexts. Ou seja, simplesmente basta você converter os valores que você quer para URL Encode. Isso fará com que o texto seja entregue da forma como você planejou e você possa aplicar caracteres especiais e formatação.

    Exemplo prático

    Digamos que você queira enviar a seguinte mensagem:

    A pia pinga, o pinto pia…
    Quanto mais a pia pinga, mais o pinto pia.

    Acesse https://ratimbum.com/?token=333 para saber mais.

    Perceba que o texto possui quebra de texto e seu código será algo como:

    A pia pinga, o pinto pia...\n
    Quanto mais a pia pinga, mais o pinto pia.\n\n
    Acesse https://ratimbum.com/?token=333 para saber mais.

    Sim, você deverá usar \n para quebrar o texto. Porém, a sanitização vai retirar o \n e o ?, o que vai criar um resultado não esperado.

    Para resolver o problema, basta você converter o texto para URL Encode. No javascript, por exemplo, ficará assim:

    var texto = "A pia pinga, o pinto pia...\n
    Quanto mais a pia pinga, mais o pinto pia.\n\n
    Acesse https://ratimbum.com/?token=333 para saber mais.";
    texto = window.encodeURIComponent(texto);
    
    /*
    O resultado será algo como:
    A%20pia%20pinga%2C%20o%20pinto%20pia...%0A%0AQuanto%20mais%20a%20pia%20pinga%2C%20mais%20o%20pinto%20pia.%0A%0AAcesse%20https%3A%2F%2Fratimbum.com%2F%3Ftoken%3D333%20para%20saber%20mais.
    */

    Dessa forma, você pode optar por colocar esse código dinamicamente em um <a> ou, o que recomendo, enviar através da função window.open, do Javascript.

    function enviarMensagem(){
    	var celular = "55DDDNUMERODOCELULAR";
      
      var texto = "Texto que eu vou enviar \n com quebras de \n texto.";
      texto = window.encodeURIComponent(texto);
      
      window.open("https://api.whatsapp.com/send?phone=" + celular + "&amp;text=" + texto, "_blank");
    	//Obs.. use "_system", no lugar de blank, caso você esteja usando Phonegap / Cordova / Ionic ou qualquer um baseado em webview;
    }

    Obs: Você não precisa converter para \n se for pegar o texto a partir de um <textarea>, como mostrado no exemplo mais abaixo.

    É importante salientar que se você estiver testando no Whatsapp web, a quebra de linha não é mostrada na pre-visualização, mas será mostrada no momento do envio real da imagem.

    Corrigindo possível erro ERR_BLOCKED_BY_RESPONSE

    As vezes, pode ocorrer o erro ERR_BLOCKED_BY_RESPONSE, em alguns navegadores ou condições específicas (principalmente no Firefox). Isso ocorreu devido a algumas atualizações não bem descritas da API do Whatsapp.

    Para corrigir esse problema, faremos uma pequena atualização no código acima, o qual será necessário verificar se é mobile ou não, e passar o prefixo web no lugar de api. Acredito que também exista uma correlação quanto a navegadores desatualizados, que estejam causando o problema.

    function enviarMensagem(){
    	var celular = "55DDDNUMERODOCELULAR";
      
      var texto = "Texto que eu vou enviar \n com quebras de \n texto.";
      texto = window.encodeURIComponent(texto);
    
      let urlApi = "https://web.whatsapp.com/send";
      if(mobileCheck()){
      	urlApi = "https://api.whatsapp.com/send";
      }
      
      window.open(urlApi + "?phone=" + celular + "&text=" + texto, "_blank");
    	//Obs.. use "_system", no lugar de blank, caso você esteja usando Phonegap / Cordova / Ionic ou qualquer um baseado em webview;
    }
    
    
    function mobileCheck(){
      let check = false;
      (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
      return check;
    }

    Ocorre também que o código questão modifica um comportamento. Ele não mais alertará o usuário de que uma mensagem será enviada. Ao contrário disso, ele já abre direto no Whatsapp web.

    Outras opções

    Se o intuito, porém, for utilizar também outras propriedades do richtext, como negrito e itálico, você deverá simplesmente passar _ (itálico), * (negrito), ~ (riscado) ou “` (tamanho fixo). Exemplo:

    var mensagemParaWpp = mensagem.replace(/<b>/g, "*").replace(/<\/b>/g,"*"); 
    alert(s);

    Código de Exemplo

  • Sistemas de Design: Padronização de Sistemas

    Sistemas de Design: Padronização de Sistemas

    Design é projeto. E, como todo projeto, ele deve ser documentado, possuindo descrições, informações de uso e instruções em geral. É exatamente isso que são Sistemas de Design.

    Sistemas de Design são documentações, online ou físicas, que descrevem a padronização e uso de elementos de um projeto, com o objetivo de que ele possa ser usado em diferentes aplicações, mantendo uma identidade compartilhada. Essa identidade pode ser referenciada a um projeto, linha, segmento ou empresa. São usados elementos como formas, grades, tipografia, assets, iconografia, recomendações de uso, dentre outros. Algo muito semelhante ao que o design gráfico já está acostumado ao criar um Manual de Identidade Visual.

    Um exemplo comum, do dia a dia dos usuários de computador, é o Microsoft Office. Trata-se de um conjunto de aplicativos que, por serem da mesma linha, precisam seguir a mesma identidade. Para que os desenvolvedores possam trabalhar com esse padrão, um sistema de design certamente foi desenvolvido para que a equipe de desenvolvimento possa trabalhar de forma coerente.

    O Sistema de Design garante ao usuário uma fluidez no uso das aplicações e reconhecimento das propriedades do software. Facilitando, dessa forma, não só a identificação, como ajudando o usuário a pressupor determinados recursos ou localizações de ferramentas.

    Experiência Compartilhada

    Grandes empresas de tecnologia desenvolvem seus próprios sistemas de design para que desenvolvedores terceiros possa criar experiências mais coesas e confortáveis para o usuário. Seguir esses sistemas pode ser requerimento ou uma simples recomendação, dependendo da loja e sistema operacional que precisar aprovar.

    Aplicativos, mobile e desktop, são os mais comuns a receberem influencias direta dos sistemas de design de sistemas operacionais que, recomenda-se, devem ser mesclados aos sistemas da própria empresa. Para esses casos temos como exemplo:

    Como dito anteriormente, seguir um sistema de design de sistema operacional é fundamental para manter uma experiência fluida para o usuário. Por isso que, por exemplo, é possível sentir diferenças entre uma mesma aplicação desenvolvida para Windows, Android e dispositivos Apple, porque cada desenvolvedora, apesar de manter sua própria identidade, adapta-se para o ambiente em que o usuário estará.

    Screenshot do WhatsApp vs iOS
    O Whatsapp adapta quase que completamente sua UI de acordo com o sistema de design de cada Sistema Operacional
    Captura de tela do Visual Studio no Windows 10 x MacOSX
    Visual Studio no Windows 10 vs Visual Studio no MacOSX

    Não necessariamente o designer ou desenvolvedor são obrigados a seguir um determinado sistema de design de terceiros. Às vezes, a melhor opção é justamente criar o seu próprio sistema ou criar uma barreira para ter uma identidade única para sua aplicação.

    Algumas empresas, como a Google, estimulam para que os designers utilizem seus sistemas também em sites ou aplicativos web. Para isso, dão descrições específicas de usabilidade e ferramentas que possam agilizar o desenvolvimento dessas aplicações.

    Frameworks e Bibliotecas

    Para facilitar o desenvolvimento, muitas empresas oferecem frameworks e bibliotecas, tanto web quanto para desktop e mobile, afim de estimular o desenvolvedor a seguir aquele determinado padrão.

    É interessante para as grandes desenvolvedoras que outras empresas sigam seus padrões de design, pois, dessa forma, ditam tendências e criam assimilações dos usuários com suas próprias plataformas, principalmente quando essas outras empresas utilizam ferramentas e APIs das grandes.

    A exemplo de frameworks e bibliotecas temos:

    Porém, nem sempre essas opções suprem a demanda, pois não são compatíveis com outras bibliotecas e tecnologias. Por isso, muitos grupos de desenvolvedores trabalham para criar frameworks e bibliotecas abertas que seguem os padrões estipulados pelos sistemas de design. Como por exemplo:

    Utilizar Sistemas de Design, além de facilitar o processo de desenvolvimento, ajuda a manter o usuário mais confortável no ambiente em que ele está acostumado. Criar ou adaptar o seu próprio sistema também ajuda a criar uma identidade única para seu conjunto de aplicativos e serviços.

    Que outros sistemas de design e frameworks vocês podem recomendar? Deixem nos comentários.

  • Como Liberar Espaço no iPhone: Guia Completo para Otimizar Seu Dispositivo

    Como Liberar Espaço no iPhone: Guia Completo para Otimizar Seu Dispositivo

    Se você está notando que seu iPhone está mais lento, com menos espaço de armazenamento disponível ou simplesmente deseja melhorar seu desempenho geral, limpar dados do sistema pode ser uma solução eficaz. No entanto, muitos usuários não sabem exatamente como realizar essa limpeza de maneira segura e eficiente. Neste artigo, explicaremos passo a passo como limpar dados do sistema no iPhone, melhorar a performance do seu dispositivo e liberar espaço de armazenamento.

    O que São “Dados do Sistema” no iPhone?

    No iPhone, os dados do sistema referem-se a uma série de arquivos essenciais para o funcionamento do dispositivo. Esses dados incluem:

    • Arquivos temporários: Cache de aplicativos, logs do sistema e outros arquivos temporários.
    • Armazenamento de dados de aplicativos: Como arquivos de configuração e dados de cache.
    • Arquivos do sistema operacional iOS: Componentes essenciais para o funcionamento do sistema.

    Embora os dados do sistema sejam necessários para que o iPhone funcione corretamente, eles podem se acumular ao longo do tempo, ocupando uma quantidade significativa de espaço de armazenamento e impactando o desempenho do dispositivo.

    Por Que Limpar os Dados do Sistema?

    Limpar os dados do sistema pode ajudar em diversas situações, tais como:

    • Liberar espaço: Com o tempo, o armazenamento do seu iPhone pode ficar saturado com caches e arquivos temporários que não são mais necessários.
    • Melhorar o desempenho: A limpeza dos dados do sistema pode ajudar a reduzir o uso de recursos do dispositivo, tornando-o mais rápido e eficiente.
    • Correção de falhas: Às vezes, arquivos corrompidos ou desnecessários podem causar problemas no iPhone, e uma limpeza pode ajudar a resolver essas falhas.

    Como Limpar Dados do Sistema no iPhone

    1. Reiniciar o iPhone

    Uma das maneiras mais simples de limpar parte dos dados do sistema no iPhone é reiniciar o dispositivo. Isso ajuda a limpar caches temporários e reiniciar o funcionamento normal dos aplicativos.

    Passos:

    1. Pressione e segure o botão de liga/desliga (ou o botão lateral, dependendo do modelo) até que apareça o slider de desligamento.
    2. Arraste o slider para desligar o iPhone.
    3. Após o dispositivo desligar, aguarde alguns segundos e ligue-o novamente pressionando o botão de liga/desliga.

    2. Limpar o Cache de Aplicativos

    Muitos aplicativos, como Safari, YouTube e WhatsApp, acumulam dados de cache ao longo do tempo. Limpar esses caches pode liberar uma quantidade significativa de espaço no iPhone.

    Limpar Cache do Safari:

    1. Abra o Ajustes do iPhone.
    2. Role para baixo e toque em Safari.
    3. Toque em Limpar Histórico e Dados dos Sites.
    4. Confirme a ação tocando em Limpar Histórico e Dados.

    Isso removerá o cache, cookies e o histórico de navegação do Safari, ajudando a liberar espaço de armazenamento.

    Limpar Cache de Outros Aplicativos:

    Para limpar o cache de outros aplicativos, a maioria dos apps não oferece uma opção direta no iPhone. No entanto, você pode desinstalar e reinstalar o aplicativo para limpar todos os dados temporários e o cache acumulado.

    1. Desinstalar o aplicativo: Toque e segure o ícone do aplicativo até que ele comece a tremer e toque no “X” para remover.
    2. Reinstalar o aplicativo: Vá até a App Store e instale o aplicativo novamente.

    3. Gerenciar Armazenamento do iPhone

    O iPhone possui uma ferramenta integrada que permite gerenciar o espaço de armazenamento de maneira eficiente. Para acessar essas configurações:

    1. Abra Ajustes no seu iPhone.
    2. Toque em Geral.
    3. Selecione Armazenamento do iPhone.
    4. Aqui você verá uma lista de aplicativos e a quantidade de espaço que cada um ocupa, incluindo Dados do Sistema.

    Se você notar que algum aplicativo está ocupando muito espaço com dados de sistema, você pode optar por excluir o aplicativo e reinstalá-lo para liberar espaço.

    4. Limpar Arquivos de Sistema e Dados de Backup Antigos

    Alguns arquivos de sistema podem ser armazenados em seu iPhone, ocupando espaço sem que você perceba. Além disso, backups antigos do iCloud podem consumir espaço de forma desnecessária. Para limpar essas informações:

    Apagar Backups Antigos do iCloud:

    1. Abra Ajustes.
    2. Toque no seu nome no topo da tela para acessar o iCloud.
    3. Selecione Gerenciar Armazenamento.
    4. Toque em Backups.
    5. Veja a lista de dispositivos que têm backups e exclua os backups antigos que você não precisa mais.

    Limpar Dados de Sistema:

    Infelizmente, não há uma opção direta para limpar os dados do sistema do iPhone, mas com a limpeza dos caches e a remoção de backups antigos, você pode reduzir consideravelmente o uso de armazenamento pelo sistema.

    5. Restaurar o iPhone de Fábrica

    Se, após seguir todas as etapas acima, você ainda sentir que o iPhone está lento ou com problemas relacionados aos dados do sistema, você pode realizar uma restauração de fábrica. Este processo apagará todos os dados do dispositivo, incluindo dados do sistema, e restaurará o iPhone para suas configurações originais.

    Passos:

    1. Faça um backup de todos os seus dados importantes (fotos, contatos, etc.).
    2. Vá até Ajustes > Geral > Redefinir.
    3. Selecione Apagar Conteúdo e Ajustes.
    4. Confirme a ação e siga as instruções para restaurar o iPhone.

    Após a restauração, você precisará configurar seu iPhone novamente, como se fosse um dispositivo novo. Isso pode ser uma solução eficaz para liberar espaço e corrigir problemas com dados do sistema.

    Conclusão

    Limpar dados do sistema no iPhone pode ser uma maneira eficaz de liberar espaço de armazenamento e melhorar o desempenho do dispositivo. Embora o processo de remoção de dados do sistema não seja totalmente automático, você pode utilizar as etapas mencionadas acima para otimizar o seu iPhone. Desde a reinicialização simples até a exclusão de backups antigos e a restauração de fábrica, existem várias formas de manter seu dispositivo funcionando de maneira eficiente.

  • Como fazer backup ou transferência de cloud drive com rclone

    Como fazer backup ou transferência de cloud drive com rclone

    O rclone é uma ferramenta de linha de comando extremamente poderosa para quem precisa gerenciar arquivos entre diferentes serviços de armazenamento em nuvem. Ele é ideal para usuários que desejam:

    • Fazer backup dos seus arquivos em nuvens diferentes
    • Sincronizar conteúdo entre um serviço e outro
    • Baixar todos os seus dados de uma conta antes de encerrá-la
    • Copiar arquivos em massa com muito mais controle e confiabilidade do que as ferramentas oficiais

    Em muitos casos, como no OneDrive, essa necessidade se tornou ainda mais comum devido ao aumento dos preços dos planos, em decorrências a outros serviços com preços mais em conta. Além disso, quando você tenta baixar muitos dados simultâneos em diversos serviços o download trava ou resulta em pastas vazias ao copiar dos aplicativos oficiais, ao transferir pastas.


    Instalação do rclone

    macOS (via Homebrew)

    brew install rclone

    Linux (Debian, Ubuntu e derivados)

    curl https://rclone.org/install.sh | sudo bash

    Ou via gerenciador de pacotes:

    sudo apt install rclone

    Windows

    1. Acesse: https://rclone.org/downloads/
    2. Baixe a versão .zip para Windows
    3. Extraia e coloque a pasta em um local fixo (ex: C:\Program Files\rclone)
    4. Adicione o caminho da pasta ao Path do sistema para usar via terminal

    Como adicionar o rclone ao PATH no Windows

    Localize a pasta onde está o executável

    Após extrair o .zip do Rclone, você terá algo como:

    C:\Program Files\rclone ou C:\Users\SeuUsuario\Downloads\rclone-vXXX-windows-amd64

    Copie o caminho completo da pasta. Por exemplo:

    C:\Program Files\rclone

    Abra as variáveis de ambiente

    Pressione Win + S e digite variáveis de ambiente

    Clique em “Editar variáveis de ambiente do sistema”

    Na janela que abrir, clique no botão “Variáveis de ambiente…” no canto inferior direito

    Em Variáveis do sistema, encontre a variável chamada Path e clique em Editar…

    Clique em Novo e cole o caminho da pasta que você copiou

    Clique em OK em todas as janelas para confirmar


    Configurando o acesso ao OneDrive (ou outra nuvem)

    Execute:

    rclone config

    Siga as instruções passo a passo:

    1. Digite n para criar uma nova configuração
    2. Escolha um nome para ela (ex: onedrive)
    3. Aparecerá uma lista numerada de serviços de nuvem. Escolha o número correspondente ao OneDrive.Importante: essa lista pode mudar de ordem conforme a versão do Rclone. Leia atentamente ao lado de cada número.
    4. Quando for perguntado sobre “client_id” e “client_secret”, pode apenas pressionar Enter para usar os padrões do Rclone.
    5. No prompt sobre “Edit advanced config?”, escolha n, a menos que saiba o que está fazendo.
    6. Quando perguntado sobre usar “auto config”, escolha y se estiver em um computador com navegador instalado. Isso abrirá o login da Microsoft no navegador para autorização.
    7. Depois de autorizado, volte ao terminal e confirme a gravação da configuração.

    É obrigatório sincronizar os arquivos?

    Não. O rclone permite tanto copiar quanto sincronizar arquivos:

    • rclone copy copia arquivos de origem para destino sem apagar nada
    • rclone sync sincroniza origem e destino, apagando do destino o que não existir mais na origem

    Para a maioria dos usuários que estão apenas fazendo backup ou transferindo dados, o ideal é usar copy, pois é mais seguro.


    Exemplo: Copiar tudo do OneDrive (exceto algumas pastas)

    rclone copy onedrive: ~/OneDriveBackup \
      --progress \
      --exclude "Vídeos Compartilhados/**" \
      --exclude "Backup do GOG/**"

    Esse comando faz o seguinte:

    • Copia todos os arquivos do OneDrive para a pasta local ~/OneDriveBackup (você pode dar o nome que quiser à pasta)
    • Exibe o progresso durante a transferência
    • Ignora as pastas Vídeos Compartilhados e Backup do GOG, assim como todos os arquivos e subpastas dentro delas

    Se quiser testar antes sem copiar nada, use a opção --dry-run:

    rclone copy onedrive: ~/OneDriveBackup --dry-run --exclude "Videos Compartilhados/**"

    Outras opções úteis

    Listar as pastas da raiz:

    rclone lsd onedrive:

    Listar arquivos:

    rclone ls onedrive:

    Sincronizar (com cautela):

    rclone sync onedrive: ~/OneDriveBackup --progress

    Atenção: sync pode apagar arquivos locais se eles não existirem mais na nuvem.

    Validar arquivos por tamanho pode ser útil para quando você copia os arquivos de outra origem e não quer sobrevescrever um arquivo que você já possua na pasta.

    rclone copy onedrive: ~/OneDriveBackup --size-only

    Concluindo

    O rclone é uma ferramenta robusta para quem precisa mais controle sobre arquivos em nuvem. Ele não depende de interfaces gráficas, é multiplataforma, e é confiável mesmo para grandes volumes de dados.

    Se você está migrando de um serviço para outro, fazendo backup, ou tentando contornar limitações do aplicativo oficial (como as do OneDrive), o rclone é uma solução altamente recomendada.

    Manter o controle total dos seus dados nunca foi tão fácil.


    Se quiser aprofundar ainda mais, você pode consultar a documentação oficial em: https://rclone.org/

  • Desenvolvimento

    Desenvolvimento

    Desenvolvemos sistemas completos, performáticos e seguros para diferentes necessidades de negócio. Atendemos desde pequenas aplicações até projetos mais robustos, com expertise em:

    • Backend com PHP ou Java
    • Banco de Dados SQL e NoSQL
    • Aplicativos híbridos com Ionic
    • Integrações com APIs, gateways de pagamento e serviços em nuvem
    • WordPress avançado: temas e plugins do zero

  • Design

    Design

    Criamos experiências visuais com foco em pessoas, conversão e consistência. Cada projeto é pensado para equilibrar estética e função, utilizando:

    • UI/UX para aplicações web e mobile
    • Prototipação e fluxo de navegação com Sketch
    • Design de identidade visual e materiais de marca
    • Suporte visual para apresentações, landing pages e campanhas
  • Consultoria

    Consultoria

    Apoiamos empresas e equipes no desenho e evolução de suas soluções digitais, com foco em eficiência, escalabilidade e boas práticas. Atuamos em:

    • Arquitetura de sistemas e definição de stack
    • Refatoração e modernização de aplicações legadas
    • Mentoria técnica e revisão de código
    • Planejamento de integrações, performance e segurança
  • Como centralizar verticalmente elementos HTML com CSS

    Como centralizar verticalmente elementos HTML com CSS

    Uma das coisas mais comuns, mas ao mesmo tempo mais chatas de se fazer no CSS é alinhar verticalmente elementos em tela. Existem várias formas de fazer isso. Neste post, vou elencar as minhas formas favoritas de fazer isso.

    Alinhamento com Flexbox

    Flex é uma propriedade incrível do CSS que permite organizar elementos. Se outrora tínhamos que fazer inúmeras gambiarras com float, o flex nos permite controlar o comportamentos dos filhos de um container. Para centralizar verticalmente um objeto, podemos usar a direção de coluna, em seu container pai.

    Alinhamento com position

    Com um pouco de matemática, conseguimos fazer um alinhamento vertical com o position absolute. Porém, é importante lembrar que o objeto será flutuante e que seu pai, necessariamente, precisa ser um position relative. O problema de usar esse tipo de alinhamento é que o conteúdo da posição precisa ser fixo. Felizmente, hoje, conseguimos fazer cálculos com variáveis de CSS, o que facilita a forma de implementarmos essa técnica. A vantagem dessa técnica é poder usar, justamente, em ambientes flutuantes que se sobreponham. Porém, caso você não precise que ele se alinhe ao pai, mas à viewport, você pode usar também o position como fixed.

    Alinhamento com Grid

    Outra forma moderna de alinhar verticalmente é através do uso de grids. A vantagem de usar grids é que o tamanho do conteúdo do elemento alinhado corresponderá ao tamanho da grid que se deseja utilizar. Ou seja, é adaptável de acordo com a viewport, e não referente ao seu conteúdo. Para isso, basta definirmos a quantidade de colunas e linhas que desejamos e estabelecemos onde o objeto alinhado vai iniciar e terminar.

    Exemplo de uso (Modal Alinhado ao Centro)

    Para mostrar como pode ser usado os alinhamentos, que tal criarmos um simples modal alinhado ao centro da tela?

    Um modal é composto por uma cortina que reveste o conteúdo original, seguido de um painel com alguma informação dentro. É convenção de que os modals carreguem essas informações no centro da tela, afim de que a informação fique direcionada e encapsulada, levando, assim, o usuário à uma atenção maior àquela informação. Ou seja, isolar e destacar. O exemplo abaixo foi feito usando a primeira estratégia de alinhamento vertical aqui apresentada, pois, desta forma, o tamanho do modal que vai ser a referência para a centralização. Alguns efeitos foram adicionados para ilustrar melhor.

  • Como adicionar e remover dinamicamente campos HTML em um form? (Javascript puro)

    Como adicionar e remover dinamicamente campos HTML em um form? (Javascript puro)

    O Javascript nos permite criar conteúdos dinâmicos e podemos usar isso para adicionar remover e adicionar elementos de acordo com as opções do usuário. Dados como informações sobre dependentes, links de mídias sociais, e-mails adicionais, etc. são curtos e não fazem sentido criarmos um formulário separado apenas para estes. Por isso, é interessante incluirmos a opção de adicionar diretamente esses campos em um subformulário dinâmico.

    Obs. Se quiser ir direto para o código final, procure o link do JsFiddle no final do post.

    HTML

    Para iniciarmos, basta criar um container no HTML onde você quer que os elementos sejam exibidos, além do botão simples de adição e um botão de captura de dados, para que, desta forma, possamos enviar o JSON resultante para o back-end.

    A organização dos containers é sempre muito importante quando trabalhamos com Javascript e nos dedicamos ao uso correto da web semântica.

    <div class="dependentes">
      <button id="btnAdicionarDependentes">
      📝Adicionar Dependentes
      </button>
      <div class="container" id="dependentesContainer">
      </div>
      <button class="green" id="btnCapturarDados">
      ✅ Capturar Dados
      </button>
    </div>
    <pre id="containerDados">  
    </pre>

    Javascript

    Como de praxe, usaremos o Javascript puro para realizar essa tarefa, dessa forma você poderá usar em qualquer lugar o que aprender aqui.

    Para poder capturar e devolver os dados, usaremos um objeto JSON, dessa forma fica fácil remontar, tanto no back-end, quando no front-end, os dados nas formatações e/ou elementos que precisamos.

    Vamos criar, como exemplo, o JSON abaixo, e vamos declará-lo em uma variável global chamada dependentes, seguindo a ideia de um cadastro de lista de dependentes, então temos:

    var dependentes = [{
      identificador: 13,
      nome: "Joana da Silva",
      idade: 12,
    }];

    Agora vamos nos focar nas funções. A primeira coisa que vamos fazer é criar um método que pegue os dados do JSON e o converta para elementos HTML renderizados na tela. Dessa forma, usaremos um laço para ler o JSON e aplicamos seus dados em uma template string e o adicionamos no container específico:

    function carregarDependentes() {
      let dependentes_container = document.querySelector("#dependentesContainer");
      dependentes_container.innerHTML = "";
      dependentes.forEach((el) =&gt; {
        let identificador = el.identificador;
        let nome = el.nome;
        let idade = el.idade;
        let dependente_container = `<div class="dependente" data-id="${identificador}">
        								<input class="nome" placeholder="Digite o nome" type="text" value="${nome}">
                                        <input class="idade" placeholder="Digite a idade" type="number" value="${idade}">
                                        <div class="action">
                                            <a href="#" class="salvar">salvar 💾</a>
                                            <a href="#" class="remover">❌</a>
    									</div>
                                    </div>`;
        dependentes_container.innerHTML += dependente_container;
      });
    }

    Agora vem o segredo que facilita o processo e o deixa mais organizado. Ao invés de remover e adicionar os elementos na tela, iremos nos focar em remover e adicionar do JSON e, em seguida, regenerar os elementos a partir desse objeto. Ficando, assim, com um código mais limpo. Outro motivo pelo qual usamos a regeneração dos elementos é para evitar criarmos IDs únicos temporários. Ao regenerar, podemos usar os índices do próprio array como identificador.

    Para adicionar um novo item, basta incluirmos um dado vazio no JSON, porém, seguindo nosso modelo, e mandamos gerar novamente os elementos:

    function adicionarDependentes() {
      dependentes.push({ identificador: "", nome: "", idade: "" });
      carregarDependentes();
    }

    Para remover, similar a criação de um novo, vamos usar um laço, porém para adicionar o evento aos botões de excluir. Usaremos então o método splice para remover o array. Depois, obviamente, vamos regenerar os elementos a partir da função carregarDependentes():

    function removerDependentes() {
      document
        .querySelectorAll("#dependentesContainer .remover")
        .forEach((el, i) =&gt; {
          el.addEventListener("click", () =&gt; {
            dependentes.splice(i, 1); // O splice vai remover um item do array no JSON
            carregarDependentes(); // E chamamos o método para regenerar os elementos
          });
        });
    }

    Uma vez que adicionamos uma nova linha em branco precisamos salvar seu preenchimento e aí iremos usar a mesma lógica de remoção, mas usaremos o splice para substituir e não para remover um dado do JSON. Porém, adicionaremos uma pequena validação para evitar entrar dados incompletos:

    unction salvarDependentes() {
      document
        .querySelectorAll("#dependentesContainer .salvar")
        .forEach((el, i) =&gt; {
          el.addEventListener("click", () =&gt; {
            let identificador = el.parentElement.parentElement.getAttribute(
              "data-id"
            );
            let nome = el.parentElement.parentElement.querySelector(".nome").value;
            let idade = el.parentElement.parentElement.querySelector(".idade")
              .value;
    
            if (!nome.length || !idade.length) { // Verifica se nome e idade foram preenchidos
              alert("Nome e idade precisam ser preenchidos para salvar.");
              return false;
            }
            dependentes.splice(i, 1, {
              identificador: identificador,
              nome: nome,
              idade: idade,
            }); // Substitui o dado no JSON
            carregarDependentes(); //  E chamamos o método para regenerar os elementos
          });
        });
    }

    Um outro método que precisamos adicionar é uma forma de bloquear para que um usuário consiga clicar em outros elementos ao redor, sem antes finalizar a edição do item. Para isso, iremos fazer um laço que adiciona uma classe de CSS, que vamos chamar de disabled, em todos os elementos, exceto o que está sendo editado. Essa classe possui um point-events: 0 e um opacity: 0.5. Para demonstrar que está desativado, você pode ainda adicionar outros efeitos, como filtros de baixo contraste ou escala de cinza.

    function travarOutros(element) {
      if (element == false) { // Passar false como parâmetro para que todos os elementos fiquem habilitados novamente, ao invés de apenas o elemento que queremos liberar
        document
          .querySelectorAll(".dependentes button, .dependentes .container &gt; div")
          .forEach((el) =&gt; {
            el.classList.remove("disabled");
          });
        document.querySelector("#containerDados").innerHTML = "";
        return false;
      }
      document
        .querySelectorAll(".dependentes button, .dependentes .container &gt; div")
        .forEach((el) =&gt; {
          if (el != element) {  // Verifica se o elemento no laço é o que está sendo editado
            el.classList.add("disabled");
          }
        });
    }

    Agora, antes de continuarmos, vamos revisitar as funções acima para chamar, quando necessário, uma função dentro da outra (leia os comentários no código para entender), ficando assim:

    function carregarDependentes() {
      let dependentes_container = document.querySelector("#dependentesContainer");
      dependentes_container.innerHTML = "";
      dependentes.forEach((el) =&gt; {
        let identificador = el.identificador;
        let nome = el.nome;
        let idade = el.idade;
        let dependente_container = `<div class="dependente" data-id="${identificador}">
        															<input class="nome" placeholder="Digite o nome" type="text" value="${nome}">
                                      <input class="idade" placeholder="Digite a idade" type="number" value="${idade}">
                                      <div class="action">
                                      	<a href="#" class="salvar">salvar 💾</a>
                                        <a href="#" class="remover">❌</a>
    																	</div>
    															  </div>`;
        dependentes_container.innerHTML += dependente_container;
      });
      salvarDependentes(); // Adicionamos o método aqui para que o laço seja aplicado nos novos items adicionados
      removerDependentes(); // Adicionamos o método aqui para que o laço seja aplicado nos novos items adicionados
      travarOutros(false); // Adicionamos para destravar tudo
    }
    
    function removerDependentes() {
      document
        .querySelectorAll("#dependentesContainer .remover")
        .forEach((el, i) =&gt; {
          el.addEventListener("click", () =&gt; {
            dependentes.splice(i, 1);
            carregarDependentes(); // Regenerar os elementos HTML após remover do JSON
          });
        });
    }
    
    function adicionarDependentes() {
      dependentes.push({ identificador: "", nome: "", idade: "" });
      carregarDependentes(); // Regenerar os elementos HTML após remover do JSON
      travarOutros(
        document.querySelector("#dependentesContainer &gt; div:last-child")
      ); // Desabilitar todos os outros elementos, exceto o que acabou de ser adicionado
    }
    
    function salvarDependentes() {
      document
        .querySelectorAll("#dependentesContainer .salvar")
        .forEach((el, i) =&gt; {
          el.addEventListener("click", () =&gt; {
            let identificador = el.parentElement.parentElement.getAttribute(
              "data-id"
            );
            let nome = el.parentElement.parentElement.querySelector(".nome").value;
            let idade = el.parentElement.parentElement.querySelector(".idade")
              .value;
    
            if (!nome.length || !idade.length) {
              alert("Nome e idade precisam ser preenchidos para salvar.");
              return false;
            }
            dependentes.splice(i, 1, {
              identificador: identificador,
              nome: nome,
              idade: idade,
            });
            carregarDependentes(); // Regenerar os elementos HTML após remover do JSON
            travarOutros(false); // Liberar todos os elementos novamente
          });
        });
    }
    
    function travarOutros(element) {
      if (element == false) {
        document
          .querySelectorAll(".dependentes button, .dependentes .container &gt; div")
          .forEach((el) =&gt; {
            el.classList.remove("disabled");
          });
        document.querySelector("#containerDados").innerHTML = "";
        return false;
      }
      document
        .querySelectorAll(".dependentes button, .dependentes .container &gt; div")
        .forEach((el) =&gt; {
          if (el != element) {
            el.classList.add("disabled");
          }
        });
    }

    Agora, tudo o que precisamos fazer é incluir os comandos de inicialização, onde aplicamos o método de adição ao evento de clique do botão e carregamos os dados iniciais do JSON:

    //init
    document.querySelector("#btnAdicionarDependentes").addEventListener("click", adicionarDependentes);
    carregarDependentes();

    Por fim, vamos criar uma função para o botão de capturar dados apenas para extrair e mostrar os dados em JSON. Você pode, eventualmente, usar esses dados e enviar via POST, por AJAX ou via campo oculto, e pegar no back-end para guardar ou processar os dados (como com um json_decoder, do PHP):

    //capturarDados
    document.querySelector("#btnCapturarDados").addEventListener("click", ()=&gt;{
    	document.querySelector("#containerDados").innerHTML = JSON.stringify(dependentes, undefined, 4);
    });

    CSS

    O único CSS que precisaremos usar é para aplicar a classe disabled. Se por acaso você está usando algum framework CSS, recomendo que você use o relativo a esta classe deste. Consulte a documentação, onde geralmente está relacionado aos helpers:

    .disabled{
      pointer-events: none;
      opacity: .5;
    }

    Se você quer usar o CSS mais elaborado que usei aqui, veja abaixo o link do JsFiddle.

    Finalizando

    Criar formulários dinâmicos auxilia a usabilidade à medida que permite que o usuário adicione dados de forma mais rápida e com respostas visuais imediatas. O uso aqui do Javascript puro visa a facilidade para que você possa implementar em quaisquer projetos, incluindo os com Typescript. Trabalhe um pouco no código para adequá-lo à sua necessidade. E, como sempre, você poderá puxar o código e testar direto do JsFiddle.

    Aproveite e entre para nosso grupo de discussão no Telegram.