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:
1 parent
5e46c98825
commit
b08862b139
17 files changed
+182
-26
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -49,11 +49,13 @@ final class EditorController extends AbstractController
|
||||
$result = $this->pages->editorPage($type, $request->query->getInt('seite', 1), $request->query->getInt('limit', 20), $query, $status);
|
||||
$pages = $result['items'];
|
||||
$parentChoices = [];
|
||||
$terms = 'post' === $type ? $this->posts->namesForMany(array_column($pages, 'id')) : [];
|
||||
$this->posts->preloadImages([...array_column($pages, 'featured_media_id'), ...array_column($pages, 'og_media_id')]);
|
||||
foreach ($pages as &$page) {
|
||||
$page['document'] = json_decode($page['document'] ?? '{}', true, 512, JSON_THROW_ON_ERROR);
|
||||
$page['title'] = $page['document']['title'] ?? $page['slug'];
|
||||
$page['depth'] = substr_count((string) $page['path'], '/');
|
||||
$page['terms'] = 'post' === $page['type'] ? $this->posts->namesFor($page['id']) : ['category' => '', 'tag' => ''];
|
||||
$page['terms'] = $terms[$page['id']] ?? ['category' => '', 'tag' => ''];
|
||||
if ($page['parent_id'] && !isset($parentChoices[$page['parent_id']])) {
|
||||
$parentChoices[$page['parent_id']] = $this->pages->choices(id: $page['parent_id'])[0] ?? null;
|
||||
}
|
||||
|
||||
@@ -960,7 +960,7 @@ final class PageController extends AbstractController
|
||||
'blocks' => [
|
||||
['id' => 'archiv-kopf', 'type' => 'section', 'layout' => ['tone' => 'mint', 'width' => 'normal'], 'children' => $kopf],
|
||||
['id' => 'archiv', 'type' => 'section', 'layout' => ['tone' => 'paper', 'width' => 'normal'], 'children' => [
|
||||
['id' => 'archiv-liste', 'type' => 'postlist', 'props' => ['count' => PostRepository::PER_PAGE, 'category' => 'category' === $kind && null !== $term ? $term['slug'] : '', 'tag' => 'tag' === $kind && null !== $term ? $term['slug'] : '', 'layout' => 'karten', 'paginate' => true]],
|
||||
['id' => 'archiv-liste', 'type' => 'postlist', 'props' => ['count' => PostRepository::PER_PAGE, 'category' => 'category' === $kind && null !== $term ? $term['slug'] : '', 'tag' => 'tag' === $kind && null !== $term ? $term['slug'] : '', 'layout' => 'karten', 'paginate' => true, 'headingLevel' => 2]],
|
||||
]],
|
||||
],
|
||||
];
|
||||
|
||||
Reference in new issue
Block a user