
A necessidade
Hoje eu pensei em criar um componente em Astro para compartilhar artigos que eu estou criando no meu blog.
A estrutura de dados
Pensei em criar um componente chamado SocialShare
.
- src
- components
SocialShare.astro
Dentro desse componente eu teria um array com os dados dos botões que usarei.
const buttons = [
{
url:``,
icon: ``
},
]
A url
irá ter a url de compartilhamento da rede social e o icon
será o ícone em formato svg
.
Iremos utilizar as seguintes propriedades e variáveis
interface Props {
url?: string;
title: string;
description: string;
image: string;
}
const {
url = Astro.request.url,
title,
description,
image } = Astro.props;
const encoded_url = encodeURIComponent(url);
A url
é opcional, já que iremos pegar de maneira dinâmica com Astro.request.url
. Vamos precisar título title
, descrição description
e imagem image
do nosso artigo, pois dependendo de cada link que geraremos, utilizaremos um ou outro. Exemplo: Pinterest utilizaremos a imagem, Twitter utilizaremos a descrição e Facebook utilizaremos o título.
Os links sociais
Uma das etapas que exigiu bastante busca (~2 minutos 😆) foi encontrar os links sociais que eu gostaria de usar para compartilhar. Num primeiro momento queria usar o X, Facebook, LinkedIn e Pinterest. Mas pensei em colocar outros também, mesmo eu não usando muito, como o Reddit, por exemplo. Então, encontrei esse artigo que me ajudou a encontrar os links que eu queria, até outros que eu nem sabia que existiam ou que não estavam no meu radar como WhatsApp e Telegram.
Vamos ver o exemplo do link de compartilhamento do WhatsApp
https://api.whatsapp.com/send?text=%text% %url%
Vamos substituir o %text%
com o texto que queremos e %url%
com a url do nosso artigo.
Os ícones
Agora, eu saí para buscar os ícones em formato SVG para compor a lista de itens. Existem 2 sites que geralmente uso para encontrar svg das marcas. O Simple Icons e o SVGL. Neste caso eu usei o Simple Icons pois já estavam bem perto do formato final que eu esperava - preto e branco.
Abaixo um exemplo do ícone X
.
<svg
class="dark:fill-white h-[1.2rem] w-[1.2rem]"
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<title>X</title>
<path
d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"
/>
</svg>
O ponto principal aqui é adicionar classes para largura, altura e dark mode no element svg
e estou utilizando TailwindCSS para isso.
A construção do link de compartilhamento
Agora que temos a url e o ícone para compor nosso array
de botões, teríamos algo semelhante a isso. (no exemplo, apenas 1 elemento, mas serão quantos necessários)
const buttons = [
{
url: `https://twitter.com/intent/tweet?url=${url}&text=${description}&via=maykbrito`,
icon: `<svg class="dark:fill-white h-[1.2rem] w-[1.2rem]" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>X</title><path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"/></svg>`
},
]
Vamos iniciar a construção do html nosso SocialShare.astro
<div class=`flex gap-2 mt-6`>
{
buttons.map(({url, icon}) => (
<a class="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 w-10"
href={url} rel="noopener noreferrer" target="_blank">
<span set:html={icon} />
</a>
))
}
</div>
Pontos de destaque
- Estou utilizando TailwindCSS para dar um estilo bacana e copiei as classes do componente Button do ShadcnUI e as adicionei ao nosso element
<a>
- Ainda no elemento
<a>
eu acionei os atributosrel="noopener noreferrer"
para evitar que informações de referência sejam passas para os sites etarget="_blank"
para garantir a abertura do link em uma nova aba. Para saber mais, tem essa thread no Stackoverflow set:html
é uma diretiva do Astro que diz para esse conteúdo ser convertido em HTML, já que estamos criando osvg
comostring
dentro do nossoarray
de botões
O Resultado
Aqui está todo o código final
---
interface Props {
url?: string;
title: string;
description: string;
image: string;
}
const {
url = Astro.request.url,
title,
description,
image } = Astro.props;
const encoded_url = encodeURIComponent(url);
const buttons = [
{
url: `https://twitter.com/intent/tweet?url=${url}&text=${description}&via=maykbrito`,
icon: `<svg class="dark:fill-white h-[1.2rem] w-[1.2rem]" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>X</title><path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"/></svg>`
},
{
url: `https://www.linkedin.com/sharing/share-offsite/?url=${encoded_url}`,
icon: `<svg class="dark:fill-white h-[1.2rem] w-[1.2rem]" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>LinkedIn</title><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>`,
},
{
url: `https://www.facebook.com/sharer/sharer.php?u=${encoded_url}&t=${title}`,
icon: `<svg class="dark:fill-white h-[1.2rem] w-[1.2rem]" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Facebook</title><path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"/></svg>`
},
{
url:`https://pinterest.com/pin/create/button/?url=${encoded_url}&media=${image}&description=${description}`,
icon: `<svg class="dark:fill-white h-[1.2rem] w-[1.2rem]" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Pinterest</title><path d="M12.017 0C5.396 0 .029 5.367.029 11.987c0 5.079 3.158 9.417 7.618 11.162-.105-.949-.199-2.403.041-3.439.219-.937 1.406-5.957 1.406-5.957s-.359-.72-.359-1.781c0-1.663.967-2.911 2.168-2.911 1.024 0 1.518.769 1.518 1.688 0 1.029-.653 2.567-.992 3.992-.285 1.193.6 2.165 1.775 2.165 2.128 0 3.768-2.245 3.768-5.487 0-2.861-2.063-4.869-5.008-4.869-3.41 0-5.409 2.562-5.409 5.199 0 1.033.394 2.143.889 2.741.099.12.112.225.085.345-.09.375-.293 1.199-.334 1.363-.053.225-.172.271-.401.165-1.495-.69-2.433-2.878-2.433-4.646 0-3.776 2.748-7.252 7.92-7.252 4.158 0 7.392 2.967 7.392 6.923 0 4.135-2.607 7.462-6.233 7.462-1.214 0-2.354-.629-2.758-1.379l-.749 2.848c-.269 1.045-1.004 2.352-1.498 3.146 1.123.345 2.306.535 3.55.535 6.607 0 11.985-5.365 11.985-11.987C23.97 5.39 18.592.026 11.985.026L12.017 0z"/></svg>`
},
{
url:`https://telegram.me/share/url?url=${url}&text=${description}`,
icon: `<svg class="dark:fill-white h-[1.2rem] w-[1.2rem]" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Telegram</title><path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/></svg>`
},
{
url:`https://api.whatsapp.com/send?text=Olha que legal esse conteúdo que vi blog do Maykão! ${description} ${url}`,
icon: `<svg class="dark:fill-white h-[1.2rem] w-[1.2rem]" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>WhatsApp</title><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z"/></svg>`
},
{
url:`https://www.reddit.com/submit?url=${encoded_url}&title=${title}`,
icon: `<svg class="dark:fill-white h-[1.2rem] w-[1.2rem]" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Reddit</title><path d="M12 0C5.373 0 0 5.373 0 12c0 3.314 1.343 6.314 3.515 8.485l-2.286 2.286C.775 23.225 1.097 24 1.738 24H12c6.627 0 12-5.373 12-12S18.627 0 12 0Zm4.388 3.199c1.104 0 1.999.895 1.999 1.999 0 1.105-.895 2-1.999 2-.946 0-1.739-.657-1.947-1.539v.002c-1.147.162-2.032 1.15-2.032 2.341v.007c1.776.067 3.4.567 4.686 1.363.473-.363 1.064-.58 1.707-.58 1.547 0 2.802 1.254 2.802 2.802 0 1.117-.655 2.081-1.601 2.531-.088 3.256-3.637 5.876-7.997 5.876-4.361 0-7.905-2.617-7.998-5.87-.954-.447-1.614-1.415-1.614-2.538 0-1.548 1.255-2.802 2.803-2.802.645 0 1.239.218 1.712.585 1.275-.79 2.881-1.291 4.64-1.365v-.01c0-1.663 1.263-3.034 2.88-3.207.188-.911.993-1.595 1.959-1.595Zm-8.085 8.376c-.784 0-1.459.78-1.506 1.797-.047 1.016.64 1.429 1.426 1.429.786 0 1.371-.369 1.418-1.385.047-1.017-.553-1.841-1.338-1.841Zm7.406 0c-.786 0-1.385.824-1.338 1.841.047 1.017.634 1.385 1.418 1.385.785 0 1.473-.413 1.426-1.429-.046-1.017-.721-1.797-1.506-1.797Zm-3.703 4.013c-.974 0-1.907.048-2.77.135-.147.015-.241.168-.183.305.483 1.154 1.622 1.964 2.953 1.964 1.33 0 2.47-.81 2.953-1.964.057-.137-.037-.29-.184-.305-.863-.087-1.795-.135-2.769-.135Z"/></svg>`
}
]
---
<div class="w-full border-top border border-xs mt-16"></div>
<h4 class="mt-4 font-bold text-xl">
Gostou? Compartilhe esse conteúdo!
</h4>
<div class=`flex gap-2 mt-6`>
{
buttons.map(({url, icon}) => (
<a class="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 w-10"
href={url} rel="noopener noreferrer" target="_blank">
<span set:html={icon} />
</a>
))
}
</div>
Para usar, eu posso chamar ele em alguma página .astro
e passar os atributos necessários
---
import SocialShare from "@/components/SocialShare.astro";
const title = 'Meu artigo'
const description = 'Alguma descrição sobre este artigo'
const image = '/alguma-imagem-da-minha-pasta-public-aqui.webp'
---
<SocialShare
title={title}
description={description}
image={image}
/>
Agora, ao final desse artigo temos os nossos links para compartilhamento de posts de blog nas redes sociais. 🎉

📚 Referências
- https://mckerlie.com/posts/improving-the-sharing-experience-in-astro
- https://simpleicons.org/
- https://svgl.vercel.app/
- https://properprogramming.com/blog/create-39-social-network-share-link-generator-and-guide-2023/
- https://stackoverflow.com/questions/57628890/why-people-use-rel-noopener-noreferrer-instead-of-just-rel-noreferrer