diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8806ef3..69cf609 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,14 @@ Format : [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/) — versionnag
---
+## [1.6.20] - 2026-05-16
+
+### Ajouté
+- Barre de partage sur les articles publiés : mail, X, LinkedIn, Mastodon, copie de lien, Web Share API mobile (#47)
+- Déduplication des images uploadées par hardlink si même hash+taille existe déjà dans un autre article (#35)
+
+---
+
## [1.6.19] - 2026-05-16
### Ajouté
diff --git a/public/assets/js/share.js b/public/assets/js/share.js
new file mode 100644
index 0000000..1ec196c
--- /dev/null
+++ b/public/assets/js/share.js
@@ -0,0 +1,40 @@
+(function () {
+ 'use strict';
+
+ var bar = document.getElementById('share-bar');
+ if (!bar) { return; }
+
+ var url = bar.getAttribute('data-url') || window.location.href;
+ var title = bar.getAttribute('data-title') || document.title;
+
+ var copyBtn = document.getElementById('share-copy');
+ if (copyBtn) {
+ copyBtn.addEventListener('click', function () {
+ if (!navigator.clipboard) {
+ var ta = document.createElement('textarea');
+ ta.value = url;
+ document.body.appendChild(ta);
+ ta.select();
+ document.execCommand('copy');
+ document.body.removeChild(ta);
+ copyBtn.textContent = 'Copié !';
+ setTimeout(function () { copyBtn.textContent = 'Copier le lien'; }, 2000);
+ return;
+ }
+ navigator.clipboard.writeText(url).then(function () {
+ copyBtn.textContent = 'Copié !';
+ setTimeout(function () { copyBtn.textContent = 'Copier le lien'; }, 2000);
+ });
+ });
+ }
+
+ var nativeBtn = document.getElementById('share-native');
+ if (nativeBtn) {
+ if (navigator.share) {
+ nativeBtn.hidden = false;
+ nativeBtn.addEventListener('click', function () {
+ navigator.share({ title: title, url: url }).catch(function () {});
+ });
+ }
+ }
+}());
diff --git a/public/version.txt b/public/version.txt
index e55f803..c45801e 100644
--- a/public/version.txt
+++ b/public/version.txt
@@ -1 +1 @@
-1.6.19
+1.6.20
diff --git a/src/ArticleManager.php b/src/ArticleManager.php
index 9946ab9..405fd11 100644
--- a/src/ArticleManager.php
+++ b/src/ArticleManager.php
@@ -1197,7 +1197,16 @@ class ArticleManager
$size = filesize($uploadedFile['tmp_name']);
$name = "{$hash}-{$size}.{$ext}";
$dest = $dir . '/' . $name;
- if (!rename($uploadedFile['tmp_name'], $dest) && !move_uploaded_file($uploadedFile['tmp_name'], $dest)) {
+ // Déduplication : si ce fichier identique existe déjà dans un autre article, crée un hardlink
+ if (!file_exists($dest)) {
+ $existing = glob($this->dataDir . '/*/files/' . $name);
+ if (!empty($existing) && is_file($existing[0])) {
+ link($existing[0], $dest) || copy($existing[0], $dest);
+ @unlink($uploadedFile['tmp_name']);
+ return $name;
+ }
+ }
+ if (!file_exists($dest) && !rename($uploadedFile['tmp_name'], $dest) && !move_uploaded_file($uploadedFile['tmp_name'], $dest)) {
return null;
}
return $name;
diff --git a/templates/layout.php b/templates/layout.php
index 23abc9c..b50cc95 100644
--- a/templates/layout.php
+++ b/templates/layout.php
@@ -163,6 +163,9 @@ $_layoutCurrentCat = trim($_GET['cat'] ?? '');
+
+
+