chore: vendor all CDN assets locally; reorganise assets into css/ and js/

All third-party assets are now self-hosted — zero external requests at runtime.

CSS (assets/css/):
  - modern-normalize.min.css  (was assets/)
  - common.css, admin.css, main.css, search.css, tfe.css, apropos.css  (was assets/)
  - easymde.min.css 2.20.0  (was cdn.jsdelivr.net)
  - font-awesome.min.css 4.7.0  (was maxcdn.bootstrapcdn.com; injected at runtime by EasyMDE)

JS (assets/js/):
  - easymde.min.js 2.20.0  (was cdn.jsdelivr.net)

Fonts (assets/fonts/fontawesome/):
  - fontawesome-webfont.{eot,woff2,woff,ttf,svg}, FontAwesome.otf 4.7.0

Path fixes:
  - common.css @font-face: ./fonts/ -> ../fonts/ (one level deeper)
  - font-awesome.min.css @font-face: ../fonts/ -> ../fonts/fontawesome/ (dedicated subdir)
  - pages-edit.php: autoDownloadFontAwesome:false added to EasyMDE init to
    suppress the runtime CDN injection that was still present inside easymde.min.js

Reference updates (all now absolute /assets/css/* or /assets/js/*):
  - templates/public/head.php: modern-normalize + common
  - templates/admin/head.php: modern-normalize + admin
  - public/admin/login.php: modern-normalize + admin (standalone head)
  - public/index.php, tfe.php, search.php, apropos.php, licence.php: extraCss paths
  - public/admin/pages-edit.php: extraCss + extraJs (font-awesome, easymde CSS/JS)

Nginx static-file location already covers .css/.js/.woff/.woff2/.ttf/.otf with
30-day cache headers — no nginx config change needed.
This commit is contained in:
Pontoporeia
2026-03-31 15:35:03 +02:00
parent 986945a347
commit 338782947c
19 changed files with 76 additions and 21 deletions

View File

@@ -329,6 +329,9 @@ Goal: rename the tables and column to the canonical M2M pattern (`tags`, `thesis
## Pending ## Pending
- [x] Vendor all CDN assets locally (`assets/css/`, `assets/js/`); drop Font Awesome entirely by
replacing EasyMDE's FA4 toolbar icons with inline SVG (Tabler Icons, MIT); saves 708 KB of
font/CSS payload and eliminates the runtime CDN injection in `easymde.min.js`
- [x] Add flake.nix for Nix-based PHP dev environment - [x] Add flake.nix for Nix-based PHP dev environment
- [x] Add favicon (`<link rel="icon">` → admin_favicon.svg) to all pages; nginx 204 for /favicon.ico - [x] Add favicon (`<link rel="icon">` → admin_favicon.svg) to all pages; nginx 204 for /favicon.ico
- [x] Remove 100-item cap from répertoire student index: `getAllPublishedTheses()` fetches all published theses; search results remain paginated at 30/page - [x] Remove 100-item cap from répertoire student index: `getAllPublishedTheses()` fetches all published theses; search results remain paginated at 30/page

View File

@@ -30,8 +30,8 @@ $pageTitle = 'Connexion';
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Connexion Posterg Admin</title> <title>Connexion Posterg Admin</title>
<link rel="icon" type="image/svg+xml" href="/assets/admin_favicon.svg"> <link rel="icon" type="image/svg+xml" href="/assets/admin_favicon.svg">
<link rel="stylesheet" href="/assets/modern-normalize.min.css"> <link rel="stylesheet" href="/assets/css/modern-normalize.min.css">
<link rel="stylesheet" href="/assets/admin.css"> <link rel="stylesheet" href="/assets/css/admin.css">
</head> </head>
<body class="admin-body"> <body class="admin-body">
<nav class="admin-nav"> <nav class="admin-nav">

View File

@@ -28,11 +28,49 @@ try {
} }
$pageTitle = "Éditer : " . htmlspecialchars($page['title']); $pageTitle = "Éditer : " . htmlspecialchars($page['title']);
$extraCss = ['https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.css']; $extraCss = ['/assets/css/easymde.min.css'];
$extraJs = ['https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.js']; $extraJs = ['/assets/js/easymde.min.js'];
// SVG icons for each toolbar button — eliminates the Font Awesome dependency entirely.
// Paths sourced from Tabler Icons (MIT). 20×20 viewBox, stroke-based, no fill.
$extraJsInline = <<<'JS' $extraJsInline = <<<'JS'
var SVG = {
bold: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 4h8a4 4 0 0 1 0 8H6z"/><path d="M6 12h9a4 4 0 0 1 0 8H6z"/></svg>',
italic: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/></svg>',
heading: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 4v16"/><path d="M18 4v16"/><path d="M6 12h12"/></svg>',
quote: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1z"/><path d="M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1z"/></svg>',
"unordered-list": '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><line x1="9" y1="6" x2="20" y2="6"/><line x1="9" y1="12" x2="20" y2="12"/><line x1="9" y1="18" x2="20" y2="18"/><circle cx="4" cy="6" r="1" fill="currentColor" stroke="none"/><circle cx="4" cy="12" r="1" fill="currentColor" stroke="none"/><circle cx="4" cy="18" r="1" fill="currentColor" stroke="none"/></svg>',
"ordered-list": '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/></svg>',
link: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>',
image: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></svg>',
preview: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>',
"side-by-side": '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="18" rx="1"/><rect x="14" y="3" width="7" height="18" rx="1"/></svg>',
fullscreen: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M21 8V5a2 2 0 0 0-2-2h-3"/><path d="M3 16v3a2 2 0 0 0 2 2h3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/></svg>',
guide: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>'
};
var toolbar = [
{ name: 'bold', action: EasyMDE.toggleBold, icon: SVG.bold, title: 'Gras (Ctrl+B)' },
{ name: 'italic', action: EasyMDE.toggleItalic, icon: SVG.italic, title: 'Italique (Ctrl+I)' },
{ name: 'heading', action: EasyMDE.toggleHeadingSmaller, icon: SVG.heading, title: 'Titre' },
'|',
{ name: 'quote', action: EasyMDE.toggleBlockquote, icon: SVG.quote, title: 'Citation' },
{ name: 'unordered-list', action: EasyMDE.toggleUnorderedList, icon: SVG['unordered-list'], title: 'Liste à puces' },
{ name: 'ordered-list', action: EasyMDE.toggleOrderedList, icon: SVG['ordered-list'], title: 'Liste numérotée' },
'|',
{ name: 'link', action: EasyMDE.drawLink, icon: SVG.link, title: 'Insérer un lien (Ctrl+K)'},
{ name: 'image', action: EasyMDE.drawImage, icon: SVG.image, title: 'Insérer une image' },
'|',
{ name: 'preview', action: EasyMDE.togglePreview, icon: SVG.preview, title: 'Aperçu (Ctrl+P)', noDisable: true },
{ name: 'side-by-side', action: EasyMDE.toggleSideBySide, icon: SVG['side-by-side'], title: 'Côte à côte (F9)', noDisable: true, noMobile: true },
{ name: 'fullscreen', action: EasyMDE.toggleFullScreen, icon: SVG.fullscreen, title: 'Plein écran (F11)', noDisable: true, noMobile: true },
'|',
{ name: 'guide', action: 'https://www.markdownguide.org/basic-syntax/', icon: SVG.guide, title: 'Guide Markdown', noDisable: true }
];
var easyMDE = new EasyMDE({ var easyMDE = new EasyMDE({
element: document.getElementById('content'), element: document.getElementById('content'),
autoDownloadFontAwesome: false,
toolbar: toolbar,
spellChecker: false, spellChecker: false,
status: ['lines', 'words'], status: ['lines', 'words'],
minHeight: '400px', minHeight: '400px',

View File

@@ -33,7 +33,7 @@ $ogTags = [
'url' => 'https://posterg.erg.be/apropos.php', 'url' => 'https://posterg.erg.be/apropos.php',
'site_name' => 'Posterg ERG', 'site_name' => 'Posterg ERG',
]; ];
$extraCss = ['assets/apropos.css']; $extraCss = ['/assets/css/apropos.css'];
?> ?>
<?php include APP_ROOT . '/templates/public/head.php'; ?> <?php include APP_ROOT . '/templates/public/head.php'; ?>
<body class="apropos-body"> <body class="apropos-body">

View File

@@ -1,6 +1,6 @@
@font-face { @font-face {
font-family: "police1"; font-family: "police1";
src: url("./fonts/Combinedd.otf"); src: url("../fonts/Combinedd.otf");
font-display: swap; font-display: swap;
} }

7
public/assets/css/easymde.min.css vendored Normal file

File diff suppressed because one or more lines are too long

7
public/assets/js/easymde.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -59,7 +59,7 @@ $ogTags = [
'url' => 'https://posterg.erg.be/', 'url' => 'https://posterg.erg.be/',
'site_name' => 'Posterg ERG', 'site_name' => 'Posterg ERG',
]; ];
$extraCss = ['assets/main.css']; $extraCss = ['/assets/css/main.css'];
?> ?>
<?php include APP_ROOT . '/templates/public/head.php'; ?> <?php include APP_ROOT . '/templates/public/head.php'; ?>
<body class="home-body"> <body class="home-body">

View File

@@ -29,7 +29,7 @@ $ogTags = [
'url' => 'https://posterg.erg.be/licence.php', 'url' => 'https://posterg.erg.be/licence.php',
'site_name' => 'Posterg ERG', 'site_name' => 'Posterg ERG',
]; ];
$extraCss = ['assets/apropos.css']; $extraCss = ['/assets/css/apropos.css'];
?> ?>
<?php include APP_ROOT . '/templates/public/head.php'; ?> <?php include APP_ROOT . '/templates/public/head.php'; ?>
<body class="apropos-body"> <body class="apropos-body">

View File

@@ -109,7 +109,7 @@ $ogTags = [
'url' => 'https://posterg.erg.be/search.php', 'url' => 'https://posterg.erg.be/search.php',
'site_name' => 'Posterg ERG', 'site_name' => 'Posterg ERG',
]; ];
$extraCss = ['assets/search.css']; $extraCss = ['/assets/css/search.css'];
?> ?>
<?php include APP_ROOT . '/templates/public/head.php'; ?> <?php include APP_ROOT . '/templates/public/head.php'; ?>
<body class="search-body"> <body class="search-body">

View File

@@ -56,7 +56,7 @@ $ogTags = [
unset($_ogBaseUrl, $_ogImage); unset($_ogBaseUrl, $_ogImage);
// --- End Open Graph ---------------------------------------------------------- // --- End Open Graph ----------------------------------------------------------
$extraCss = ['assets/tfe.css']; $extraCss = ['/assets/css/tfe.css'];
?> ?>
<?php include APP_ROOT . '/templates/public/head.php'; ?> <?php include APP_ROOT . '/templates/public/head.php'; ?>
<body class="tfe-body"> <body class="tfe-body">

View File

@@ -5,8 +5,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title><?= htmlspecialchars($pageTitle ?? 'Admin') ?> Posterg</title> <title><?= htmlspecialchars($pageTitle ?? 'Admin') ?> Posterg</title>
<link rel="icon" type="image/svg+xml" href="/assets/admin_favicon.svg"> <link rel="icon" type="image/svg+xml" href="/assets/admin_favicon.svg">
<link rel="stylesheet" href="/assets/modern-normalize.min.css"> <link rel="stylesheet" href="/assets/css/modern-normalize.min.css">
<link rel="stylesheet" href="/assets/admin.css"> <link rel="stylesheet" href="/assets/css/admin.css">
<?php foreach ($extraCss ?? [] as $css): ?> <?php foreach ($extraCss ?? [] as $css): ?>
<link rel="stylesheet" href="<?= htmlspecialchars($css) ?>"> <link rel="stylesheet" href="<?= htmlspecialchars($css) ?>">
<?php endforeach; ?> <?php endforeach; ?>

View File

@@ -49,8 +49,8 @@
<?php endif; ?> <?php endif; ?>
<?php endif; ?> <?php endif; ?>
<link rel="icon" type="image/svg+xml" href="/assets/admin_favicon.svg"> <link rel="icon" type="image/svg+xml" href="/assets/admin_favicon.svg">
<link rel="stylesheet" href="assets/modern-normalize.min.css"> <link rel="stylesheet" href="/assets/css/modern-normalize.min.css">
<link rel="stylesheet" href="assets/common.css"> <link rel="stylesheet" href="/assets/css/common.css">
<?php foreach ($extraCss ?? [] as $css): ?> <?php foreach ($extraCss ?? [] as $css): ?>
<link rel="stylesheet" href="<?= htmlspecialchars($css) ?>"> <link rel="stylesheet" href="<?= htmlspecialchars($css) ?>">
<?php endforeach; ?> <?php endforeach; ?>