Pular para o conteúdo
He4rt / Docs
Toggle sidebar
Interno noindex

Referência técnica — acessível, mas fora dos buscadores.

Discord
Engenharia Leitura · 6 min 20/06/2026 documento interno · noindex

Página de redes sociais (link-tree) — `portal`

Artefato de planejamento de 20/06/2026 — pode não refletir o estado atual do código.

1. Contexto

A He4rt precisa de uma página link-tree que reúna seus links de rede social num único endereço fácil de divulgar (heartdevs.com/redes). A página reaproveita a linha de batimento (ECG) animada que hoje existe na capa do deck de retrospectiva (app-modules/portal/resources/views/components/retro/slides/cover.blade.php), dando identidade visual coerente com o resto do portal.

Tudo vive no módulo portal, seguindo o padrão de página Livewire full-page já usado em Homepage e CommunityRetrospectivePage (rota registrada no PortalServiceProvider, #[Layout] + #[Title], render() retorna uma view portal::...).

Rede URL Ícone
Discord https://discord.gg/invite/he4rt fab-discord
X (Twitter) https://x.com/He4rtDevs fab-x-twitter
LinkedIn https://www.linkedin.com/company/he4rt/ fab-linkedin
WhatsApp https://chat.whatsapp.com/EBKjYxIodpe1x5LLExbTzK fab-whatsapp
GitHub https://github.com/he4rt fab-github
Site https://heartdevs.com/ fas-globe

Os ícones de marca vêm de owenvoke/blade-fontawesome (já instalado; a navbar já usa fab-discord).

Escolhido: array tipado de DTO SocialLink exposto pelo componente Livewire.

São 6 links estáticos que mudam raramente; banco de dados ou config seria over-engineering (YAGNI). Um final readonly class SocialLink mantém a blade limpa, é testável e segue a convenção do projeto (DTO em vez de array associativo). Se um dia for preciso editar pelo painel, a migração para config/DB é local e não quebra a interface da página.

Descartado:

3. Estrutura de arquivos

app-modules/portal/
├── src/
│   ├── DTOs/
│   │   └── SocialLink.php              (NOVO)
│   ├── Livewire/
│   │   └── SocialLinksPage.php         (NOVO)
│   └── PortalServiceProvider.php       (EDIT — registra a rota)
├── resources/views/
│   └── social-links.blade.php          (NOVO)
└── tests/Feature/
    └── SocialLinksPageTest.php          (NOVO)

app-modules/portal/src/DTOs/SocialLink.php, namespace He4rt\Portal\DTOs.

final readonly class SocialLink
{
    public function __construct(
        public string $label,
        public string $url,
        public string $icon, // ex.: 'fab-discord'
        public string $accent,
    ) {
        // classe/cor de destaque no hover
    }
}

3.2 Componente SocialLinksPage

app-modules/portal/src/Livewire/SocialLinksPage.php, namespace He4rt\Portal\Livewire. Espelha o padrão de Homepage:

#[Layout('portal::components.layouts.app')]
#[Title('Nossas redes')]
final class SocialLinksPage extends Component
{
    /** @return list<SocialLink> */
    public function links(): array
    {
        return [
                /* os 6 SocialLink */
            ];
    }

    public function render(): View
    {
        return view('portal::social-links');
    }
}

A blade lê os links via $this->links().

3.3 Rota (PortalServiceProvider::boot())

Route::get('/redes', SocialLinksPage::class)->name('social-links');

3.4 View social-links.blade.php

Único elemento raiz (<div>) por exigência do Livewire. Estrutura: logo He4rt (x-he4rt::logo ou x-portal::logo) + tagline + linha ECG animada + stack vertical de links centralizado (max-w-[480px]), botões full-width com ícone de marca, label e seta; accent da marca no hover. Cada link abre em nova aba (target="_blank" rel="noopener noreferrer").

A implementação visual usa as skills /frontend-design e /tailwindcss-development, reaproveitando componentes/cores do design system he4rt.

4. Reaproveitamento da ECG

A ECG da capa (cover.blade.php) tem a animação acoplada a .retro .slide.active no retrospective.css. Para usá-la fora do deck, copiamos somente o markup do <svg> e definimos uma animação própria, scoped e inline na página, que dispara no carregamento (não depende de .slide.active). Isso mantém a feature autocontida — sem alterar o layout compartilhado nem o retrospective.css.

Antes (cover.blade.php):

<svg class="ecg" viewBox="0 0 560 60" preserveAspectRatio="none" data-anim aria-hidden="true">
    <path
        d="M0 34 H210 l10 0 l8 -7 l11 14 l13 -34 l15 50 l11 -22 l9 0 H340 l9 0 l8 -6 l9 12 l12 -28 l13 40 l10 -16 l8 0 H560"
    />
</svg>

Depois (social-links.blade.php):

<svg class="links-ecg" viewBox="0 0 560 60" preserveAspectRatio="none" aria-hidden="true">
    <path
        d="M0 34 H210 l10 0 l8 -7 l11 14 l13 -34 l15 50 l11 -22 l9 0 H340 l9 0 l8 -6 l9 12 l12 -28 l13 40 l10 -16 l8 0 H560"
    />
</svg>
<style>
    .links-ecg {
        width: 100%;
        max-width: 560px;
        height: 60px;
        display: block;
        margin: 14px auto 6px;
    }
    .links-ecg path {
        fill: none;
        stroke: var(--primary);
        stroke-width: 2.4;
        stroke-linecap: round;
        stroke-linejoin: round;
        filter: drop-shadow(0 0 7px rgba(120, 43, 241, 0.85));
        stroke-dasharray: 1500;
        stroke-dashoffset: 1500;
        animation: links-ecg-draw 1.8s 0.3s ease-out forwards;
    }
    @keyframes links-ecg-draw {
        to {
            stroke-dashoffset: 0;
        }
    }
</style>

A cor da linha usa a variável de tema (--primary/--brand); confirmar qual está disponível no theme.css durante a implementação e usar fallback.

5. Comportamento esperado (BDD)

Cenário: visitante acessa a página de redes
  Dado que acesso GET /redes
  Então recebo 200 e vejo o logo He4rt e a linha de batimento (ECG)
  E vejo os 6 links, cada um com seu ícone de marca
  E cada link aponta para a URL correta e abre em nova aba (target=_blank rel=noopener noreferrer)

Cenário: animação da ECG
  Dado que a página carrega
  Então a linha de ECG se desenha uma única vez (stroke-dashoffset 1500 → 0) e para
  E não depende de .retro .slide.active do deck

Cenário: rota nomeada
  Dado o nome de rota 'social-links'
  Então route('social-links') resolve para /redes

Cenário: responsivo / acessibilidade
  Dado mobile ou desktop
  Então os botões ficam em coluna única centralizada (max-w ~480px)
  E cada link tem texto/aria legível e foco visível

6. Layout visual (ASCII)

┌───────────────────────────────┐
│           [navbar]             │  ← vem do layout app
│                                │
│          ♥ He4rt Devs          │  ← logo
│      Conecte-se com a gente    │  ← tagline
│      ╱╲    ╱╲                   │  ← linha ECG animada (desenha 1x)
│   ──╱  ╲──╱  ╲───────          │
│                                │
│  ┌─────────────────────────┐   │
│  │ (discord)  Discord    →  │   │  ← botões full-width; accent no hover
│  ├─────────────────────────┤   │
│  │ (x)        X / Twitter→  │   │
│  ├─────────────────────────┤   │
│  │ (linkedin) LinkedIn   →  │   │
│  ├─────────────────────────┤   │
│  │ (whatsapp) WhatsApp   →  │   │
│  ├─────────────────────────┤   │
│  │ (github)   GitHub     →  │   │
│  ├─────────────────────────┤   │
│  │ (globe)    Site       →  │   │
│  └─────────────────────────┘   │
└───────────────────────────────┘

7. Testes

app-modules/portal/tests/Feature/SocialLinksPageTest.php (Pest + Livewire):

8. Fora de escopo (YAGNI)