Skip to content

Latest commit

 

History

History
440 lines (391 loc) · 15.1 KB

File metadata and controls

440 lines (391 loc) · 15.1 KB
layout default
title Brag Document
<style> .project-card__header-flex { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.5rem; } .project-card__header-flex h3 { margin-bottom: 0; /* Override default to let flexbox handle spacing */ } .filters-wrapper { position: sticky; top: 1rem; z-index: 100; max-width: 1100px; margin: 0 auto 2rem auto; box-sizing: border-box; background: var(--glass-bg); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid var(--glass-border); border-radius: 12px; padding: 0.8rem 2rem; /* Aligné sur les sections */ box-shadow: 0 10px 30px rgba(0,0,0,0.5); display: flex; flex-direction: column; gap: 0.6rem; } .brag-filters { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin: 0 !important; justify-content: flex-start; } .brag-filters span { font-size: 0.75rem; font-weight: 700; color: var(--color-foreground); margin-right: 0.5rem; text-transform: uppercase; letter-spacing: 0.5px; opacity: 0.8; } .filter-btn { background: rgba(255,255,255,0.05); color: var(--color-foreground); border: 1px solid rgba(255,255,255,0.1); padding: 0.2rem 0.6rem; border-radius: 12px; cursor: pointer; transition: all var(--motion-fast); font-weight: 600; font-size: 0.75rem; display: inline-flex; align-items: center; gap: 0.3rem; } .filter-btn:hover { background: rgba(255,255,255,0.1); border-color: var(--glass-border-strong); } .filter-btn.active { background: var(--color-primary); color: var(--color-dark); border-color: var(--color-primary); } .tag-filter-btn.active { background: rgba(255, 167, 38, 0.2); color: #ffca28; border-color: rgba(255, 167, 38, 0.5); } .project-card { transition: opacity 300ms ease, filter 300ms ease, transform 300ms ease; } .filtered-out { opacity: 0.35; filter: grayscale(100%); pointer-events: none; } /* Collapse content to reduce scroll for filtered items */ .filtered-out p, .filtered-out .project-card__tags, .filtered-out .project-card__link, .filtered-out .talk-card__tags { display: none !important; } .filtered-out .project-card__impact { margin-bottom: 0; } .filtered-out .talk-card__body { padding-bottom: 0.5rem; } .tag-filter-btn.active { background: rgba(255, 167, 38, 0.15); color: #ffca28; border-color: rgba(255, 167, 38, 0.5); box-shadow: 0 0 15px rgba(255, 167, 38, 0.2); } .year-separator { width: 100%; font-size: 2rem; color: var(--color-primary); font-weight: 900; margin: 3rem 0 1.5rem 0; padding-left: 1.2rem; border-left: 5px solid var(--color-primary); text-shadow: 0 2px 10px rgba(36, 181, 255, 0.2); } /* ── Ongoing / En cours ──────────────────────────── */ .project-card--ongoing { border: 1px solid rgba(76, 175, 80, 0.4); box-shadow: 0 0 20px rgba(76, 175, 80, 0.12), inset 0 0 30px rgba(76, 175, 80, 0.04); } .badge-ongoing { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.6px; color: #81c784; background: rgba(76, 175, 80, 0.15); border: 1px solid rgba(76, 175, 80, 0.35); border-radius: 20px; padding: 0.15rem 0.65rem; vertical-align: middle; margin-left: 0.5rem; animation: ongoing-pulse 2.5s ease-in-out infinite; } @keyframes ongoing-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } } </style>

Réalisations & Impact

Brag Document

Une synthèse de mes réalisations les plus significatives, de l'architecture à l'open source, illustrant mon évolution et mon impact sur l'écosystème tech.

Impact : Tous Distinguished Principal Staff Tech Lead Senior Software Engineer

Impact produit & technique

Projets majeurs

Réalisations ayant eu un impact significatif sur les produits, les équipes ou les organisations.

{% assign projects_sorted = site.data.brag.projects | sort: "sort_key" | reverse %} {% assign current_year = '' %} {% for project in projects_sorted %} {% assign project_year = project.sort_key | divided_by: 10000 %} {% if project_year != current_year %}

{{ project_year }}

{% assign current_year = project_year %} {% endif %} {% include brag-project-card.html project=project %} {% endfor %}

Open Source & Communauté

Contributions open source

Projets publiés, contributions à l'écosystème et engagement dans la communauté .NET.

{% assign opensource_sorted = site.data.brag.opensource | sort: "sort_key" | reverse %} {% assign current_year = '' %} {% for item in opensource_sorted %} {% assign item_year = item.sort_key | divided_by: 10000 %} {% if item_year != current_year %}

{{ item_year }}

{% assign current_year = item_year %} {% endif %} {% include brag-project-card.html project=item %} {% endfor %}

Conférences & Partage

Talks & Publications

Présentations en meetups, conférences et contenus publiés pour la communauté.

{% assign talks_sorted = site.data.talks | sort: "sort_key" | reverse %} {% for talk in talks_sorted %}

{{ talk.title }}

{{ talk.meta }}

{{ talk.description }}

{% if talk.report_url %}

Retour d'expérience (LinkedIn)

{% endif %}
{{ talk.category }} {% for t in talk.tags %}{{ t }}{% endfor %}
{% endfor %}

Impact humain & organisationnel

Mentoring & Leadership

Accompagnement des équipes, transmission de compétences et animation de la culture technique.

{% for item in site.data.brag.mentoring %}

{{ item.title }}

{% for paragraph in item.paragraphs %}

{{ paragraph }}

{% endfor %}
{% endfor %}
<script> document.addEventListener("DOMContentLoaded", () => { const impactButtons = document.querySelectorAll(".impact-filters .filter-btn"); const tagContainer = document.getElementById("tag-filters-container"); const cards = document.querySelectorAll(".project-card, .talk-card"); const separators = document.querySelectorAll(".year-separator"); let currentImpact = "all"; let currentTag = "all"; // 0. Auto-hide empty impact filters const impactCounts = {}; cards.forEach(card => { if (card.classList.contains("project-card")) { const type = card.dataset.impactType; if (type) impactCounts[type] = (impactCounts[type] || 0) + 1; } }); impactButtons.forEach(btn => { const filter = btn.dataset.filter; if (filter !== "all" && !impactCounts[filter]) { btn.style.display = "none"; } }); // 1. Gather tags const tagCounts = {}; cards.forEach(card => { const orangeTags = card.querySelectorAll(".tag--orange"); orangeTags.forEach(t => { const label = t.textContent.trim(); tagCounts[label] = (tagCounts[label] || 0) + 1; }); }); // 2. Build tag buttons let tagHtml = ` Tags :`; tagHtml += `Tous`; // Sort tags by frequency descending const sortedTags = Object.entries(tagCounts).sort((a,b) => b[1] - a[1]); sortedTags.forEach(([tag, count]) => { tagHtml += `${tag} (${count})`; }); tagContainer.innerHTML = tagHtml; const tagButtons = document.querySelectorAll(".tag-filter-btn"); // 3. Central update function function updateFilters() { cards.forEach(card => { // Impact logic (only applies to project-card, talks are not impacted by impact filter right now) // wait, talks don't have impact, so they pass impact filter if we want them to stay... // let's say "principal/staff" filter ONLY hides non-matching project-cards. It hides talks too? // "Vraiment, filtering by Staff means only staff things." so let's hide talks if impact is specific. const isProjectCard = card.classList.contains("project-card"); const impactType = card.dataset.impactType || ""; let passesImpact = true; if (currentImpact !== "all") { if (isProjectCard) { passesImpact = (impactType === currentImpact); } else { // It's a talk card, it has no impact. Hide it if an impact is selected? Yes. passesImpact = false; } } // Tag logic let passesTag = true; if (currentTag !== "all") { const myTags = Array.from(card.querySelectorAll(".tag--orange")).map(t => t.textContent.trim()); passesTag = myTags.includes(currentTag); } if (passesImpact && passesTag) { card.classList.remove("filtered-out"); } else { card.classList.add("filtered-out"); } }); // Update Year Separators (only applies to where they are used: projects & opensource) separators.forEach(sep => { let nextEl = sep.nextElementSibling; let hasVisibleCards = false; while(nextEl && !nextEl.classList.contains("year-separator") && !nextEl.classList.contains("section__header")) { if (nextEl.classList.contains("project-card") && !nextEl.classList.contains("filtered-out")) { hasVisibleCards = true; break; } nextEl = nextEl.nextElementSibling; } sep.style.opacity = hasVisibleCards ? "1" : "0.35"; sep.style.display = "block"; // reset display in case it was "none" }); if (currentImpact !== "all" || currentTag !== "all") { setTimeout(() => { const firstActive = document.querySelector('.project-card:not(.filtered-out), .talk-card:not(.filtered-out)'); if (firstActive) { const wrapper = document.querySelector('.filters-wrapper'); const offset = (wrapper ? wrapper.offsetHeight : 100) + 20; // espace pour la barre sticky // Vérifie si on a un year-separator juste au-dessus let target = firstActive; const prev = firstActive.previousElementSibling; if (prev && prev.classList.contains("year-separator") && prev.style.opacity === "1") { target = prev; // on scroll au séparateur d'année c'est plus propre } const topPos = target.getBoundingClientRect().top + window.scrollY - offset; window.scrollTo({ top: topPos, behavior: "smooth" }); } }, 50); // léger délai pour laisser le layout se resserrer avec les display:none } } // 4. Attach Events impactButtons.forEach(btn => { btn.addEventListener("click", () => { impactButtons.forEach(b => b.classList.remove("active")); btn.classList.add("active"); currentImpact = btn.dataset.filter; updateFilters(); }); }); tagButtons.forEach(btn => { btn.addEventListener("click", () => { tagButtons.forEach(b => b.classList.remove("active")); btn.classList.add("active"); currentTag = btn.dataset.tag; updateFilters(); }); }); }); </script>