diff --git a/public/assets/css/style.css b/public/assets/css/style.css
index e1eb707..a565f6b 100644
--- a/public/assets/css/style.css
+++ b/public/assets/css/style.css
@@ -1278,14 +1278,34 @@ footer.mt-5 { margin-top: 0 !important; }
.author-profile-link:hover { color: var(--vl-accent); }
-.author-profile-bio {
+.author-bio-wrap {
flex: 1;
- margin: 0;
+}
+
+.author-profile-bio {
+ margin: 0 0 .25rem;
color: var(--vl-muted);
line-height: 1.7;
font-size: .9375rem;
}
+.author-profile-bio.bio-clamped {
+ display: -webkit-box;
+ -webkit-line-clamp: 3;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+.bio-toggle {
+ background: none;
+ border: none;
+ padding: 0;
+ color: var(--vl-accent);
+ font-size: .875rem;
+ cursor: pointer;
+ text-decoration: underline;
+}
+
/* ─── Page "Mes liens" ───────────────────── */
.liens-page {
diff --git a/public/feed.php b/public/feed.php
index 022b701..302820e 100644
--- a/public/feed.php
+++ b/public/feed.php
@@ -74,7 +74,7 @@ echo '' . "\n";
= htmlspecialchars(siteTitle()) ?>
= htmlspecialchars($base) ?>
= htmlspecialchars(siteClaim()) ?>
- fr
+ = htmlspecialchars(siteLang()) ?>
= htmlspecialchars($lastBuild) ?>
diff --git a/public/index.php b/public/index.php
index 1f05a4c..7413cc1 100644
--- a/public/index.php
+++ b/public/index.php
@@ -1770,8 +1770,13 @@ switch ($action) {
exit;
}
saveSiteSettings([
- 'site_title' => $_POST['site_title'] ?? '',
- 'site_claim' => $_POST['site_claim'] ?? '',
+ 'site_title' => $_POST['site_title'] ?? '',
+ 'site_claim' => $_POST['site_claim'] ?? '',
+ 'site_author' => $_POST['site_author'] ?? '',
+ 'site_lang' => $_POST['site_lang'] ?? '',
+ 'posts_per_page' => $_POST['posts_per_page'] ?? '',
+ 'site_license_label' => $_POST['site_license_label'] ?? '',
+ 'site_license_url' => $_POST['site_license_url'] ?? '',
]);
header('Location: /admin/site?saved=1');
exit;
@@ -2152,7 +2157,7 @@ switch ($action) {
}
return true;
}));
- $perPage = 12;
+ $perPage = postsPerPage();
$cursor = trim($_GET['cursor'] ?? '');
// Trouve la position du curseur dans la liste triée
diff --git a/src/SiteSettings.php b/src/SiteSettings.php
index 4a03b01..348b110 100644
--- a/src/SiteSettings.php
+++ b/src/SiteSettings.php
@@ -39,11 +39,36 @@ function siteAuthor(): string
return siteSettings()['site_author'] ?? '';
}
+function siteLang(): string
+{
+ return siteSettings()['site_lang'] ?? 'fr-FR';
+}
+
+function siteLangOgLocale(): string
+{
+ return str_replace('-', '_', siteLang());
+}
+
+function postsPerPage(): int
+{
+ return max(1, (int)(siteSettings()['posts_per_page'] ?? 12));
+}
+
+function siteLicenseLabel(): string
+{
+ return siteSettings()['site_license_label'] ?? 'CC BY 4.0';
+}
+
+function siteLicenseUrl(): string
+{
+ return siteSettings()['site_license_url'] ?? 'https://creativecommons.org/licenses/by/4.0/';
+}
+
function saveSiteSettings(array $data): void
{
$current = siteSettings();
- $allowed = ['site_title', 'site_claim', 'site_author'];
- foreach ($allowed as $key) {
+ $stringKeys = ['site_title', 'site_claim', 'site_author', 'site_lang', 'site_license_label', 'site_license_url'];
+ foreach ($stringKeys as $key) {
if (array_key_exists($key, $data)) {
$val = trim((string)$data[$key]);
if ($val !== '') {
@@ -51,6 +76,12 @@ function saveSiteSettings(array $data): void
}
}
}
+ if (array_key_exists('posts_per_page', $data)) {
+ $val = (int)$data['posts_per_page'];
+ if ($val > 0) {
+ $current['posts_per_page'] = $val;
+ }
+ }
file_put_contents(
siteSettingsPath(),
json_encode($current, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
diff --git a/templates/admin.php b/templates/admin.php
index 5b966e4..8970e78 100644
--- a/templates/admin.php
+++ b/templates/admin.php
@@ -360,6 +360,36 @@ function adminStatusBadge(array $a, int $now): string
maxlength="100" placeholder="ex : Cédrix">
Utilisé dans les métadonnées des articles (meta author, JSON-LD).
+
+
+
+
Format BCP 47 (ex : fr, fr-FR). Utilisé dans <html lang>, og:locale, RSS et JSON-LD.
+
+
+
+
+
+
+
+
+
+
+
+
+
Affiché dans le footer.
+
diff --git a/templates/author_profile.php b/templates/author_profile.php
index 462990e..8350454 100644
--- a/templates/author_profile.php
+++ b/templates/author_profile.php
@@ -20,9 +20,28 @@ $_initials = mb_strtoupper(mb_substr($_apName, 0, 1, 'UTF-8'), 'UTF-8');
= htmlspecialchars(parse_url($_apUrl, PHP_URL_HOST) ?: $_apUrl) ?> ↗
+ Mes liens →
- = nl2br(htmlspecialchars($_apBio)) ?>
+
+
= nl2br(htmlspecialchars($_apBio)) ?>
+
+
+
diff --git a/templates/contact.php b/templates/contact.php
index bfcfbd6..ca88305 100644
--- a/templates/contact.php
+++ b/templates/contact.php
@@ -46,13 +46,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!$error && $contactEmail !== '') {
$subjectClean = mb_encode_mimeheader(
- '[varlog contact] ' . mb_strimwidth($subject, 0, 100, '…'),
+ '[' . siteTitle() . ' contact] ' . mb_strimwidth($subject, 0, 100, '…'),
'UTF-8',
'B'
);
$nameClean = mb_encode_mimeheader($name, 'UTF-8', 'B');
- $headers = 'From: =?UTF-8?B?' . base64_encode('varlog contact') . "?= \r\n";
+ $fromEmail = $_ENV['CONTACT_FROM_EMAIL'] ?? ('noreply@' . (parse_url(APP_URL, PHP_URL_HOST) ?? 'localhost'));
+ $headers = 'From: =?UTF-8?B?' . base64_encode(siteTitle() . ' contact') . "?= <{$fromEmail}>\r\n";
$headers .= "Reply-To: {$nameClean} <{$from}>\r\n";
$headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
$headers .= "Content-Transfer-Encoding: 8bit\r\n";
diff --git a/templates/layout.php b/templates/layout.php
index b3f319e..aea13cd 100644
--- a/templates/layout.php
+++ b/templates/layout.php
@@ -1,5 +1,5 @@
-
+
= htmlspecialchars(($seoTitle ?? '') ?: ($title ?? siteTitle())) ?>
@@ -14,7 +14,7 @@
-
+
@@ -56,16 +56,16 @@
getPrivateCategories() : [];
- $_layoutCats = isset($articles) ? array_filter(
- $articles->getCategories(),
- function ($cat) use ($_layoutPrivateCats) {
- return isLoggedIn() || !in_array($cat, $_layoutPrivateCats, true);
- },
- ARRAY_FILTER_USE_KEY
- ) : [];
- $_layoutCurrentCat = trim($_GET['cat'] ?? '');
- ?>
+$_layoutPrivateCats = isset($articles) ? $articles->getPrivateCategories() : [];
+$_layoutCats = isset($articles) ? array_filter(
+ $articles->getCategories(),
+ function ($cat) use ($_layoutPrivateCats) {
+ return isLoggedIn() || !in_array($cat, $_layoutPrivateCats, true);
+ },
+ ARRAY_FILTER_USE_KEY
+) : [];
+$_layoutCurrentCat = trim($_GET['cat'] ?? '');
+?>
= htmlspecialchars(siteTitle()) ?>
= htmlspecialchars(siteClaim()) ?>
@@ -116,7 +116,7 @@