app/Services/Branding.php
Rama main · réplica de lectura del repositorio original.
<?php
namespace App\Services;
use App\Models\Setting;
use Illuminate\Support\Facades\Storage;
/**
* One place that answers "what does this install look like and what does it show".
* Every default is the free behaviour, so an unlicensed install is complete,
* not crippled.
*/
class Branding
{
/** Page modules, with their defaults. Everything on: a new install shows a full page. */
public const MODULES = [
'page.show_overall' => ['label' => 'Overall status banner', 'help' => 'The "All systems operational" headline.', 'default' => true],
'page.show_uptime' => ['label' => 'Uptime bar and percentage', 'help' => 'The 90 day bar under the headline.', 'default' => true],
'page.show_services' => ['label' => 'Services list', 'help' => 'Components grouped into services.', 'default' => true],
'page.show_component_uptime' => ['label' => 'Uptime bar per component', 'help' => 'The small bar next to each component.', 'default' => true],
'page.show_incidents' => ['label' => 'Incident history', 'help' => 'Incidents grouped per day.', 'default' => true],
'page.show_empty_days' => ['label' => 'Days without incidents', 'help' => 'Shows "No incidents" rather than skipping the day.', 'default' => true],
'page.show_api_link' => ['label' => 'API link in the footer', 'help' => 'Points at the public JSON feed.', 'default' => true],
'page.show_subscribe' => ['label' => '"Get notified" button', 'help' => 'Lets visitors subscribe to incident e-mails. Needs mail settings (Settings → Mail) and the switch on the Subscribers screen.', 'default' => true],
];
public function module(string $key): bool
{
$default = self::MODULES[$key]['default'] ?? true;
// Every default happens to be "on" today; the table is still the source of truth.
return Setting::get($key, $default ? '1' : '0') === '1'; // @phpstan-ignore ternary.alwaysTrue
}
/** @return array<string, bool> */
public function modules(): array
{
return collect(self::MODULES)->map(fn ($m, $key) => $this->module($key))->all();
}
public function name(): string
{
return Setting::get('brand.name', 'Pharos');
}
public function accent(): string
{
return Setting::get('brand.accent', '#0079d2');
}
/** system | light | dark — what the page starts on before a visitor chooses. */
public function theme(): string
{
$theme = Setting::get('brand.theme', 'system');
return in_array($theme, ['system', 'light', 'dark'], true) ? $theme : 'system';
}
public function __construct(protected License $license) {}
/**
* The paid half is checked when it is *shown*, not only when it is saved:
* otherwise a key that is removed, shared or lapsed would leave the branding
* behind for good. Uploads stay on disk so a returning key restores them.
*/
public function licensed(): bool
{
return $this->license->has(License::FEATURE_BRAND_PACK);
}
public function creditHidden(): bool
{
return $this->licensed() && Setting::get('brand.credit_hidden', '0') === '1';
}
/** Uploaded logo, or null to fall back to the built-in mark. */
public function logoUrl(): ?string
{
return $this->licensed() ? $this->assetUrl('brand.logo_path') : null;
}
/** Second logo for the dark theme; the light one is the fallback. */
public function logoDarkUrl(): ?string
{
return $this->licensed() ? $this->assetUrl('brand.logo_dark_path') : null;
}
/** Content-based URLs also refresh assets when the configured release version is stale. */
public function builtInAssetUrl(string $name): string
{
$path = public_path('brand/'.$name);
$revision = is_file($path) ? hash_file('sha256', $path) : (string) config('pharos.version');
return asset('brand/'.$name).'?v='.rawurlencode((string) $revision);
}
public function faviconUrl(): string
{
return ($this->licensed() ? $this->assetUrl('brand.favicon_path') : null) ?? $this->builtInAssetUrl('pharos-favicon.svg');
}
protected function assetUrl(string $key): ?string
{
$path = Setting::get($key);
// A setting pointing at a file that is gone must not render a broken image.
if (! $path || ! Storage::disk('public')->exists($path)) {
return null;
}
return Storage::disk('public')->url($path);
}
}