Back up unsaved editor work locally, structure the settings, fix archive accessibility

- The editor keeps unsaved changes in the browser and offers them
  after a crash, a closed tab or an expired session. No timed save on
  the server: every save is a full revision.
- The save status stays visible in narrow windows.
- Settings get a sticky section bar, two folded groups and a save bar
  that stays in view.
- The admin post list fetches terms and images once, not per post.
- Archive post titles are second-level headings, the archive head
  keeps full text contrast, the skip link sits above a sticky header,
  a linked image without alternative text names its link.
- The editor check starts through the dev router like the others.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
kantarciandClaude Fable 5.2 committed 2026-11-10 13:01:23 +01:00
1 parent 5e46c98825
commit b08862b139
17 files changed
+182 -26

No files matched your search

+2 -1
View File
@@ -130,7 +130,8 @@ final class MediaLibrary
'SELECT * FROM media WHERE id IN ('.implode(',', array_fill(0, count($ids), '?')).')',
$ids,
) as $row) {
$found[$row['id']] = $this->present($row);
// Auch für find(): Wer die Bilder einer Liste vorab holt, erspart jede Einzelabfrage danach.
$found[$row['id']] = $this->gemerkt[$row['id']] = $this->present($row);
}
return $found;
+34
View File
@@ -313,6 +313,40 @@ final class PostRepository
}
/** Term names of one page, as the comma separated list the metadata form edits. */
/**
* Kategorien und Schlagwörter mehrerer Beiträge in einer Abfrage, als Text je Beitrag.
*
* Die Liste der Verwaltung fragte vorher für jeden Beitrag einzeln nach: zwanzig Beiträge,
* vierzig Abfragen.
*
* @param list<string> $pageIds
*
* @return array<string, array{category: string, tag: string}>
*/
public function namesForMany(array $pageIds): array
{
$names = [];
foreach ($this->termsForMany($pageIds) as $id => $terms) {
$names[$id] = [
'category' => implode(', ', array_column($terms['category'], 'name')),
'tag' => implode(', ', array_column($terms['tag'], 'name')),
];
}
return $names;
}
/**
* Holt die Bilder einer Liste in einer Abfrage, damit die Vorlage sie danach einzeln findet,
* ohne je Zeile die Datenbank zu fragen.
*
* @param list<string|null> $mediaIds
*/
public function preloadImages(array $mediaIds): void
{
$this->media->findMany(array_map('strval', array_filter($mediaIds)));
}
public function namesFor(string $pageId): array
{
$terms = $this->termsFor($pageId);