переработал систему модалок и добавил блоки

This commit is contained in:
GP_DEV
2025-06-07 23:28:58 +03:00
parent decc7c470a
commit f23ac49f97
6 changed files with 224 additions and 171 deletions

View File

@@ -29,41 +29,63 @@ if (!function_exists('get_club_cards_for_current_language')) {
} }
$cards = get_club_cards_for_current_language(); $cards = get_club_cards_for_current_language();
$heading = get_field('heading', $block['id']);
?> ?>
<div id="<?php echo esc_attr($block_id); ?>" class="container mx-auto mt-[24px] <?php echo esc_attr($class_name); ?>"> <section id="<?php echo esc_attr($block_id); ?>" class="<?php echo esc_attr($class_name); ?>">
<?php if ($cards): ?> <div class="container mx-auto mt-[24px]">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-[24px]"> <?php if ($heading) : ?>
<?php foreach ($cards as $card): ?> <h2 class="text-[32px] font-bold mt-[24px]"><?php echo esc_html($heading); ?></h2>
<div class="club-card rounded-[8px] overflow-hidden border transition-shadow "> <?php endif; ?>
<?php if (has_post_thumbnail($card->ID)): ?> <?php if ($cards): ?>
<div class="aspect-video overflow-hidden"> <div class="mt-[24px] grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-[30px] max-[768px]:gap-[20px]">
<?php echo get_the_post_thumbnail($card->ID, 'medium', ['class' => 'w-full h-full object-cover']); ?> <?php foreach ($cards as $card): ?>
</div> <div class="bg-[#ffffff] border-[1px] border-[#e5e7eb] rounded-[16px] overflow-hidden shadow-lg hover:shadow-xl transition-shadow ">
<?php endif; ?> <?php
$card_image = get_field('image', $card->ID);
<div class="p-[24px]"> if ($card_image): ?>
<h3 class="text-[20px] font-semibold mb-[12px]"> <div class="overflow-hidden max-w-[60px] max-h-[60px] mx-auto mt-[22px] rounded-full">
<?php echo get_the_title($card->ID); ?> <img src="<?php echo esc_url($card_image['url']); ?>"
</h3> alt="<?php echo esc_attr($card_image['alt']); ?>"
class="w-full h-full object-cover" />
<?php if (get_the_excerpt($card->ID)): ?>
<div class="text-gray-600 mb-[16px]">
<?php echo get_the_excerpt($card->ID); ?>
</div> </div>
<?php endif; ?> <?php endif; ?>
<div class="p-[30px] max-[768px]:p-[20px]">
<?php $card_heading = get_field('heading', $card->ID); ?>
<?php if ($card_heading): ?>
<h3 class="text-[24px] max-[768px]:text-[20px] font-semibold text-[#1f2937] mb-[16px] text-center">
<?php echo esc_html($card_heading); ?>
</h3>
<?php endif; ?>
<div class="text-center"> <?php $card_description = get_field('description', $card->ID); ?>
<button data-modal="club-card" <?php if ($card_description): ?>
data-card-id="<?php echo $card->ID; ?>" <div class="text-[16px] max-[768px]:text-[14px] text-[#6b7280] leading-[150%] text-center mb-[16px]">
class="inline-block px-[24px] py-[12px] bg-blue-500 text-white rounded-[6px] hover:bg-blue-600 transition-colors "> <?php echo wp_kses_post($card_description); ?>
Подробнее </div>
</button> <?php endif; ?>
<?php $card_price = get_field('price', $card->ID); ?>
<?php if ($card_price): ?>
<div class="text-[20px] max-[768px]:text-[18px] font-bold text-[#1f2937] text-center mb-[24px]">
<span>От</span> <?php echo esc_html($card_price); ?> Р.
</div>
<?php endif; ?>
<div class="text-center mt-auto">
<?php $popup_button = get_field('popup_button', $card->ID); ?>
<button data-modal="club-card"
data-card-id="<?php echo $card->ID; ?>"
class="inline-block cursor-pointer px-[24px] py-[12px] bg-[#3b82f6] text-white rounded-[8px] hover:bg-[#2563eb] transition-colors ">
<?php echo $popup_button ? esc_html($popup_button) : 'Подробнее'; ?>
</button>
</div>
</div> </div>
</div> </div>
</div> <?php endforeach; ?>
<?php endforeach; ?> </div>
</div> <?php endif; ?>
<?php endif; ?> </div>
</div> </section>

View File

@@ -31,7 +31,7 @@ $tiles_repeater = get_field('tiles_repeater');
<?php if ($tiles_repeater) : ?> <?php if ($tiles_repeater) : ?>
<div class="mt-[24px] grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-[30px] max-[768px]:gap-[20px]"> <div class="mt-[24px] grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-[30px] max-[768px]:gap-[20px]">
<?php foreach ($tiles_repeater as $tile) : ?> <?php foreach ($tiles_repeater as $tile) : ?>
<div class="bg-[#ffffff] border-[1px] border-[#e5e7eb] rounded-[16px] p-[30px] max-[768px]:p-[20px] shadow-lg hover:shadow-xl transition-shadow duration-300"> <div class="bg-[#ffffff] border-[1px] border-[#e5e7eb] rounded-[16px] p-[30px] max-[768px]:p-[20px] shadow-lg hover:shadow-xl transition-shadow ">
<?php if (!empty($tile['image'])) : ?> <?php if (!empty($tile['image'])) : ?>
<div class="w-[80px] h-[80px] rounded-full overflow-hidden mb-[20px] mx-auto bg-[#f3f4f6] flex items-center justify-center"> <div class="w-[80px] h-[80px] rounded-full overflow-hidden mb-[20px] mx-auto bg-[#f3f4f6] flex items-center justify-center">

View File

@@ -73,6 +73,29 @@ function register_acf_blocks() {
), ),
)); ));
acf_register_block_type(array(
'name' => 'form-block',
'title' => __('Блок формы'),
'description' => __('Блок формы обратной связи'),
'render_template' => 'template-parts/la-components/blocks/form-block/form-block.php',
'category' => 'theme-blocks',
'icon' => 'id-alt',
'keywords' => array('форма', 'форма записи', 'имя', 'телефон'),
'supports' => array(
'align' => array('wide', 'full'),
'anchor' => true,
'customClassName' => true,
),
'enqueue_assets' => function() {
wp_enqueue_style(
'form-block-css',
get_template_directory_uri() . '/template-parts/la-components/blocks/form-block/form-block.css',
[],
'1.0.0'
);
}
));
acf_register_block_type(array( acf_register_block_type(array(
'name' => 'tiles-block', 'name' => 'tiles-block',
'title' => __('Блок с плитками'), 'title' => __('Блок с плитками'),
@@ -88,6 +111,22 @@ function register_acf_blocks() {
), ),
)); ));
acf_register_block_type(array(
'name' => 'advantages-block',
'title' => __('Блок преимуществ'),
'description' => __('Блок с преимуществами'),
'render_template' => 'template-parts/la-components/blocks/advantages-block/advantages-block.php',
'category' => 'theme-blocks',
'icon' => 'grid-view',
'keywords' => array('преимущества', 'карточки', 'advantages', 'преимущество'),
'supports' => array(
'align' => array('wide', 'full'),
'anchor' => true,
'customClassName' => true,
),
));
acf_register_block_type(array( acf_register_block_type(array(
'name' => 'reviews-block', 'name' => 'reviews-block',
'title' => __('Блок с отзывами'), 'title' => __('Блок с отзывами'),

View File

@@ -5,15 +5,13 @@ function enqueue_theme_scripts() {
'modals-js', 'modals-js',
get_template_directory_uri() . '/template-parts/la-components/js/modals.js', get_template_directory_uri() . '/template-parts/la-components/js/modals.js',
array('jquery'), array('jquery'),
'1.0.0', '2.0.0',
true true
); );
} }
add_action('wp_enqueue_scripts', 'enqueue_theme_scripts'); add_action('wp_enqueue_scripts', 'enqueue_theme_scripts');
// Вывод всех модалок в футере
function modal_system_container() { function modal_system_container() {
// Получаем список всех модалок
$modals_dir = get_template_directory() . '/template-parts/la-components/modals/'; $modals_dir = get_template_directory() . '/template-parts/la-components/modals/';
$modals = array(); $modals = array();
@@ -26,25 +24,18 @@ function modal_system_container() {
} }
} }
// общий контейнер
?> ?>
<div id="modal-overlay" class="fixed inset-0 bg-[rgba(0,0,0,0.5)] backdrop-blur-sm z-50 flex items-center justify-center p-4 opacity-0 invisible transition-all duration-300"> <div id="modal-overlay" class="fixed inset-0 bg-[rgba(0,0,0,0.5)] backdrop-blur-sm z-50 flex items-center justify-center p-4 opacity-0 invisible transition-all duration-300">
<div class="bg-white rounded-lg shadow-2xl max-w-2xl w-full max-h-[90vh] relative transform scale-90 transition-transform duration-300 overflow-hidden"> <div class="bg-white rounded-lg shadow-2xl max-w-2xl w-full max-h-[90vh] relative transform scale-90 transition-transform duration-300 overflow-hidden">
<button id="modal-close" class="absolute top-4 right-4 z-10 w-8 h-8 flex items-center justify-center rounded-full hover:bg-gray-100 transition-colors text-gray-500 hover:text-gray-700"> <button id="modal-close" class="absolute top-4 right-4 z-10 w-8 h-8 flex items-center justify-center rounded-full hover:bg-gray-100 transition-colors text-gray-500 hover:text-gray-700">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg> </svg>
</button> </button>
<div id="modal-content" class="overflow-y-auto max-h-[90vh]"></div>
<!-- Контейнер для контента модалок -->
<div id="modal-content" class="overflow-y-auto max-h-[90vh]">
</div>
</div> </div>
</div> </div>
<div id="modal-templates" class="hidden"> <div id="modal-templates" class="hidden">
<?php foreach ($modals as $modal_name): ?> <?php foreach ($modals as $modal_name): ?>
<div id="modal-template-<?php echo esc_attr($modal_name); ?>" class="modal-template"> <div id="modal-template-<?php echo esc_attr($modal_name); ?>" class="modal-template">

View File

@@ -1,13 +1,13 @@
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
window.ModalSystem = {
const ModalSystem = {
overlay: null, overlay: null,
content: null, content: null,
container: null, container: null,
closeBtn: null, closeBtn: null,
isOpen: false, modalStack: [],
currentModal: null,
init: function() { init() {
this.overlay = document.getElementById('modal-overlay'); this.overlay = document.getElementById('modal-overlay');
if (!this.overlay) return; if (!this.overlay) return;
@@ -16,21 +16,20 @@ document.addEventListener('DOMContentLoaded', function() {
this.closeBtn = document.getElementById('modal-close'); this.closeBtn = document.getElementById('modal-close');
this.bindEvents(); this.bindEvents();
this.initFormHandling();
}, },
bindEvents: function() {
bindEvents() {
if (this.closeBtn) { if (this.closeBtn) {
this.closeBtn.addEventListener('click', () => this.close()); this.closeBtn.addEventListener('click', () => this.close());
} }
this.overlay.addEventListener('click', (e) => { this.overlay.addEventListener('click', (e) => {
if (e.target === this.overlay) { if (e.target === this.overlay) this.close();
this.close();
}
}); });
document.addEventListener('keydown', (e) => { document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && this.isOpen) { if (e.key === 'Escape' && this.isOpen()) this.close();
this.close();
}
}); });
document.addEventListener('click', (e) => { document.addEventListener('click', (e) => {
@@ -38,7 +37,8 @@ document.addEventListener('DOMContentLoaded', function() {
if (modalTrigger) { if (modalTrigger) {
e.preventDefault(); e.preventDefault();
const modalName = modalTrigger.getAttribute('data-modal'); const modalName = modalTrigger.getAttribute('data-modal');
this.open(modalName); const cardId = modalTrigger.getAttribute('data-card-id');
this.open(modalName, { cardId });
} }
}); });
@@ -50,71 +50,140 @@ document.addEventListener('DOMContentLoaded', function() {
}); });
}, },
initFormHandling() {
console.log('Form handling initialized');
open: function(modalName) { document.addEventListener('fluentform_submission_success', (e) => {
if (this.isOpen) { const form = e.target.closest('.ff-el-form-wrapper form');
this.close(); if (form) {
setTimeout(() => {
if (this.isOpen()) {
this.replace('form-success');
} else {
this.open('form-success');
}
}, 300);
}
}, true);
if (typeof jQuery !== 'undefined') {
jQuery(document).ajaxSuccess((event, xhr, settings) => {
if (settings.url && settings.url.includes('admin-ajax.php') &&
settings.data && settings.data.includes('fluentform_submit')) {
try {
const response = JSON.parse(xhr.responseText);
console.log('Response:', response);
if (response.success && response.data && response.data.insert_id) {
setTimeout(() => {
if (this.isOpen()) {
this.replace('form-success');
} else {
this.open('form-success');
}
}, 300);
}
} catch (e) {
}
}
});
} else {
}
},
open(modalName, params = {}) {
const template = document.getElementById(`modal-template-${modalName}`);
if (!template) return;
this.modalStack.push({
name: modalName,
params: params,
content: template.innerHTML
});
this.content.innerHTML = template.innerHTML;
if (this.modalStack.length === 1) {
this.show();
} }
const template = document.getElementById(`modal-template-${modalName}`); this.injectParams(params);
if (!template) { },
console.error(`модальное окно ${modalName} не найдено`);
replace(modalName, params = {}) {
if (this.modalStack.length === 0) {
this.open(modalName, params);
return; return;
} }
this.currentModal = modalName; const template = document.getElementById(`modal-template-${modalName}`);
if (!template) return;
this.modalStack[this.modalStack.length - 1] = {
name: modalName,
params: params,
content: template.innerHTML
};
this.content.innerHTML = template.innerHTML; this.content.innerHTML = template.innerHTML;
this.show(); this.injectParams(params);
}, },
show: function() { injectParams(params) {
if (params.cardId) {
setTimeout(() => {
const hiddenInput = this.content.querySelector('input[name="hidden"]');
if (hiddenInput && !hiddenInput.dataset.cardInjected) {
const currentValue = hiddenInput.value || '';
hiddenInput.value = currentValue + ` | Карта ID: ${params.cardId}`;
hiddenInput.dataset.cardInjected = 'true';
}
}, 100);
}
},
show() {
this.overlay.classList.remove('opacity-0', 'invisible'); this.overlay.classList.remove('opacity-0', 'invisible');
this.overlay.classList.add('opacity-100', 'visible'); this.overlay.classList.add('opacity-100', 'visible');
setTimeout(() => { setTimeout(() => {
this.container.classList.remove('scale-90'); this.container.classList.remove('scale-90');
this.container.classList.add('scale-100'); this.container.classList.add('scale-100');
}, 10); }, 10);
this.isOpen = true;
setTimeout(() => { setTimeout(() => {
this.closeBtn.focus(); if (this.closeBtn) this.closeBtn.focus();
}, 350); }, 350);
}, },
close: function() { close() {
if (!this.isOpen) return; if (this.modalStack.length === 0) return;
this.modalStack.pop();
if (this.modalStack.length > 0) {
const prevModal = this.modalStack[this.modalStack.length - 1];
this.content.innerHTML = prevModal.content;
this.injectParams(prevModal.params);
} else {
this.hide();
}
},
hide() {
this.container.classList.remove('scale-100'); this.container.classList.remove('scale-100');
this.container.classList.add('scale-90'); this.container.classList.add('scale-90');
this.overlay.classList.remove('opacity-100', 'visible'); this.overlay.classList.remove('opacity-100', 'visible');
this.overlay.classList.add('opacity-0', 'invisible'); this.overlay.classList.add('opacity-0', 'invisible');
this.isOpen = false; this.modalStack = [];
this.currentModal = null;
}, },
isOpen() {
getState: function() { return this.modalStack.length > 0;
return {
isOpen: this.isOpen,
currentModal: this.currentModal
};
} }
}; };
ModalSystem.init(); ModalSystem.init();
window.openModal = function(modalName) {
ModalSystem.open(modalName);
};
window.closeModal = function() {
ModalSystem.close();
};
}); });

View File

@@ -1,90 +1,22 @@
<?php
<div class="bg-white max-w-lg w-full rounded-[8px]"> $form_id = '4';
<div class="p-[24px]"> $form_title = 'Заявка на клубную карту';
<h2 class="text-[24px] font-bold text-gray-900 mb-[16px]">
Заказать клубную карту
</h2>
<form class="space-y-[16px]"> $current_url = home_url($_SERVER['REQUEST_URI']);
<div> $page_title = get_the_title() ?: 'Главная страница';
<label for="name" class="block text-[14px] font-medium text-gray-700 mb-[8px]">
Имя *
</label>
<input type="text"
id="name"
name="name"
required
class="w-full px-[12px] py-[8px] border border-gray-300 rounded-[6px] focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div> $hidden_value = "Форма: {$form_title} | Страница: {$page_title} | URL: {$current_url}";
<label for="email" class="block text-[14px] font-medium text-gray-700 mb-[8px]"> ?>
Email *
</label>
<input type="email"
id="email"
name="email"
required
class="w-full px-[12px] py-[8px] border border-gray-300 rounded-[6px] focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div> <div class="p-[30px] max-[768px]:p-[20px]">
<label for="phone" class="block text-[14px] font-medium text-gray-700 mb-[8px]"> <h3 class="text-[24px] max-[768px]:text-[20px] font-bold text-[#1f2937] mb-[24px] text-center">
Телефон * <?php echo esc_html($form_title); ?>
</label> </h3>
<input type="tel"
id="phone"
name="phone"
required
class="w-full px-[12px] py-[8px] border border-gray-300 rounded-[6px] focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div> <div class="form-block-wrapper"
<label for="card-type" class="block text-[14px] font-medium text-gray-700 mb-[8px]"> data-form-id="<?php echo esc_attr($form_id); ?>"
Тип карты data-hidden-value="<?php echo esc_attr($hidden_value); ?>">
</label> <?php echo do_shortcode('[fluentform id="' . esc_attr($form_id) . '"]'); ?>
<select id="card-type"
name="card-type"
class="w-full px-[12px] py-[8px] border border-gray-300 rounded-[6px] focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="">Выберите тип карты</option>
<option value="basic">Базовая</option>
<option value="premium">Премиум</option>
<option value="vip">VIP</option>
</select>
</div>
<div>
<label for="message" class="block text-[14px] font-medium text-gray-700 mb-[8px]">
Комментарий
</label>
<textarea id="message"
name="message"
rows="3"
class="w-full px-[12px] py-[8px] border border-gray-300 rounded-[6px] focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none"></textarea>
</div>
<div class="flex items-center">
<input type="checkbox"
id="agreement"
name="agreement"
required
class="mr-[8px] w-[16px] h-[16px] text-blue-600 border-gray-300 rounded focus:ring-blue-500">
<label for="agreement" class="text-[14px] text-gray-700">
Я согласен с обработкой персональных данных *
</label>
</div>
</form>
<div class="flex justify-end gap-[12px] mt-[24px]">
<button data-modal-close
type="button"
class="px-[24px] py-[12px] bg-gray-500 text-white rounded-[6px] hover:bg-gray-600 transition-colors duration-[300ms]">
Отмена
</button>
<button type="submit"
class="px-[24px] py-[12px] bg-blue-500 text-white rounded-[6px] hover:bg-blue-600 transition-colors duration-[300ms]">
Отправить заявку
</button>
</div>
</div>
</div> </div>
</div>