0716b70bfa
- New tenant setting: settings.faq_video_url. TextInput on Settings page → Liste configurabile (accepts YouTube watch URL, youtu.be short URL, YouTube shorts/embed URL, or Vimeo URL). - Faq page has getVideoEmbedUrl() that converts recognized URLs to their /embed/ variant. Unknown URLs fall back to a "?" card with a direct link. Admins see a "configure in Settings" nudge when no URL is set. - Video renders as a 16:9 iframe capped at 480px height, above the hero. - .faq-shell is now width:100% (was max-width:1200px) so FAQ uses all available horizontal space. - .faq-grid switched from strict 2 columns to repeat(auto-fit, minmax(420px, 1fr)) so wide screens get 3 columns and narrow screens stack. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
94 lines
2.7 KiB
PHP
94 lines
2.7 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Tenant\Pages;
|
|
|
|
use App\Support\Hints;
|
|
use Filament\Pages\Page;
|
|
|
|
/**
|
|
* FAQ / help page — renders the entire hints registry grouped by area
|
|
* with a client-side search box. Same content that surfaces contextually
|
|
* in "?" popovers around the app.
|
|
*/
|
|
class Faq extends Page
|
|
{
|
|
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-question-mark-circle';
|
|
|
|
protected string $view = 'filament.tenant.pages.faq';
|
|
|
|
public string $search = '';
|
|
|
|
public static function getNavigationLabel(): string
|
|
{
|
|
return __('nav.label.FAQ & Ghid');
|
|
}
|
|
|
|
public static function getNavigationGroup(): ?string
|
|
{
|
|
return __('nav.group.Admin');
|
|
}
|
|
|
|
protected static ?int $navigationSort = 1;
|
|
|
|
public function getTitle(): string
|
|
{
|
|
return __('FAQ & Ghid utilizator');
|
|
}
|
|
|
|
public function getHeading(): string
|
|
{
|
|
return '';
|
|
}
|
|
|
|
public function getAreas(): array
|
|
{
|
|
return Hints::AREAS;
|
|
}
|
|
|
|
/**
|
|
* Convert a YouTube / Vimeo watch URL to the embed URL that goes in
|
|
* an <iframe src="">. Returns null if the URL is empty or the host
|
|
* isn't recognized (in which case we fall back to a plain link).
|
|
*/
|
|
public function getVideoEmbedUrl(): ?string
|
|
{
|
|
$tenant = app(\App\Tenancy\TenantManager::class)->current();
|
|
$raw = trim((string) ($tenant?->settings['faq_video_url'] ?? ''));
|
|
if ($raw === '') return null;
|
|
|
|
// YouTube: watch?v=ID | youtu.be/ID | shorts/ID
|
|
if (preg_match('#(?:youtube\.com/(?:watch\?v=|shorts/|embed/)|youtu\.be/)([A-Za-z0-9_-]{6,})#', $raw, $m)) {
|
|
return 'https://www.youtube.com/embed/' . $m[1];
|
|
}
|
|
// Vimeo: vimeo.com/ID
|
|
if (preg_match('#vimeo\.com/(\d+)#', $raw, $m)) {
|
|
return 'https://player.vimeo.com/video/' . $m[1];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public function getVideoRawUrl(): ?string
|
|
{
|
|
$tenant = app(\App\Tenancy\TenantManager::class)->current();
|
|
$raw = trim((string) ($tenant?->settings['faq_video_url'] ?? ''));
|
|
return $raw !== '' ? $raw : null;
|
|
}
|
|
|
|
public function getGrouped(): array
|
|
{
|
|
$q = mb_strtolower(trim($this->search));
|
|
$lc = Hints::locale();
|
|
$grouped = Hints::byArea();
|
|
if ($q === '') return $grouped;
|
|
$out = [];
|
|
foreach ($grouped as $area => $hints) {
|
|
$matched = array_filter($hints, function ($h) use ($q, $lc) {
|
|
$t = mb_strtolower(($h['title'][$lc] ?? '') . ' ' . ($h['body'][$lc] ?? ''));
|
|
return str_contains($t, $q);
|
|
});
|
|
if (! empty($matched)) $out[$area] = $matched;
|
|
}
|
|
return $out;
|
|
}
|
|
}
|