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>
348 lines
13 KiB
PHP
348 lines
13 KiB
PHP
<x-filament-panels::page>
|
||
@php
|
||
$lc = \App\Support\Hints::locale();
|
||
$areas = $this->getAreas();
|
||
$grouped = $this->getGrouped();
|
||
$user = auth()->user();
|
||
$totalHints = collect($grouped)->sum(fn ($g) => count($g));
|
||
$videoEmbed = $this->getVideoEmbedUrl();
|
||
$videoRaw = $this->getVideoRawUrl();
|
||
// Distinct accent color per area for card headers
|
||
$areaColors = [
|
||
'service' => '#0ea5e9',
|
||
'crm' => '#8b5cf6',
|
||
'depozit' => '#f59e0b',
|
||
'finante' => '#10b981',
|
||
];
|
||
@endphp
|
||
|
||
<style>
|
||
.faq-shell { width: 100%; }
|
||
|
||
/* ── VIDEO ── */
|
||
.faq-video-card {
|
||
background: #000;
|
||
border-radius: 12px;
|
||
overflow: hidden;
|
||
margin-bottom: 20px;
|
||
position: relative;
|
||
aspect-ratio: 16 / 9;
|
||
max-height: 480px;
|
||
}
|
||
.faq-video-card iframe {
|
||
position: absolute;
|
||
inset: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
border: 0;
|
||
}
|
||
.faq-video-fallback {
|
||
background: linear-gradient(135deg, #374151 0%, #111827 100%);
|
||
border-radius: 12px;
|
||
padding: 40px 28px;
|
||
color: #fff;
|
||
margin-bottom: 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 20px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.faq-video-fallback-icon { font-size: 40px; }
|
||
.faq-video-fallback-txt { flex: 1; min-width: 200px; }
|
||
.faq-video-fallback-title { font-size: 16px; font-weight: 600; margin: 0 0 4px; }
|
||
.faq-video-fallback-sub { font-size: 13px; opacity: .8; margin: 0; }
|
||
.faq-video-fallback a { color: #60a5fa; text-decoration: none; font-weight: 500; }
|
||
.faq-video-fallback a:hover { text-decoration: underline; }
|
||
|
||
/* ── HERO STRIP ── */
|
||
.faq-hero {
|
||
background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%);
|
||
border-radius: 12px;
|
||
padding: 24px 28px;
|
||
color: #fff;
|
||
margin-bottom: 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 24px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.dark .faq-hero { background: linear-gradient(135deg, #1e3a8a 0%, #0f172a 100%); }
|
||
.faq-hero-icon { font-size: 48px; line-height: 1; }
|
||
.faq-hero-txt { flex: 1; min-width: 200px; }
|
||
.faq-hero-title { font-size: 22px; font-weight: 700; margin: 0 0 4px; letter-spacing: -.3px; }
|
||
.faq-hero-sub { font-size: 13px; opacity: .85; margin: 0; }
|
||
.faq-hero-stats { display: flex; gap: 16px; }
|
||
.faq-hero-stat { text-align: center; }
|
||
.faq-hero-stat-n { font-size: 24px; font-weight: 700; line-height: 1; }
|
||
.faq-hero-stat-l { font-size: 11px; opacity: .8; text-transform: uppercase; letter-spacing: .5px; }
|
||
|
||
/* ── CONTROLS BAR ── */
|
||
.faq-controls {
|
||
display: grid;
|
||
grid-template-columns: 1fr auto;
|
||
gap: 12px;
|
||
align-items: center;
|
||
margin-bottom: 24px;
|
||
padding: 12px 16px;
|
||
background: #fff;
|
||
border: 1px solid #e5e7eb;
|
||
border-radius: 10px;
|
||
}
|
||
.dark .faq-controls { background: #1f2937; border-color: #374151; }
|
||
.faq-search {
|
||
width: 100%;
|
||
padding: 10px 14px 10px 40px;
|
||
border: 1px solid #d1d5db;
|
||
border-radius: 8px;
|
||
font-size: 14px;
|
||
background: #fff url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.35-4.35'/></svg>") no-repeat 12px center;
|
||
}
|
||
.dark .faq-search { background-color: #111827; border-color: #4b5563; color: #f3f4f6; }
|
||
.faq-search:focus { outline: 2px solid #3b82f6; outline-offset: -1px; border-color: #3b82f6; }
|
||
.faq-toggle { display: flex; gap: 8px; align-items: center; font-size: 13px; }
|
||
.faq-toggle-lbl { color: #6b7280; font-size: 12px; }
|
||
.faq-btn-toggle {
|
||
display: inline-flex; align-items: center; gap: 6px;
|
||
padding: 7px 14px; border-radius: 20px; border: 0;
|
||
font-size: 12px; font-weight: 600; cursor: pointer;
|
||
transition: all .15s;
|
||
}
|
||
.faq-btn-toggle.on { background: #10b981; color: #fff; }
|
||
.faq-btn-toggle.off { background: #e5e7eb; color: #374151; }
|
||
.faq-btn-toggle:hover { transform: translateY(-1px); box-shadow: 0 2px 6px rgba(0,0,0,.15); }
|
||
.faq-btn-reset {
|
||
padding: 7px 14px; border-radius: 20px;
|
||
border: 1px solid #d1d5db; background: #fff; color: #6b7280;
|
||
font-size: 12px; cursor: pointer;
|
||
}
|
||
.dark .faq-btn-reset { background: #374151; border-color: #4b5563; color: #d1d5db; }
|
||
.faq-btn-reset:hover { background: #f9fafb; color: #111; }
|
||
.dark .faq-btn-reset:hover { background: #4b5563; color: #f3f4f6; }
|
||
|
||
/* ── GRID OF AREA CARDS ── */
|
||
.faq-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); gap: 20px; }
|
||
@media (max-width: 900px) { .faq-grid { grid-template-columns: 1fr; } }
|
||
|
||
.faq-card {
|
||
background: #fff;
|
||
border: 1px solid #e5e7eb;
|
||
border-radius: 12px;
|
||
overflow: hidden;
|
||
box-shadow: 0 1px 3px rgba(0,0,0,.05);
|
||
}
|
||
.dark .faq-card { background: #1f2937; border-color: #374151; }
|
||
.faq-card-hd {
|
||
padding: 16px 18px;
|
||
border-bottom: 1px solid #e5e7eb;
|
||
display: flex; align-items: center; gap: 12px;
|
||
color: #fff;
|
||
}
|
||
.dark .faq-card-hd { border-bottom-color: #374151; }
|
||
.faq-card-icon { font-size: 26px; line-height: 1; }
|
||
.faq-card-title { font-size: 15px; font-weight: 700; letter-spacing: -.2px; flex: 1; }
|
||
.faq-card-badge {
|
||
background: rgba(255,255,255,.25);
|
||
padding: 2px 10px; border-radius: 10px;
|
||
font-size: 11px; font-weight: 700;
|
||
}
|
||
|
||
.faq-card-body { padding: 8px; }
|
||
.faq-item {
|
||
border-radius: 8px;
|
||
margin-bottom: 4px;
|
||
overflow: hidden;
|
||
transition: background .15s;
|
||
}
|
||
.faq-item summary {
|
||
padding: 10px 14px;
|
||
cursor: pointer;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
color: #111;
|
||
list-style: none;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
user-select: none;
|
||
border-radius: 8px;
|
||
}
|
||
.dark .faq-item summary { color: #f3f4f6; }
|
||
.faq-item summary:hover { background: #f9fafb; }
|
||
.dark .faq-item summary:hover { background: #374151; }
|
||
.faq-item summary::-webkit-details-marker { display: none; }
|
||
.faq-item summary::after { content: '+'; color: #9ca3af; font-size: 18px; font-weight: 400; line-height: 1; }
|
||
.faq-item[open] { background: #f0f9ff; }
|
||
.dark .faq-item[open] { background: #1e3a5f; }
|
||
.faq-item[open] summary::after { content: '−'; }
|
||
|
||
.faq-body-txt {
|
||
padding: 0 14px 14px;
|
||
font-size: 12.5px;
|
||
line-height: 1.55;
|
||
color: #374151;
|
||
}
|
||
.dark .faq-body-txt { color: #d1d5db; }
|
||
.faq-next {
|
||
margin-top: 10px;
|
||
padding: 8px 12px;
|
||
background: #d1fae5;
|
||
color: #065f46;
|
||
border-radius: 6px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
}
|
||
.dark .faq-next { background: #064e3b; color: #a7f3d0; }
|
||
.faq-next::before { content: '→ '; font-weight: 700; }
|
||
.faq-links {
|
||
margin-top: 10px;
|
||
display: flex;
|
||
gap: 8px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.faq-link {
|
||
padding: 4px 10px;
|
||
background: #eff6ff;
|
||
color: #1d4ed8;
|
||
border-radius: 6px;
|
||
font-size: 11.5px;
|
||
text-decoration: none;
|
||
font-weight: 500;
|
||
}
|
||
.dark .faq-link { background: #1e3a8a; color: #93c5fd; }
|
||
.faq-link:hover { background: #dbeafe; }
|
||
.dark .faq-link:hover { background: #1e40af; }
|
||
|
||
/* ── EMPTY STATE ── */
|
||
.faq-empty {
|
||
grid-column: 1 / -1;
|
||
text-align: center;
|
||
padding: 60px 20px;
|
||
color: #9ca3af;
|
||
font-size: 14px;
|
||
background: #fff;
|
||
border: 1px dashed #e5e7eb;
|
||
border-radius: 12px;
|
||
}
|
||
.dark .faq-empty { background: #1f2937; border-color: #374151; }
|
||
.faq-empty-icon { font-size: 40px; margin-bottom: 12px; }
|
||
</style>
|
||
|
||
<div class="faq-shell">
|
||
|
||
{{-- HERO --}}
|
||
<div class="faq-hero">
|
||
<div class="faq-hero-icon">📖</div>
|
||
<div class="faq-hero-txt">
|
||
<h1 class="faq-hero-title">{{ __('Ghid rapid AutoCRM') }}</h1>
|
||
<p class="faq-hero-sub">{{ __('Toate răspunsurile la un click distanță. Fiecare pagină are propriile hint-uri „?" — sau caută mai jos.') }}</p>
|
||
</div>
|
||
<div class="faq-hero-stats">
|
||
<div class="faq-hero-stat">
|
||
<div class="faq-hero-stat-n">{{ $totalHints }}</div>
|
||
<div class="faq-hero-stat-l">{{ __('subiecte') }}</div>
|
||
</div>
|
||
<div class="faq-hero-stat">
|
||
<div class="faq-hero-stat-n">{{ count($areas) }}</div>
|
||
<div class="faq-hero-stat-l">{{ __('secțiuni') }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- VIDEO TUTORIAL (dacă e configurat) --}}
|
||
@if ($videoEmbed)
|
||
<div class="faq-video-card">
|
||
<iframe src="{{ $videoEmbed }}"
|
||
title="{{ __('Video tutorial') }}"
|
||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||
allowfullscreen></iframe>
|
||
</div>
|
||
@elseif ($videoRaw)
|
||
<div class="faq-video-fallback">
|
||
<div class="faq-video-fallback-icon">🎥</div>
|
||
<div class="faq-video-fallback-txt">
|
||
<h3 class="faq-video-fallback-title">{{ __('Video tutorial') }}</h3>
|
||
<p class="faq-video-fallback-sub">
|
||
{{ __('URL nerecunoscut — deschide-l direct:') }}
|
||
<a href="{{ $videoRaw }}" target="_blank">{{ $videoRaw }}</a>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
@elseif ($user?->isAdmin())
|
||
<div class="faq-video-fallback">
|
||
<div class="faq-video-fallback-icon">🎥</div>
|
||
<div class="faq-video-fallback-txt">
|
||
<h3 class="faq-video-fallback-title">{{ __('Video tutorial') }}</h3>
|
||
<p class="faq-video-fallback-sub">
|
||
{{ __('Adaugă un link YouTube/Vimeo în') }}
|
||
<a href="{{ url('/app/settings') }}">{{ __('Setări → Liste configurabile') }} →</a>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
@endif
|
||
|
||
{{-- CONTROLS --}}
|
||
<div class="faq-controls">
|
||
<input type="text" class="faq-search" placeholder="{{ __('Caută în ghid...') }}" wire:model.live.debounce.300ms="search">
|
||
<div class="faq-toggle">
|
||
<span class="faq-toggle-lbl">{{ __('Sugestii pe pagini:') }}</span>
|
||
<form method="POST" action="{{ route('hints.toggle') }}" style="display:inline;">
|
||
@csrf
|
||
<button type="submit" class="faq-btn-toggle {{ $user?->hints_enabled ? 'on' : 'off' }}">
|
||
{{ $user?->hints_enabled ? '● ' . __('ACTIVE') : '○ ' . __('INACTIVE') }}
|
||
</button>
|
||
</form>
|
||
<form method="POST" action="{{ route('hints.reset') }}" style="display:inline;">
|
||
@csrf
|
||
<button type="submit" class="faq-btn-reset" title="{{ __('Aduce înapoi hint-urile ascunse') }}">
|
||
↻ {{ __('Resetează') }}
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- GRID --}}
|
||
<div class="faq-grid">
|
||
@if (empty($grouped))
|
||
<div class="faq-empty">
|
||
<div class="faq-empty-icon">🔍</div>
|
||
{{ __('Nicio potrivire pentru „:q".', ['q' => $search]) }}
|
||
</div>
|
||
@endif
|
||
|
||
@foreach ($grouped as $areaKey => $hints)
|
||
@php
|
||
$area = $areas[$areaKey] ?? null;
|
||
$accent = $areaColors[$areaKey] ?? '#6b7280';
|
||
@endphp
|
||
<div class="faq-card">
|
||
<div class="faq-card-hd" style="background:{{ $accent }};">
|
||
<span class="faq-card-icon">{{ $area['icon'] ?? '📖' }}</span>
|
||
<span class="faq-card-title">{{ $area['label'][$lc] ?? $areaKey }}</span>
|
||
<span class="faq-card-badge">{{ count($hints) }}</span>
|
||
</div>
|
||
<div class="faq-card-body">
|
||
@foreach ($hints as $key => $h)
|
||
<details class="faq-item">
|
||
<summary>{{ $h['title'][$lc] ?? $h['title']['ro'] }}</summary>
|
||
<div class="faq-body-txt">
|
||
{{ $h['body'][$lc] ?? $h['body']['ro'] }}
|
||
@if (! empty($h['next'][$lc]))
|
||
<div class="faq-next">{{ $h['next'][$lc] }}</div>
|
||
@endif
|
||
@if (! empty($h['links']))
|
||
<div class="faq-links">
|
||
@foreach ($h['links'] as $ln)
|
||
<a class="faq-link" href="{{ url($ln['url']) }}">{{ $ln['label_' . $lc] ?? $ln['label_ro'] }}</a>
|
||
@endforeach
|
||
</div>
|
||
@endif
|
||
</div>
|
||
</details>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
</x-filament-panels::page>
|