feat: ColorArea schreibt geänderte globale Farben gemischt und stellt Snapshots ersetzend wieder her

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-19 14:07:12 +02:00
co-authored by Claude Sonnet 5.5
parent e269fcb1f8
commit c1f77d2017
2 changed files with 265 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Integrations\Divi\Design;
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
defined('ABSPATH') || exit;
/**
* The area "colors" (spec §7.1, rulings V3, V4): the global colors as ColorBook reads them through
* GlobalColorsAdapter (the five main colors from et_divi, their lastUpdated empty). A change writes only the new and
* changed colors – merged, the way Divi's builder saves –, compared with the inventory read right before; a restore
* (and a rollback) replaces all stored colors with the snapshot. Divi's sanitizing may change values: verify() only
* insists on the same colors with the same status, differences() names the colors whose values changed.
*/
final class ColorArea implements DesignArea
{
public function __construct(private GlobalColorsAdapter $colors)
{
}
public function name(): string
{
return 'colors';
}
public function label(): string
{
return 'Farben';
}
public function feature(): DiviFeature
{
return DiviFeature::ColorWrite;
}
public function raw(): array
{
return ColorBook::fromDivi($this->colors->read())->data();
}
public function rev(array $raw): string
{
return ColorBook::fromDivi($raw)->rev();
}
public function write(array $raw, bool $mayRemove): array
{
$planned = ColorBook::fromDivi($raw);
if ($mayRemove) {
$this->colors->save($planned->data(), true);
return $this->raw();
}
$changed = $planned->changedSince(ColorBook::fromDivi($this->colors->read()));
if ($changed !== []) {
$this->colors->save($changed, false);
}
return $this->raw();
}
public function restore(array $raw): array
{
return $this->write($raw, true);
}
public function verify(array $expected, array $actual): bool
{
return self::statuses($expected) === self::statuses($actual);
}
public function differences(array $expected, array $actual): array
{
$warnings = [];
foreach (ColorDiff::between(ColorBook::fromDivi($expected), ColorBook::fromDivi($actual)) as $row) {
if ($row['action'] === 'changed') {
$warnings[] = sprintf('Divi hat die Farbe „%s“ beim Speichern bereinigt.', $row['name']);
}
}
return $warnings;
}
/**
* @param array<array-key, mixed> $raw
* @return array<string, string> ID => status, sorted by ID
*/
private static function statuses(array $raw): array
{
$statuses = array_map(
static fn (array $entry): string => (string) $entry['status'],
ColorBook::fromDivi($raw)->data()
);
ksort($statuses);
return $statuses;
}
}