index.blade.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. {{--
  2. Вьюха: Настройки сайта — все секции сворачиваемые через AdminLTE card-widget="collapse"
  3. Partials (в admin/settings/partials/):
  4. _card_analytics — Яндекс.Метрика и Google Analytics
  5. _card_og — Open Graph метатеги
  6. _card_logos — Логотипы шапки и подвала + кнопка сохранения
  7. _card_site_mode — Режим сайта (обслуживание + noindex)
  8. --}}
  9. @extends('admin.layout')
  10. @section('title', 'Настройки сайта')
  11. @section('content_header')
  12. <h1 class="m-0">Настройки сайта</h1>
  13. @stop
  14. @section('breadcrumb')
  15. <li class="breadcrumb-item"><a href="{{ route('admin.dashboard') }}">Главная</a></li>
  16. <li class="breadcrumb-item active">Настройки</li>
  17. @stop
  18. @section('content')
  19. @if(session('success'))
  20. <div class="alert alert-success alert-dismissible">
  21. <button type="button" class="close" data-dismiss="alert">&times;</button>
  22. {{ session('success') }}
  23. </div>
  24. @endif
  25. <form action="{{ route('admin.settings.update') }}" method="POST" enctype="multipart/form-data">
  26. @csrf
  27. <div class="row">
  28. {{-- Левая колонка --}}
  29. <div class="col-md-8">
  30. {{-- Контакты --}}
  31. <div class="card card-primary card-outline">
  32. <div class="card-header">
  33. <h3 class="card-title">Контакты</h3>
  34. <div class="card-tools">
  35. <button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i></button>
  36. </div>
  37. </div>
  38. <div class="card-body">
  39. <div class="form-group">
  40. <label>Номер телефона</label>
  41. <div class="input-group">
  42. <div class="input-group-prepend"><span class="input-group-text"><i class="fas fa-phone"></i></span></div>
  43. <input type="tel" name="phone" class="form-control @error('phone') is-invalid @enderror"
  44. value="{{ old('phone', $settings['phone'] ?? '') }}" placeholder="+7 (___) ___-__-__">
  45. </div>
  46. @error('phone')<div class="text-danger small mt-1">{{ $message }}</div>@enderror
  47. </div>
  48. <div class="form-group">
  49. <label>Email</label>
  50. <div class="input-group">
  51. <div class="input-group-prepend"><span class="input-group-text"><i class="fas fa-envelope"></i></span></div>
  52. <input type="email" name="email" class="form-control @error('email') is-invalid @enderror"
  53. value="{{ old('email', $settings['email'] ?? '') }}" placeholder="info@example.ru">
  54. </div>
  55. @error('email')<div class="text-danger small mt-1">{{ $message }}</div>@enderror
  56. </div>
  57. <div class="form-group mb-0">
  58. <label>Режим работы</label>
  59. <div class="input-group">
  60. <div class="input-group-prepend"><span class="input-group-text"><i class="fas fa-clock"></i></span></div>
  61. <input type="text" name="working_hours" class="form-control @error('working_hours') is-invalid @enderror"
  62. value="{{ old('working_hours', $settings['working_hours'] ?? '') }}"
  63. placeholder="Пн–Пт: 9:00 – 20:00 | Сб–Вс: 10:00 – 18:00">
  64. </div>
  65. <small class="text-muted">Разделитель строк: | (вертикальная черта)</small>
  66. @error('working_hours')<div class="text-danger small mt-1">{{ $message }}</div>@enderror
  67. </div>
  68. </div>
  69. </div>
  70. {{-- Социальные сети --}}
  71. <div class="card card-secondary card-outline">
  72. <div class="card-header">
  73. <h3 class="card-title">Социальные сети</h3>
  74. <div class="card-tools">
  75. <button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i></button>
  76. </div>
  77. </div>
  78. <div class="card-body">
  79. <div class="form-group">
  80. <label>Telegram</label>
  81. <div class="input-group">
  82. <div class="input-group-prepend"><span class="input-group-text" style="background:#229ED9;color:#fff;border-color:#229ED9">TG</span></div>
  83. <input type="url" name="telegram" class="form-control @error('telegram') is-invalid @enderror"
  84. value="{{ old('telegram', $settings['telegram'] ?? '') }}" placeholder="https://t.me/your_channel">
  85. </div>
  86. @error('telegram')<div class="text-danger small mt-1">{{ $message }}</div>@enderror
  87. </div>
  88. <div class="form-group">
  89. <label>YouTube</label>
  90. <div class="input-group">
  91. <div class="input-group-prepend"><span class="input-group-text" style="background:#FF0000;color:#fff;border-color:#FF0000">YT</span></div>
  92. <input type="url" name="youtube" class="form-control @error('youtube') is-invalid @enderror"
  93. value="{{ old('youtube', $settings['youtube'] ?? '') }}" placeholder="https://youtube.com/@channel">
  94. </div>
  95. @error('youtube')<div class="text-danger small mt-1">{{ $message }}</div>@enderror
  96. </div>
  97. <div class="form-group mb-0">
  98. <label>ВКонтакте</label>
  99. <div class="input-group">
  100. <div class="input-group-prepend"><span class="input-group-text" style="background:#0077FF;color:#fff;border-color:#0077FF">ВК</span></div>
  101. <input type="url" name="vk" class="form-control @error('vk') is-invalid @enderror"
  102. value="{{ old('vk', $settings['vk'] ?? '') }}" placeholder="https://vk.com/your_group">
  103. </div>
  104. @error('vk')<div class="text-danger small mt-1">{{ $message }}</div>@enderror
  105. </div>
  106. </div>
  107. </div>
  108. {{-- Подвал --}}
  109. <div class="card card-secondary card-outline">
  110. <div class="card-header">
  111. <h3 class="card-title">Подвал сайта</h3>
  112. <div class="card-tools">
  113. <button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i></button>
  114. </div>
  115. </div>
  116. <div class="card-body">
  117. <div class="form-group">
  118. <label>Слоган под логотипом в подвале</label>
  119. <input type="text" name="footer_slogan" class="form-control @error('footer_slogan') is-invalid @enderror"
  120. value="{{ old('footer_slogan', $settings['footer_slogan'] ?? '') }}"
  121. placeholder="Автоподбор по России и доставка авто из любой страны под ключ.">
  122. @error('footer_slogan')<div class="text-danger small mt-1">{{ $message }}</div>@enderror
  123. </div>
  124. <div class="form-group mb-0">
  125. <label>Копирайт (строка внизу страницы)</label>
  126. <input type="text" name="copyright" class="form-control @error('copyright') is-invalid @enderror"
  127. value="{{ old('copyright', $settings['copyright'] ?? '') }}"
  128. placeholder="© 2025 Компания. Все права защищены.">
  129. @error('copyright')<div class="text-danger small mt-1">{{ $message }}</div>@enderror
  130. </div>
  131. </div>
  132. </div>
  133. @include('admin.settings.partials._card_analytics')
  134. @include('admin.settings.partials._card_og')
  135. @include('admin.settings.partials._card_logos')
  136. </div>
  137. {{-- Правая колонка --}}
  138. <div class="col-md-4">
  139. @include('admin.settings.partials._card_site_mode')
  140. <div class="card card-secondary card-outline">
  141. <div class="card-header">
  142. <h3 class="card-title">Где используются</h3>
  143. <div class="card-tools">
  144. <button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i></button>
  145. </div>
  146. </div>
  147. <div class="card-body text-muted" style="font-size:13px;line-height:1.9">
  148. <p><strong>Телефон</strong> — topbar, кнопка «Позвонить», подвал, контакты</p>
  149. <p><strong>Email</strong> — topbar, подвал, контакты</p>
  150. <p><strong>Telegram</strong> — кнопка в шапке, подвал, плавающая кнопка, контакты</p>
  151. <p><strong>YouTube / ВК</strong> — topbar, подвал</p>
  152. <p><strong>Режим работы</strong> — страница контактов</p>
  153. <p><strong>Слоган / Копирайт</strong> — подвал сайта</p>
  154. <p><strong>Логотипы</strong> — шапка и подвал</p>
  155. <hr>
  156. <p><strong>Яндекс.Метрика / GA</strong> — &lt;head&gt; всех страниц</p>
  157. <p><strong>OG-изображение</strong> — превью в соцсетях (если нет фото авто)</p>
  158. <hr>
  159. <p><strong>Обслуживание</strong> — заглушка для гостей и редакторов</p>
  160. <p><strong>Noindex</strong> — запрет индексации поисковиками</p>
  161. <hr>
  162. <p class="mb-0 text-info">
  163. <i class="fas fa-info-circle"></i>
  164. Незаполненные поля скрываются на сайте автоматически.
  165. </p>
  166. </div>
  167. </div>
  168. </div>
  169. </div>
  170. </form>
  171. @stop
  172. @push('js')
  173. <script>
  174. // ── Аккордеон карточек настроек (только левая колонка) ──────────────────────
  175. $(function () {
  176. // Все карточки левой колонки у которых есть кнопка сворачивания
  177. var $cards = $('.col-md-8 [data-card-widget="collapse"]').closest('.card');
  178. // Сворачиваем все кроме первой (без анимации — чтобы не мигало при загрузке)
  179. $cards.each(function (i) {
  180. if (i > 0) {
  181. $(this).addClass('collapsed-card');
  182. $(this).find('[data-card-widget="collapse"] i')
  183. .removeClass('fa-minus').addClass('fa-plus');
  184. $(this).find('.card-body, .card-footer').hide();
  185. }
  186. });
  187. // При разворачивании карточки — сворачиваем все остальные в колонке
  188. $(document).on('expanded.lte.cardwidget', '.col-md-8 .card', function () {
  189. var $opened = $(this);
  190. $cards.each(function () {
  191. if (!$(this).is($opened) && !$(this).hasClass('collapsed-card')) {
  192. $(this).find('[data-card-widget="collapse"]').trigger('click');
  193. }
  194. });
  195. });
  196. });
  197. // Счётчик символов в поле og_description
  198. (function () {
  199. var ta = document.querySelector('textarea[name=og_description]');
  200. var counter = document.getElementById('og-desc-count');
  201. if (!ta || !counter) return;
  202. ta.addEventListener('input', function () {
  203. var len = this.value.length;
  204. counter.textContent = len + '/300';
  205. counter.className = len > 200 ? 'text-warning' : 'text-muted';
  206. });
  207. })();
  208. // Показываем имя выбранного файла в custom-file-input
  209. document.querySelectorAll('.custom-file-input').forEach(function(input) {
  210. input.addEventListener('change', function() {
  211. var label = this.nextElementSibling;
  212. label.textContent = this.files[0] ? this.files[0].name : 'Выбрать файл';
  213. });
  214. });
  215. // Маска телефона
  216. (function () {
  217. var el = document.querySelector('input[name=phone]');
  218. if (!el) return;
  219. el.setAttribute('maxlength', '18');
  220. function fmt(d) {
  221. var out = '+7';
  222. if (d.length > 0) out += ' (' + d.slice(0, 3);
  223. if (d.length >= 3) out += ')';
  224. if (d.length > 3) out += ' ' + d.slice(3, 6);
  225. if (d.length > 6) out += '-' + d.slice(6, 8);
  226. if (d.length > 8) out += '-' + d.slice(8, 10);
  227. return out;
  228. }
  229. function digits() { return el.value.replace(/\D/g, '').replace(/^[78]/, ''); }
  230. el.addEventListener('focus', function () { if (!this.value) this.value = '+7'; });
  231. el.addEventListener('blur', function () { if (digits().length === 0) this.value = ''; });
  232. el.addEventListener('keydown', function (e) {
  233. if (e.ctrlKey || e.metaKey) return;
  234. if (['Tab','Enter','ArrowLeft','ArrowRight','Home','End'].includes(e.key)) return;
  235. e.preventDefault();
  236. var d = digits();
  237. if (e.key === 'Backspace') { d = d.slice(0, -1); }
  238. else if (/^\d$/.test(e.key) && d.length < 10) { d += e.key; }
  239. else { return; }
  240. this.value = fmt(d);
  241. });
  242. el.addEventListener('paste', function (e) {
  243. e.preventDefault();
  244. var text = (e.clipboardData || window.clipboardData).getData('text');
  245. var d = (digits() + text.replace(/\D/g, '').replace(/^[78]/, '')).slice(0, 10);
  246. this.value = fmt(d);
  247. });
  248. })();
  249. </script>
  250. @endpush