tests / feature (8.5) (push) Successful in 1m8s
tests / browser (safari, webkit) (push) Has been cancelled
tests / browser (firefox, firefox) (push) Has been cancelled
tests / lint (push) Successful in 1m5s
tests / feature (8.4) (push) Successful in 1m11s
tests / browser (chrome, chromium) (push) Failing after 6m9s
Error pages for 401 to 503 in an error-view root appended to view.paths, with an inline fallback when the Vite build is missing, and a mail theme rendered from the application's scheme JSON, with opt-in header and message components. Completes Phase 9. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
77 lines
2.5 KiB
PHP
77 lines
2.5 KiB
PHP
<?php
|
|
|
|
namespace NoNameWeb\LivewireMaterial\Support;
|
|
|
|
/**
|
|
* The colour scheme as data, for the places CSS custom properties cannot reach: a mail client
|
|
* resolves none, and an error page whose build is missing has no stylesheet to declare them.
|
|
*
|
|
* The data is the JSON `php artisan material:scheme` writes beside the stylesheet
|
|
* (`livewire-material.scheme`, resources/css/material-scheme.json by default). Without that
|
|
* file — or with one that is not a scheme — the package's own default applies, the same one
|
|
* tokens/scheme.css carries. A role the application's file lacks (a scheme generated before
|
|
* the role existed) is taken from the default, and a value that is not a #rrggbb hex is
|
|
* refused, so nothing but a colour ever reaches a stylesheet.
|
|
*
|
|
* Read on every call and never kept: a regenerated scheme applies at once, and a long-running
|
|
* worker holds nothing.
|
|
*/
|
|
class Scheme
|
|
{
|
|
/**
|
|
* @return array{light: array<string, string>, dark: array<string, string>}
|
|
*/
|
|
public static function load(?string $path = null): array
|
|
{
|
|
$default = static::read(dirname(__DIR__, 2).'/resources/css/tokens/scheme.json');
|
|
$scheme = static::read($path ?? (string) config('livewire-material.scheme'));
|
|
|
|
return [
|
|
'light' => [...$default['light'], ...$scheme['light']],
|
|
'dark' => [...$default['dark'], ...$scheme['dark']],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* The light roles: what a mail wears.
|
|
*
|
|
* @return array<string, string>
|
|
*/
|
|
public static function light(?string $path = null): array
|
|
{
|
|
return static::load($path)['light'];
|
|
}
|
|
|
|
/**
|
|
* @return array{light: array<string, string>, dark: array<string, string>}
|
|
*/
|
|
protected static function read(string $path): array
|
|
{
|
|
$data = is_file($path) ? json_decode((string) file_get_contents($path), true) : null;
|
|
|
|
return [
|
|
'light' => static::roles($data['light'] ?? null),
|
|
'dark' => static::roles($data['dark'] ?? null),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<string, string>
|
|
*/
|
|
protected static function roles(mixed $roles): array
|
|
{
|
|
if (! is_array($roles)) {
|
|
return [];
|
|
}
|
|
|
|
return array_filter(
|
|
$roles,
|
|
fn (mixed $hex, mixed $role): bool => is_string($role)
|
|
&& preg_match('/^[a-z-]+$/', $role) === 1
|
|
&& is_string($hex)
|
|
&& preg_match('/^#[0-9a-fA-F]{6}$/', $hex) === 1,
|
|
ARRAY_FILTER_USE_BOTH,
|
|
);
|
|
}
|
|
}
|