Feat: header article avec date + boutons de partage, share section bas de page, golden-grid conditionnel
All checks were successful
Deploy / Deploy to Production (push) Successful in 18s
All checks were successful
Deploy / Deploy to Production (push) Successful in 18s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b9631b8c53
commit
3c5b4f76dd
10 changed files with 178 additions and 28 deletions
|
|
@ -28,8 +28,16 @@ async function loadSlide(path) {
|
|||
// Sub-page: resolve to parent slide (ex: /blog/slug → /blog)
|
||||
if (idx === -1) {
|
||||
const parentPath = path.replace(/\/[^/]+$/, "");
|
||||
idx = slides.getIndexByPath(parentPath);
|
||||
if (idx !== -1) slidePath = parentPath;
|
||||
if (parentPath && parentPath !== path) {
|
||||
const parentIdx = slides.getIndexByPath(parentPath);
|
||||
if (parentIdx !== -1) {
|
||||
idx = parentIdx;
|
||||
slidePath = parentPath;
|
||||
} else if (!siteInitialized) {
|
||||
// Slides not yet initialized — assume sub-page, fetch parent to bootstrap
|
||||
slidePath = parentPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (idx !== -1) {
|
||||
|
|
|
|||
|
|
@ -4,14 +4,48 @@
|
|||
* Reçoit les données article via props, pas via le slide system.
|
||||
*/
|
||||
let { data, onBack } = $props()
|
||||
|
||||
let copySuccess = $state(false)
|
||||
let copyTimer = null
|
||||
|
||||
function copyLink() {
|
||||
navigator.clipboard.writeText(window.location.href)
|
||||
copySuccess = true
|
||||
clearTimeout(copyTimer)
|
||||
copyTimer = setTimeout(() => { copySuccess = false }, 2000)
|
||||
}
|
||||
|
||||
const shareUrl = $derived(encodeURIComponent(window.location.href))
|
||||
</script>
|
||||
|
||||
<article class="article">
|
||||
|
||||
<!-- Date + retour -->
|
||||
<!-- Date + share buttons -->
|
||||
<div class="article-topbar">
|
||||
<time class="article-date">{data.date}</time>
|
||||
<button class="article-back" onclick={onBack}>← Retour</button>
|
||||
<time class="article-date">Publié le {data.published}</time>
|
||||
<div class="article-share">
|
||||
{#if copySuccess}
|
||||
<span class="copy-toast">Lien copié !</span>
|
||||
{/if}
|
||||
<div class="share-buttons">
|
||||
<!-- svelte-ignore a11y_invalid_attribute -->
|
||||
<a href="#" class="share-button" title="Copier le lien" onclick={(e) => { e.preventDefault(); copyLink() }}>
|
||||
<img src="/assets/icons/link-icon.svg" alt="Copier le lien" width="20" height="20" />
|
||||
</a>
|
||||
<a href="https://api.whatsapp.com/send?text={shareUrl}" target="_blank" rel="noopener noreferrer" class="share-button">
|
||||
<img src="/assets/icons/whatsapp-icon.svg" alt="Partager sur WhatsApp" width="20" height="20" />
|
||||
</a>
|
||||
<a href="https://twitter.com/intent/tweet?url={shareUrl}" target="_blank" rel="noopener noreferrer" class="share-button">
|
||||
<img src="/assets/icons/twitter-icon.svg" alt="Partager sur X" width="20" height="20" />
|
||||
</a>
|
||||
<a href="https://www.facebook.com/sharer/sharer.php?u={shareUrl}" target="_blank" rel="noopener noreferrer" class="share-button">
|
||||
<img src="/assets/icons/facebook-icon.svg" alt="Partager sur Facebook" width="20" height="20" />
|
||||
</a>
|
||||
<a href="https://www.linkedin.com/sharing/share-offsite/?url={shareUrl}" target="_blank" rel="noopener noreferrer" class="share-button">
|
||||
<img src="/assets/icons/linkedin-icon.svg" alt="Partager sur LinkedIn" width="20" height="20" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Titre -->
|
||||
|
|
@ -34,6 +68,30 @@
|
|||
<div class="article-body">{@html data.body}</div>
|
||||
{/if}
|
||||
|
||||
<!-- Share section (bas d'article) -->
|
||||
<div class="article-share-section">
|
||||
<hr class="share-divider" />
|
||||
<p class="share-label">Partager cet article</p>
|
||||
<div class="share-buttons">
|
||||
<!-- svelte-ignore a11y_invalid_attribute -->
|
||||
<a href="#" class="share-button" title="Copier le lien" onclick={(e) => { e.preventDefault(); copyLink() }}>
|
||||
<img src="/assets/icons/link-icon.svg" alt="Copier le lien" width="20" height="20" />
|
||||
</a>
|
||||
<a href="https://api.whatsapp.com/send?text={shareUrl}" target="_blank" rel="noopener noreferrer" class="share-button">
|
||||
<img src="/assets/icons/whatsapp-icon.svg" alt="Partager sur WhatsApp" width="20" height="20" />
|
||||
</a>
|
||||
<a href="https://twitter.com/intent/tweet?url={shareUrl}" target="_blank" rel="noopener noreferrer" class="share-button">
|
||||
<img src="/assets/icons/twitter-icon.svg" alt="Partager sur X" width="20" height="20" />
|
||||
</a>
|
||||
<a href="https://www.facebook.com/sharer/sharer.php?u={shareUrl}" target="_blank" rel="noopener noreferrer" class="share-button">
|
||||
<img src="/assets/icons/facebook-icon.svg" alt="Partager sur Facebook" width="20" height="20" />
|
||||
</a>
|
||||
<a href="https://www.linkedin.com/sharing/share-offsite/?url={shareUrl}" target="_blank" rel="noopener noreferrer" class="share-button">
|
||||
<img src="/assets/icons/linkedin-icon.svg" alt="Partager sur LinkedIn" width="20" height="20" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Articles recommandés -->
|
||||
{#if data.related?.length}
|
||||
<section class="article-related">
|
||||
|
|
@ -55,9 +113,8 @@
|
|||
|
||||
<style>
|
||||
.article {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
padding: 4rem 2rem 6rem;
|
||||
grid-area: 6 / 1 / span 10 / span 20;
|
||||
padding: 0 20%;
|
||||
}
|
||||
|
||||
/* --- Topbar --- */
|
||||
|
|
@ -73,37 +130,84 @@
|
|||
font-size: var(--font-size-paragraph);
|
||||
}
|
||||
|
||||
.article-back {
|
||||
background: none;
|
||||
color: var(--color-primary);
|
||||
font-family: "Danzza Medium", sans-serif;
|
||||
font-size: var(--font-size-paragraph-small);
|
||||
cursor: pointer;
|
||||
/* --- Share (topbar) --- */
|
||||
.article-share {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.share-buttons {
|
||||
display: flex;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.share-button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 0.8;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.article-back:hover {
|
||||
opacity: 0.7;
|
||||
.share-button:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.copy-toast {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -36px;
|
||||
background: var(--color-primary);
|
||||
color: #1e1938;
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* --- Share section (bas d'article) --- */
|
||||
.article-share-section {
|
||||
margin: 3rem 0 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.share-divider {
|
||||
border: none;
|
||||
border-top: 1px solid white;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.share-label {
|
||||
font-family: "Danzza Bold", sans-serif;
|
||||
font-size: 16px;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.article-share-section .share-buttons {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* --- Titre --- */
|
||||
.article-title {
|
||||
font-size: var(--font-size-title-main);
|
||||
font-size: var(--font-size-title-section);
|
||||
font-weight: 700;
|
||||
font-family: "Danzza", sans-serif;
|
||||
text-align: center;
|
||||
margin-bottom: 1.5rem;
|
||||
line-height: 1.2;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
/* --- Intro --- */
|
||||
.article-intro {
|
||||
text-align: center;
|
||||
font-size: var(--font-size-subtitle);
|
||||
line-height: 1.6;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-size: var(--font-size-paragraph);
|
||||
line-height: 1.5;
|
||||
color: hsla(0,0%,100%,.9);
|
||||
margin-bottom: 2.5rem;
|
||||
max-width: 700px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
/* --- Cover --- */
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@
|
|||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<section
|
||||
class="blog page-scrollable"
|
||||
class:golden-grid={!!articleData}
|
||||
bind:this={sectionEl}
|
||||
onclick={handleClick}
|
||||
>
|
||||
|
|
@ -120,7 +121,7 @@
|
|||
{#if featured}
|
||||
<article class="blog-card blog-card--featured">
|
||||
<div class="blog-card-text">
|
||||
<time class="blog-card-date">{featured.date}</time>
|
||||
<time class="blog-card-date">{featured.published}</time>
|
||||
<h2 class="blog-card-title">
|
||||
<a href="/blog/{featured.slug}">{featured.title}</a>
|
||||
</h2>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue