Files
Portfolio-Codex/docs/stories/5.7.liens-contact-secondaires.md

7.8 KiB

Story 5.7: Liens de Contact Secondaires

Status

Ready for Dev

Story

As a visiteur, I want avoir des alternatives au formulaire pour contacter le développeur, so that je choisis le canal qui me convient.

Acceptance Criteria

  1. Sous le formulaire, une section affiche les liens secondaires : LinkedIn, GitHub, email direct (mailto)
  2. Les liens sont affichés avec leurs icônes respectives
  3. Les liens s'ouvrent dans un nouvel onglet (sauf mailto)
  4. La section est visuellement distincte mais cohérente avec le formulaire
  5. L'adresse email est protégée contre le scraping (encodage ou JS)

Tasks / Subtasks

  • [] Task 1 : Ajouter la section dans contact.php (AC: 1, 4)

    • [] Titre "Retrouvez-moi aussi sur"
    • [] Positionnement sous le formulaire (mt-16, pt-8, border-t)
    • [] Style distinct mais cohérent (bg-surface-alt, border)
  • [] Task 2 : Ajouter les liens avec icônes (AC: 2)

    • [] LinkedIn avec icône SVG (#0A66C2)
    • [] GitHub avec icône SVG
    • [] Email avec icône SVG (primary)
  • [] Task 3 : Configurer les liens (AC: 3)

    • [] target="_blank" + rel="noopener noreferrer" pour LinkedIn/GitHub
    • [] mailto: généré par JS pour l'email
  • [] Task 4 : Protéger l'email (AC: 5)

    • [] data-user et data-domain dans le HTML
    • [] initEmailProtection() dans main.js
    • [] Reconstruction du mailto au chargement

Dev Notes

Section à ajouter dans contact.php

<!-- Sous le formulaire et les messages de feedback -->

<!-- Liens secondaires -->
<section class="mt-16 pt-8 border-t border-border">
    <h2 class="text-lg font-semibold text-center mb-6">Retrouvez-moi aussi sur</h2>

    <div class="flex flex-wrap justify-center gap-6">
        <!-- LinkedIn -->
        <a
            href="https://linkedin.com/in/votre-profil"
            target="_blank"
            rel="noopener"
            class="flex items-center gap-3 px-6 py-3 bg-surface rounded-lg hover:bg-surface-light transition-colors group"
            aria-label="Profil LinkedIn"
        >
            <svg class="w-6 h-6 text-[#0A66C2]" fill="currentColor" viewBox="0 0 24 24">
                <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>
            <span class="font-medium text-text-primary group-hover:text-primary transition-colors">LinkedIn</span>
        </a>

        <!-- GitHub -->
        <a
            href="https://github.com/votre-username"
            target="_blank"
            rel="noopener"
            class="flex items-center gap-3 px-6 py-3 bg-surface rounded-lg hover:bg-surface-light transition-colors group"
            aria-label="Profil GitHub"
        >
            <svg class="w-6 h-6 text-text-primary" fill="currentColor" viewBox="0 0 24 24">
                <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
            </svg>
            <span class="font-medium text-text-primary group-hover:text-primary transition-colors">GitHub</span>
        </a>

        <!-- Email (protégé) -->
        <a
            href="#"
            id="email-link"
            class="flex items-center gap-3 px-6 py-3 bg-surface rounded-lg hover:bg-surface-light transition-colors group"
            aria-label="Envoyer un email"
            data-user="contact"
            data-domain="monportfolio.fr"
        >
            <svg class="w-6 h-6 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
            </svg>
            <span class="font-medium text-text-primary group-hover:text-primary transition-colors">Email</span>
        </a>
    </div>
</section>

Protection de l'Email (JavaScript)

// assets/js/main.js (ajouter)

/**
 * Protection de l'email contre le scraping
 * Reconstruit l'adresse email à partir de data-attributes
 */
function initEmailProtection() {
    const emailLink = document.getElementById('email-link');
    if (!emailLink) return;

    const user = emailLink.dataset.user;
    const domain = emailLink.dataset.domain;

    if (user && domain) {
        const email = `${user}@${domain}`;
        emailLink.href = `mailto:${email}`;

        // Optionnel : afficher l'email au hover
        emailLink.title = email;
    }
}

document.addEventListener('DOMContentLoaded', () => {
    initEmailProtection();
});

Alternative : Encodage HTML

<?php
/**
 * Encode une adresse email en entités HTML
 */
function encodeEmail(string $email): string
{
    $encoded = '';
    for ($i = 0; $i < strlen($email); $i++) {
        $encoded .= '&#' . ord($email[$i]) . ';';
    }
    return $encoded;
}

$email = 'contact@monportfolio.fr';
$encodedEmail = encodeEmail($email);
?>

<a href="mailto:<?= $encodedEmail ?>">
    <?= $encodedEmail ?>
</a>

Liens à Configurer

Plateforme URL Notes
LinkedIn https://linkedin.com/in/votre-profil Profil public
GitHub https://github.com/votre-username Profil public
Email contact@monportfolio.fr Via .env ou config

Couleurs des Icônes

Plateforme Couleur Tailwind
LinkedIn #0A66C2 text-[#0A66C2]
GitHub Inherit (blanc) text-text-primary
Email Primary text-primary

Testing

  • [] Les 3 liens sont affichés avec leurs icônes
  • [] LinkedIn et GitHub s'ouvrent dans un nouvel onglet
  • [] Le lien mailto déclenche le client email
  • [] L'email n'apparaît pas en clair dans le HTML source (data-attributes)
  • [] Le JS reconstruit correctement le lien mailto
  • [] Les hover states fonctionnent (border-primary/50)
  • [] La section est visuellement distincte (border-t, mt-16)

Dev Agent Record

Agent Model Used

Claude Opus 4.5 (claude-opus-4-5-20251101)

File List

File Action Description
pages/contact.php Modified Section liens secondaires (LinkedIn, GitHub, Email)
assets/js/main.js Modified Ajout initEmailProtection()

Completion Notes

  • Section "Retrouvez-moi aussi sur" avec 3 liens
  • LinkedIn : https://linkedin.com/in/celian-music (à personnaliser)
  • GitHub : https://github.com/skycel
  • Email protégé : data-user/data-domain + reconstruction JS
  • Icônes SVG avec couleurs appropriées (LinkedIn bleu, GitHub inherit, Email primary)
  • Hover state : border-primary/50
  • target="_blank" + rel="noopener noreferrer" pour les liens externes

Debug Log References

Aucun problème rencontré.

Change Log

Date Version Description Author
2026-01-22 0.1 Création initiale Sarah (PO)
2026-01-24 1.0 Implémentation complète James (Dev)