| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- {{-- Вьюха: Мастер генерации макета блока из HTML --}}
- @extends('admin.layout')
- @section('title', 'Генератор макета блока')
- @section('content_header')
- <div class="d-flex justify-content-between align-items-center">
- <h1 class="m-0">Генератор макета блока</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">Генератор макета</li>
- @stop
- @section('content')
- @if(session('success'))
- <div class="alert alert-success alert-dismissible">
- <button type="button" class="close" data-dismiss="alert">×</button>
- {{ session('success') }}
- </div>
- @endif
- {{-- ════════════════════════════════════════════════════════════════════════ --}}
- {{-- ШАГ 1: вставляем HTML --}}
- {{-- ════════════════════════════════════════════════════════════════════════ --}}
- @if($parsed === null)
- <div class="row">
- <div class="col-md-8">
- <div class="card card-primary card-outline">
- <div class="card-header"><h3 class="card-title">Шаг 1 — Вставьте HTML секции</h3></div>
- <form action="{{ route('admin.blocks.wizard.analyze') }}" method="POST">
- @csrf
- <div class="card-body">
- <div class="row">
- <div class="col-md-6">
- <div class="form-group">
- <label>Системное имя макета <span class="text-danger">*</span>
- <small class="text-muted">— латиница и _</small>
- </label>
- <input type="text" name="layout_name"
- class="form-control @error('layout_name') is-invalid @enderror"
- value="{{ old('layout_name') }}"
- placeholder="hero_banner">
- @error('layout_name')<div class="invalid-feedback">{{ $message }}</div>@enderror
- </div>
- </div>
- <div class="col-md-6">
- <div class="form-group">
- <label>Название макета <span class="text-danger">*</span></label>
- <input type="text" name="layout_title"
- class="form-control @error('layout_title') is-invalid @enderror"
- value="{{ old('layout_title') }}"
- placeholder="Главный баннер">
- @error('layout_title')<div class="invalid-feedback">{{ $message }}</div>@enderror
- </div>
- </div>
- </div>
- <div class="form-group">
- <label>HTML секции <span class="text-danger">*</span></label>
- <textarea name="html" rows="18"
- class="form-control text-monospace @error('html') is-invalid @enderror"
- placeholder="Вставьте HTML-разметку секции или повторяющихся карточек...">{{ old('html') }}</textarea>
- @error('html')<div class="invalid-feedback">{{ $message }}</div>@enderror
- <small class="text-muted d-block mt-1">
- Можно вставить как одну секцию целиком, так и несколько однотипных карточек.
- Парсер сам определит структуру.
- </small>
- </div>
- </div>
- <div class="card-footer">
- <button type="submit" class="btn btn-primary">
- <i class="fas fa-search"></i> Анализировать HTML
- </button>
- </div>
- </form>
- </div>
- </div>
- <div class="col-md-4">
- <div class="card card-info card-outline">
- <div class="card-header"><h3 class="card-title">Как это работает</h3></div>
- <div class="card-body text-sm">
- <p><strong>1.</strong> Вставьте HTML-код секции.</p>
- <p><strong>2.</strong> Парсер найдёт все текстовые элементы, заголовки, ссылки, картинки и повторяющиеся блоки.</p>
- <p><strong>3.</strong> Вы увидите список полей и черновик Blade-шаблона. Всё можно отредактировать.</p>
- <p><strong>4.</strong> После подтверждения создаётся файл макета и Blade-шаблон. Макет появится в дропдауне при создании блока.</p>
- <hr>
- <p class="text-muted small">
- Поддерживаемые теги: <code>h1–h6</code>, <code>p</code>, <code>a</code>, <code>img</code>, любые листовые элементы с текстом.
- </p>
- </div>
- </div>
- </div>
- </div>
- {{-- ════════════════════════════════════════════════════════════════════════ --}}
- {{-- ШАГ 2: review и сохранение --}}
- {{-- ════════════════════════════════════════════════════════════════════════ --}}
- @else
- @php
- $isRepeater = $parsed['is_repeater'];
- $fields = $parsed['fields'];
- @endphp
- <form action="{{ route('admin.blocks.wizard.generate') }}" method="POST">
- @csrf
- <input type="hidden" name="layout_name" value="{{ $layout_name }}">
- <input type="hidden" name="layout_title" value="{{ $layout_title }}">
- <input type="hidden" name="is_repeater" value="{{ $isRepeater ? 1 : 0 }}">
- <div class="row">
- {{-- ── Левая колонка: поля ───────────────────────────────────────── --}}
- <div class="col-md-6">
- {{-- Обнаруженная структура --}}
- <div class="alert {{ $isRepeater ? 'alert-info' : 'alert-success' }}">
- <i class="fas fa-{{ $isRepeater ? 'layer-group' : 'align-left' }}"></i>
- @if($isRepeater)
- <strong>Обнаружены повторяющиеся элементы.</strong>
- Добавлено поле <code>items</code> типа repeater.
- @else
- <strong>Плоская структура.</strong>
- Обнаружено {{ count($fields) }} {{ trans_choice('поле|поля|полей', count($fields)) }}.
- @endif
- </div>
- {{-- Плоские поля (не repeater) --}}
- @php
- $flatFields = collect($fields)->where('type', '!=', 'repeater')->values()->all();
- $repeaterField = collect($fields)->firstWhere('type', 'repeater');
- @endphp
- @if(count($flatFields) > 0)
- <div class="card card-success card-outline">
- <div class="card-header"><h3 class="card-title">Поля блока</h3></div>
- <div class="card-body p-0">
- <table class="table table-sm mb-0">
- <thead><tr>
- <th>Системное имя</th>
- <th>Название</th>
- <th>Тип</th>
- </tr></thead>
- <tbody>
- @foreach($flatFields as $i => $field)
- <tr>
- <td>
- <input type="text" name="flat_fields[{{ $i }}][name]"
- class="form-control form-control-sm"
- value="{{ $field['name'] }}">
- </td>
- <td>
- <input type="text" name="flat_fields[{{ $i }}][label]"
- class="form-control form-control-sm"
- value="{{ $field['label'] }}">
- </td>
- <td>
- <select name="flat_fields[{{ $i }}][type]" class="form-control form-control-sm">
- @foreach(['text','textarea','url','image'] as $t)
- <option value="{{ $t }}" {{ $field['type'] === $t ? 'selected' : '' }}>{{ $t }}</option>
- @endforeach
- </select>
- </td>
- </tr>
- @endforeach
- </tbody>
- </table>
- </div>
- </div>
- @endif
- {{-- Repeater-поле и его sub_fields --}}
- @if($repeaterField)
- <div class="card card-info card-outline">
- <div class="card-header">
- <h3 class="card-title">Repeater-группа</h3>
- </div>
- <div class="card-body">
- <div class="row mb-2">
- <div class="col-6">
- <label class="small text-muted">Системное имя</label>
- <input type="text" name="repeater_name"
- class="form-control form-control-sm"
- value="{{ $repeaterField['name'] }}">
- </div>
- <div class="col-6">
- <label class="small text-muted">Название</label>
- <input type="text" name="repeater_label"
- class="form-control form-control-sm"
- value="{{ $repeaterField['label'] }}">
- </div>
- </div>
- <label class="font-weight-bold small">Дочерние поля (sub_fields):</label>
- <table class="table table-sm mb-0">
- <thead><tr>
- <th>Системное имя</th>
- <th>Название</th>
- <th>Тип</th>
- </tr></thead>
- <tbody>
- @foreach($repeaterField['sub_fields'] as $j => $sub)
- <tr>
- <td>
- <input type="text" name="sub_fields[{{ $j }}][name]"
- class="form-control form-control-sm"
- value="{{ $sub['name'] }}">
- </td>
- <td>
- <input type="text" name="sub_fields[{{ $j }}][label]"
- class="form-control form-control-sm"
- value="{{ $sub['label'] }}">
- </td>
- <td>
- <select name="sub_fields[{{ $j }}][type]" class="form-control form-control-sm">
- @foreach(['text','textarea','url','image'] as $t)
- <option value="{{ $t }}" {{ $sub['type'] === $t ? 'selected' : '' }}>{{ $t }}</option>
- @endforeach
- </select>
- </td>
- </tr>
- @endforeach
- </tbody>
- </table>
- </div>
- </div>
- @endif
- {{-- Мета --}}
- <div class="card card-secondary card-outline">
- <div class="card-body">
- <div class="row">
- <div class="col-6">
- <label class="small text-muted">Системное имя макета</label>
- <input type="text" class="form-control form-control-sm" value="{{ $layout_name }}" readonly>
- </div>
- <div class="col-6">
- <label class="small text-muted">Название макета</label>
- <input type="text" class="form-control form-control-sm" value="{{ $layout_title }}" readonly>
- </div>
- </div>
- </div>
- <div class="card-footer">
- <button type="submit" class="btn btn-success btn-block">
- <i class="fas fa-save"></i> Сохранить макет и Blade-шаблон
- </button>
- <a href="{{ route('admin.blocks.wizard') }}" class="btn btn-secondary btn-block mt-1">
- <i class="fas fa-redo"></i> Начать заново
- </a>
- </div>
- </div>
- </div>
- {{-- ── Правая колонка: Blade-шаблон ─────────────────────────────── --}}
- <div class="col-md-6">
- <div class="card card-warning card-outline">
- <div class="card-header d-flex justify-content-between align-items-center">
- <h3 class="card-title">Черновик Blade-шаблона</h3>
- <small class="text-muted">можно редактировать</small>
- </div>
- <div class="card-body p-0">
- <textarea name="blade" rows="30"
- class="form-control text-monospace border-0"
- style="border-radius:0;font-size:12px;resize:vertical">{{ $parsed['blade'] }}</textarea>
- </div>
- <div class="card-footer text-muted small">
- Файл будет сохранён в
- <code>resources/views/blocks/{{ $layout_name }}.blade.php</code>
- </div>
- </div>
- </div>
- </div>
- </form>
- @endif
- @stop
|