index.blade.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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. <p><strong>Анимации</strong> — class="no-animations" на &lt;body&gt;, reveal-блоки видны сразу</p>
  162. <hr>
  163. <p class="mb-0 text-info">
  164. <i class="fas fa-info-circle"></i>
  165. Незаполненные поля скрываются на сайте автоматически.
  166. </p>
  167. </div>
  168. </div>
  169. </div>
  170. </div>
  171. </form>
  172. @stop
  173. @push('js')
  174. <script>
  175. // ── Аккордеон карточек настроек (только левая колонка) ──────────────────────
  176. $(function () {
  177. // Все карточки левой колонки у которых есть кнопка сворачивания
  178. var $cards = $('.col-md-8 [data-card-widget="collapse"]').closest('.card');
  179. // Сворачиваем все кроме первой (без анимации — чтобы не мигало при загрузке)
  180. $cards.each(function (i) {
  181. if (i > 0) {
  182. $(this).addClass('collapsed-card');
  183. $(this).find('[data-card-widget="collapse"] i')
  184. .removeClass('fa-minus').addClass('fa-plus');
  185. $(this).find('.card-body, .card-footer').hide();
  186. }
  187. });
  188. // При разворачивании карточки — сворачиваем все остальные в колонке
  189. $(document).on('expanded.lte.cardwidget', '.col-md-8 .card', function () {
  190. var $opened = $(this);
  191. $cards.each(function () {
  192. if (!$(this).is($opened) && !$(this).hasClass('collapsed-card')) {
  193. $(this).find('[data-card-widget="collapse"]').trigger('click');
  194. }
  195. });
  196. });
  197. });
  198. // Счётчик символов в поле og_description
  199. (function () {
  200. var ta = document.querySelector('textarea[name=og_description]');
  201. var counter = document.getElementById('og-desc-count');
  202. if (!ta || !counter) return;
  203. ta.addEventListener('input', function () {
  204. var len = this.value.length;
  205. counter.textContent = len + '/300';
  206. counter.className = len > 200 ? 'text-warning' : 'text-muted';
  207. });
  208. })();
  209. // Показываем имя выбранного файла в custom-file-input
  210. document.querySelectorAll('.custom-file-input').forEach(function(input) {
  211. input.addEventListener('change', function() {
  212. var label = this.nextElementSibling;
  213. label.textContent = this.files[0] ? this.files[0].name : 'Выбрать файл';
  214. });
  215. });
  216. // Маска телефона
  217. (function () {
  218. var el = document.querySelector('input[name=phone]');
  219. if (!el) return;
  220. el.setAttribute('maxlength', '18');
  221. function fmt(d) {
  222. var out = '+7';
  223. if (d.length > 0) out += ' (' + d.slice(0, 3);
  224. if (d.length >= 3) out += ')';
  225. if (d.length > 3) out += ' ' + d.slice(3, 6);
  226. if (d.length > 6) out += '-' + d.slice(6, 8);
  227. if (d.length > 8) out += '-' + d.slice(8, 10);
  228. return out;
  229. }
  230. function digits() { return el.value.replace(/\D/g, '').replace(/^[78]/, ''); }
  231. el.addEventListener('focus', function () { if (!this.value) this.value = '+7'; });
  232. el.addEventListener('blur', function () { if (digits().length === 0) this.value = ''; });
  233. el.addEventListener('keydown', function (e) {
  234. if (e.ctrlKey || e.metaKey) return;
  235. if (['Tab','Enter','ArrowLeft','ArrowRight','Home','End'].includes(e.key)) return;
  236. e.preventDefault();
  237. var d = digits();
  238. if (e.key === 'Backspace') { d = d.slice(0, -1); }
  239. else if (/^\d$/.test(e.key) && d.length < 10) { d += e.key; }
  240. else { return; }
  241. this.value = fmt(d);
  242. });
  243. el.addEventListener('paste', function (e) {
  244. e.preventDefault();
  245. var text = (e.clipboardData || window.clipboardData).getData('text');
  246. var d = (digits() + text.replace(/\D/g, '').replace(/^[78]/, '')).slice(0, 10);
  247. this.value = fmt(d);
  248. });
  249. })();
  250. </script>
  251. @endpush