| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- {{-- Вьюха: Форма создания/редактирования блока контента (ACF-подобные поля) --}}
- @extends('admin.layout')
- @section('title', $block->exists ? 'Редактировать блок' : 'Новый блок')
- @section('content_header')
- <div class="d-flex justify-content-between align-items-center">
- <h1 class="m-0">{{ $block->exists ? 'Блок: ' . $block->title : 'Новый блок' }}</h1>
- <a href="{{ route('admin.blocks.index') }}" class="btn btn-default btn-sm">
- <i class="fas fa-arrow-left"></i> Назад
- </a>
- </div>
- @stop
- @section('breadcrumb')
- <li class="breadcrumb-item"><a href="{{ route('admin.dashboard') }}">Главная</a></li>
- <li class="breadcrumb-item"><a href="{{ route('admin.blocks.index') }}">Блоки контента</a></li>
- <li class="breadcrumb-item active">{{ $block->exists ? 'Редактировать' : 'Новый блок' }}</li>
- @stop
- @section('content')
- @if($block->exists)
- <form action="{{ route('admin.blocks.update', $block) }}" method="POST" enctype="multipart/form-data">
- @method('PUT')
- @else
- <form action="{{ route('admin.blocks.store') }}" method="POST" enctype="multipart/form-data">
- @endif
- @csrf
- <div class="row">
- {{-- ── Левая колонка: поля блока ──────────────────────────────── --}}
- <div class="col-md-8">
- {{-- Системные поля (name, title, layout) --}}
- <div class="card card-primary card-outline">
- <div class="card-header"><h3 class="card-title">Идентификация</h3></div>
- <div class="card-body">
- <div class="form-group">
- <label>Название <span class="text-danger">*</span></label>
- <input type="text" name="title"
- class="form-control @error('title') is-invalid @enderror"
- value="{{ old('title', $block->title) }}" required>
- @error('title')<div class="invalid-feedback">{{ $message }}</div>@enderror
- </div>
- <div class="form-group">
- <label>
- Системное имя <span class="text-danger">*</span>
- <small class="text-muted">— только латиница, цифры и _</small>
- </label>
- <input type="text" name="name"
- class="form-control @error('name') is-invalid @enderror"
- value="{{ old('name', $block->name) }}"
- {{ $block->exists ? 'readonly' : '' }}
- placeholder="например: why_us" required>
- @error('name')<div class="invalid-feedback">{{ $message }}</div>@enderror
- @if($block->exists)
- <small class="text-muted">Системное имя нельзя изменить после создания.</small>
- @endif
- </div>
- @if($block->exists)
- {{-- Макет заблокирован: показываем только для чтения --}}
- <input type="hidden" name="layout" value="{{ $block->layout }}">
- <div class="form-group">
- <label>Макет блока</label>
- <input type="text" class="form-control"
- value="{{ $layoutDef['title'] ?? $block->layout }}" readonly>
- <small class="text-muted">Макет нельзя изменить после создания.</small>
- </div>
- @else
- {{-- Выбор макета при создании --}}
- <div class="form-group">
- <label>Макет блока <span class="text-danger">*</span></label>
- <select name="layout" id="layout-select"
- class="form-control @error('layout') is-invalid @enderror" required>
- <option value="">— выберите макет —</option>
- @foreach($layouts as $key => $layout)
- <option value="{{ $key }}"
- {{ old('layout') === $key ? 'selected' : '' }}>
- {{ $layout['title'] }}
- </option>
- @endforeach
- </select>
- @error('layout')<div class="invalid-feedback">{{ $message }}</div>@enderror
- <small class="text-muted">Определяет, какие поля нужно заполнить.</small>
- </div>
- @endif
- </div>
- </div>
- {{-- Содержимое: поля по макету --}}
- <div class="card card-success card-outline" id="block-fields-card"
- style="{{ (!$block->exists && !old('layout')) ? 'display:none' : '' }}">
- <div class="card-header"><h3 class="card-title">Содержимое блока</h3></div>
- <div class="card-body">
- @if($block->exists && $layoutDef)
- {{-- Редактирование: макет известен, рендерим сразу --}}
- @include('admin.blocks._fields', [
- 'fields' => $layoutDef['fields'],
- 'prefix' => 'data',
- 'values' => old('data', $block->data ?? []),
- ])
- @else
- {{-- Создание: рендерим поля для каждого макета, JS показывает нужный --}}
- @foreach($layouts as $key => $layout)
- <div class="layout-fields-set {{ old('layout') === $key ? '' : 'd-none' }}"
- data-layout="{{ $key }}">
- @include('admin.blocks._fields', [
- 'fields' => $layout['fields'],
- 'prefix' => 'data',
- 'values' => old('data', []),
- ])
- </div>
- @endforeach
- @endif
- </div>
- </div>
- </div>
- {{-- ── Правая колонка: настройки ───────────────────────────────── --}}
- <div class="col-md-4">
- <div class="card card-secondary card-outline">
- <div class="card-header"><h3 class="card-title">Настройки</h3></div>
- <div class="card-body">
- <div class="custom-control custom-switch">
- <input type="checkbox" class="custom-control-input" id="is_active"
- name="is_active" value="1"
- {{ old('is_active', $block->is_active ?? true) ? 'checked' : '' }}>
- <label class="custom-control-label" for="is_active">Блок активен</label>
- </div>
- @if($block->exists && $block->layout)
- <hr>
- <small class="text-muted d-block">
- Подключение на Blade-странице:
- </small>
- @php
- $blockHint = '{!! \App\Models\Block::getByName(\'' . $block->name . '\')?->render() !!}';
- @endphp
- <code class="d-block mt-1 small">{{ $blockHint }}</code>
- @endif
- </div>
- <div class="card-footer">
- <button type="submit" class="btn btn-primary btn-block">
- <i class="fas fa-save"></i> Сохранить
- </button>
- <a href="{{ route('admin.blocks.index') }}" class="btn btn-secondary btn-block mt-1">
- Отмена
- </a>
- </div>
- </div>
- </div>
- </div>
- </form>
- @stop
- @push('js')
- <script>
- $(document).ready(function () {
- // ── Переключение полей при смене макета (только создание) ──────────────
- $('#layout-select').on('change', function () {
- var val = $(this).val();
- $('.layout-fields-set').addClass('d-none');
- if (val) {
- $('[data-layout="' + val + '"]').removeClass('d-none');
- $('#block-fields-card').show();
- } else {
- $('#block-fields-card').hide();
- }
- });
- // ── Превью загружаемого изображения ───────────────────────────────────
- $(document).on('change', '.js-img-upload', function () {
- var wrap = $(this).closest('.form-group');
- var preview = wrap.find('.js-img-preview-new');
- var file = this.files[0];
- if (!file) return;
- // Обновляем лейбл кнопки
- $(this).siblings('.custom-file-label').text(file.name);
- // Читаем файл и показываем превью
- var reader = new FileReader();
- reader.onload = function (e) {
- preview.find('img').attr('src', e.target.result);
- preview.find('.js-img-new-name').text(file.name);
- preview.show();
- // Скрываем старое превью (заменяется)
- wrap.find('.js-img-preview-current').hide();
- };
- reader.readAsDataURL(file);
- });
- // ── Repeater: добавить строку ──────────────────────────────────────────
- $(document).on('click', '.btn-add-repeater-row', function () {
- var repName = $(this).data('repeater');
- var rowsContainer = $('#repeater-rows-' + repName);
- var template = $('#repeater-tpl-' + repName).html();
- var newIndex = rowsContainer.find('.repeater-row').length;
- // Заменяем __IDX__ на реальный порядковый индекс
- var html = template.replace(/__IDX__/g, newIndex);
- rowsContainer.append(html);
- });
- // ── Repeater: удалить строку ───────────────────────────────────────────
- $(document).on('click', '.btn-remove-repeater-row', function () {
- $(this).closest('.repeater-row').remove();
- });
- });
- </script>
- @endpush
|