clusev/app/Livewire/Help/Index.php

63 lines
2.3 KiB
PHP

<?php
namespace App\Livewire\Help;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Url;
use Livewire\Component;
/**
* In-panel help/documentation. Pure display: a left topic nav (like Settings) and a per-locale
* content partial. No persistence, no external calls. Topic keys are also the content-partial
* filenames at resources/views/livewire/help/content/{de,en}/<topic>.blade.php.
*/
#[Layout('layouts.app')]
class Index extends Component
{
/** Help topics in display order. */
private const TOPICS = [
'overview', 'domain-tls', 'security', 'updates', 'commands',
'servers', 'sessions', 'email', 'audit', 'wireguard', 'recovery',
];
#[Url]
public string $topic = 'overview';
// mount() handles the test/parameter-injection path (Livewire::test($class, ['topic' => …])).
// Browser deep links populate $topic via the #[Url] attribute above and bypass mount on
// hydration. Both paths are validated by the render() clamp below.
public function mount(?string $topic = null): void
{
if ($topic !== null) {
$this->topic = $topic; // clamped to a known topic in render()
}
}
public function render()
{
// Authoritative guard: any unknown topic (deep link, tampered property) → overview, so
// the view never @includes a missing content partial.
if (! in_array($this->topic, self::TOPICS, true)) {
$this->topic = 'overview';
}
$labels = [
'overview' => __('help.topic_overview'),
'domain-tls' => __('help.topic_domain_tls'),
'security' => __('help.topic_security'),
'updates' => __('help.topic_updates'),
'commands' => __('help.topic_commands'),
'servers' => __('help.topic_servers'),
'sessions' => __('help.topic_sessions'),
'email' => __('help.topic_email'),
'audit' => __('help.topic_audit'),
'wireguard' => __('help.topic_wireguard'),
'recovery' => __('help.topic_recovery'),
];
$topics = array_map(fn (string $key): array => ['key' => $key, 'label' => $labels[$key]], self::TOPICS);
return view('livewire.help.index', ['topics' => $topics])->title(__('help.title'));
}
}