feat(faq): video tutorial + full-width layout + wider grid

- 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>
This commit is contained in:
2026-09-01 10:50:40 +00:00
parent cae2904c76
commit 0716b70bfa
5 changed files with 119 additions and 2 deletions
@@ -5,6 +5,8 @@
$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',
@@ -15,7 +17,42 @@
@endphp
<style>
.faq-shell { max-width: 1200px; margin: 0 auto; }
.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 {
@@ -83,7 +120,7 @@
.dark .faq-btn-reset:hover { background: #4b5563; color: #f3f4f6; }
/* ── GRID OF AREA CARDS ── */
.faq-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
.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 {
@@ -211,6 +248,38 @@
</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">