@if ($sec['data'])
@php /* Nothing to write here, so the section says why rather than opening onto an
empty box: it is built from real records, or its wording is written on
another screen. Same sentences the page editors have always used — the
switch above is the whole control. */
@endphp
{{ $sec['note'] !== '' ? $sec['note'] : t_raw('admin.pc.data_only') }}
@endif
@php
// A section built from repeating rows — ten services, eight FAQ pairs — folds each
// one away. Ten open panels of eight fields ran to a dozen screens and the operator
// scrolled past nine services to reach the tenth. The first is left open so the
// section still shows its shape on arrival. A single-panel section stays a plain
// card: there is nothing to choose between.
$accordion = count($sec['panels']) > 1;
// A panel whose fields all declare a `group` is really several blocks in one — the
// hero's slides. Split it so each becomes its own fold rather than one long card
// with three headings in it.
$panels = [];
foreach ($sec['panels'] as $panel) {
$byGroup = [];
$loose = [];
foreach ($panel['fields'] as $f) {
$g = (string) ($f['opts']['group'] ?? '');
if ($g === '') { $loose[] = $f; } else { $byGroup[$g][] = $f; }
}
if ($byGroup === []) { $panels[] = $panel; continue; }
if ($loose !== []) { $panels[] = ['label' => $panel['label'], 'fields' => $loose, 'slide' => '']; }
// Group panels ARE the slides, in order, so each is tagged with the slide it is
// — the switch below then belongs to a slide rather than to a position.
$slideIds = $sec['slides'] ?? [];
$n = 0;
foreach ($byGroup as $gKey => $gFields) {
$panels[] = ['label' => t_raw($gKey), 'fields' => $gFields, 'slide' => $slideIds[$n] ?? ''];
$n++;
}
}
$accordion = $accordion || count($panels) > 1;
@endphp
@foreach ($panels as $pIdx => $panel)
@php
// Copy left, artwork right when a panel has both — the way these sections are laid
// out on the page itself, and it halves a panel that would otherwise stack eight
// fields vertically.
$media = array_values(array_filter($panel['fields'], static fn (array $f): bool => in_array($f['kind'], ['image', 'video'], true)));
$copy = array_values(array_filter($panel['fields'], static fn (array $f): bool => !in_array($f['kind'], ['image', 'video'], true)));
$split = $media !== [] && $copy !== [];
$cols = $split ? [['col-md-7', $copy], ['col-md-5', $media]] : [['col-12', $panel['fields']]];
// A panel with no name of its own prints no heading: repeating the section's name
// under the fold that already carries it read as the same title three times over.
$pLabel = (string) $panel['label'];
// A slide of a carousel carries its own switch, so one slide can come off the deck.
$pSlide = (string) ($panel['slide'] ?? '');
$pSlideToggle = $pSlide !== ''
? \App\Services\HomeSection::settingKey($slug, $sec['id'] . '_' . $pSlide) : '';
$pSlideOn = $pSlideToggle === '' || setting($pSlideToggle, '1') === '1';
@endphp
@if ($accordion)
{{ $pLabel }}
@if ($pSlideToggle !== '')
@php /* On the summary row, so which slides are live reads at a glance without
opening three folds. data-nofold keeps the click on the switch instead
of letting it open the fold as well — a control inside
toggles the fold too unless it is stopped. */
@endphp
{{ t_raw('admin.pc.visible') }}
@endif
@else
{{ $pLabel }}
@endif
@foreach ($cols as [$colClass, $colFields])
@php // .qm-pc-fields puts a glyph picker on the same line as the
// heading it belongs to, the way the Business-model cards do.
@endphp
@foreach ($colFields as $i => $f)
@php $fid = 'f-' . md5($f['key']); @endphp
@php
// Two fields that belong together share a row — declared in
// PageContent::ROW_PAIRS, so it holds in every language.
$lk = (string) ($f['labelKey'] ?? '');
$next = (string) ($colFields[$i + 1]['labelKey'] ?? '');
$prev = (string) ($colFields[$i - 1]['labelKey'] ?? '');
$half = \App\Services\PageContent::pairsWith($lk, $next)
|| \App\Services\PageContent::pairsWith($prev, $lk);
@endphp
{{ $f['label'] }}
@if ($f['kind'] === 'image' || $f['kind'] === 'video')
@if (!empty($f['opts']['multi']))
@php /* A MULTI field could be added to but never emptied. Each chosen image
renders one `name="…[]"` input, so with no chips left the key vanished
from $_POST entirely — and PageContent::save() iterates POSTED values,
so a declared-but-absent key was never written and the old images came
straight back. This is the same hidden companion the `bool` kind below
already uses: the key is always present, so "none" can be said. PHP
takes the later `…[]` entries over this scalar when any exist. */
@endphp
@endif
{!! media_field_html(
'content[' . $f['key'] . ']',
!empty($f['opts']['multi']) ? array_filter(array_map('trim', explode(',', $f['value']))) : $f['value'],
[
'accept' => $f['kind'] === 'video' ? 'both' : 'image',
'multi' => !empty($f['opts']['multi']),
'allowClear' => true,
'id' => $fid,
]
) !!}
@elseif ($f['kind'] === 'bool')
@php /* Stored as "1"/"" so an unchecked box clears it, matching how every
other content value round-trips through the same text column. */
@endphp
@elseif ($f['kind'] === 'icon')
@partial('pc-icon-field', ['name' => 'content[' . $f['key'] . ']', 'value' => $f['value'], 'id' => $fid, 'label' => $f['label']])
@elseif ($f['kind'] === 'link')
@partial('pc-link-field', ['name' => 'content[' . $f['key'] . ']', 'value' => $f['value'], 'id' => $fid, 'label' => $f['label']])
@elseif ($f['kind'] === 'paragraph')
@else
@endif
@endforeach
@endforeach
{!! $accordion ? '' : '
' !!}
@endforeach
@endforeach
@php /* No section list here. Every section is on the page already, folded and
named, and each carries its own switch — a second copy of the same list
down the right was a third of the screen spent restating it. */
@endphp
@php /* How this page describes itself to a search engine — the same four controls a
CMS page carries, which these four pages had no way to set at all: they are
fixed routes rather than `pages` rows, so nothing keyed by a record id could
ever reach them. Stored once, not per language, like the rest of the SEO
overrides. Nothing here is required; left empty the page's own heading and
the site defaults are used. */
@endphp
{{ t_raw('admin.seo.page_section') }}
{{ t_raw('admin.pages.submit_save') }}