mirror of
https://github.com/LOBSTERVOVA/Tennis-Site.git
synced 2026-04-17 17:40:49 +03:00
добавил блок с местами, теперь блоки с фильтрами и местами независимы
This commit is contained in:
@@ -97,7 +97,7 @@ public class SecurityConfig {
|
|||||||
.authorizeExchange(exchange -> exchange
|
.authorizeExchange(exchange -> exchange
|
||||||
.anyExchange().permitAll()
|
.anyExchange().permitAll()
|
||||||
)
|
)
|
||||||
.csrf(ServerHttpSecurity.CsrfSpec::disable)
|
// .csrf(ServerHttpSecurity.CsrfSpec::disable)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,16 +19,5 @@ import java.util.Map;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@RequestMapping("/account")
|
@RequestMapping("/account")
|
||||||
public class AccountController {
|
public class AccountController {
|
||||||
@GetMapping("/login")
|
|
||||||
public Mono<Rendering> loginPage() {
|
|
||||||
Map<String, String> model = new HashMap<>();
|
|
||||||
model.put("title", "Login");
|
|
||||||
model.put("index", "login");
|
|
||||||
return Mono.just(
|
|
||||||
Rendering.view("template")
|
|
||||||
.model(model)
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
73
src/main/resources/static/css/places.css
Normal file
73
src/main/resources/static/css/places.css
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
.place-card {
|
||||||
|
border: none;
|
||||||
|
border-radius: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: transform 0.3s, box-shadow 0.3s;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.place-card:hover {
|
||||||
|
transform: translateY(-10px);
|
||||||
|
box-shadow: 0 20px 40px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.place-img {
|
||||||
|
height: 200px;
|
||||||
|
object-fit: cover;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.place-category {
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
right: 15px;
|
||||||
|
padding: 5px 15px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heart-counter {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
background: rgba(255,255,255,0.9);
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heart-counter i {
|
||||||
|
color: #e74c3c;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rating {
|
||||||
|
color: #f1c40f;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-tag {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #e74c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.place-category {
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
right: 15px;
|
||||||
|
padding: 5px 15px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.romantic-badge { background: #FD79A8FF; color: white; }
|
||||||
|
.active-badge { background: #2ECC71FF; color: white; }
|
||||||
|
.intellectual-badge { background: #3498DBFF; color: white; }
|
||||||
|
.horror-badge { background: #2C3E50FF; color: white; }
|
||||||
|
.cozy-badge { background: #E67E22FF; color: white; }
|
||||||
|
.mystery-badge { background: #9B59B6FF; color: white; }
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
@import "fonts.css";
|
@import "fonts.css";
|
||||||
@import "main.css";
|
@import "main.css";
|
||||||
@import "header.css";
|
@import "header.css";
|
||||||
|
@import "places.css";
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ function initHeader($header){
|
|||||||
<!-- Форма входа -->
|
<!-- Форма входа -->
|
||||||
<div class="tab-pane fade show active" id="login" role="tabpanel">
|
<div class="tab-pane fade show active" id="login" role="tabpanel">
|
||||||
<form id="loginForm" method="POST" action="/account/login">
|
<form id="loginForm" method="POST" action="/account/login">
|
||||||
|
<input type="hidden" name="${csrf.parameterName}" value="${csrf.token}" />
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Email или телефон</label>
|
<label class="form-label">Email или телефон</label>
|
||||||
<input type="text" class="form-control" id="loginEmail" placeholder="example@mail.ru" required>
|
<input type="text" class="form-control" id="loginEmail" placeholder="example@mail.ru" required>
|
||||||
|
|||||||
@@ -1,37 +1,35 @@
|
|||||||
function toggleCategoryFilter(filter) {
|
let currentFilters = {category: [], price: [], time: []};
|
||||||
const btn = event.target.closest('.filter-btn');
|
export function initPlaceFilters($filtersContainer) {
|
||||||
|
|
||||||
if (btn.classList.contains('active')) {
|
|
||||||
btn.classList.remove('active');
|
|
||||||
} else {
|
|
||||||
btn.classList.add('active');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function togglePriceFilter(filter) {
|
|
||||||
const btn = event.target.closest('.filter-btn');
|
|
||||||
|
|
||||||
if (btn.classList.contains('active')) {
|
|
||||||
btn.classList.remove('active');
|
|
||||||
} else {
|
|
||||||
btn.classList.add('active');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleTimeFilter(filter) {
|
|
||||||
const btn = event.target.closest('.filter-btn');
|
|
||||||
|
|
||||||
if (btn.classList.contains('active')) {
|
|
||||||
btn.classList.remove('active');
|
|
||||||
} else {
|
|
||||||
btn.classList.add('active');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function initPlaceFilters($filtersContainer) {
|
|
||||||
console.log("init places filters");
|
console.log("init places filters");
|
||||||
|
|
||||||
const $filters = (`
|
// Одна общая функция для всех фильтров
|
||||||
|
function toggleFilter(event) {
|
||||||
|
const $btn = $(event.currentTarget);
|
||||||
|
$btn.toggleClass('active');
|
||||||
|
|
||||||
|
// Можно получить тип и значение фильтра
|
||||||
|
const type = $btn.data('type');
|
||||||
|
const value = $btn.data('value');
|
||||||
|
|
||||||
|
console.log(`Фильтр: ${type} = ${value}, активен: ${$btn.hasClass('active')}`);
|
||||||
|
|
||||||
|
// ОБНОВЛЯЕМ МАССИВ ФИЛЬТРОВ!
|
||||||
|
if ($btn.hasClass('active')) {
|
||||||
|
// Добавляем фильтр, если его еще нет
|
||||||
|
if (!currentFilters[type].includes(value)) {
|
||||||
|
currentFilters[type].push(value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Удаляем фильтр
|
||||||
|
currentFilters[type] = currentFilters[type].filter(item => item !== value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Здесь можно обновить данные или сделать запрос
|
||||||
|
// Триггерим событие изменения фильтров
|
||||||
|
$(document).trigger('filtersChanged', [currentFilters]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const $filters = $(`
|
||||||
<section class="py-5">
|
<section class="py-5">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="filter-card">
|
<div class="filter-card">
|
||||||
@@ -40,22 +38,22 @@ function initPlaceFilters($filtersContainer) {
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h5 class="mb-3">Тип свидания</h5>
|
<h5 class="mb-3">Тип свидания</h5>
|
||||||
<div class="d-flex flex-wrap mb-4">
|
<div class="d-flex flex-wrap mb-4">
|
||||||
<div class="filter-btn category-romantic active" onclick="toggleCategoryFilter('ROMANTIC')">
|
<div class="filter-btn category-romantic" data-type="category" data-value="ROMANTIC">
|
||||||
<i class="fas fa-heart me-2"></i>Романтическое
|
<i class="fas fa-heart me-2"></i>Романтическое
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-btn category-active" onclick="toggleCategoryFilter('ACTIVE')">
|
<div class="filter-btn category-active" data-type="category" data-value="ACTIVE">
|
||||||
<i class="fas fa-hiking me-2"></i>Активное
|
<i class="fas fa-hiking me-2"></i>Активное
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-btn category-intellectual" onclick="toggleCategoryFilter('INTELLECTUAL')">
|
<div class="filter-btn category-intellectual" data-type="category" data-value="INTELLECTUAL">
|
||||||
<i class="fas fa-brain me-2"></i>Интеллектуальное
|
<i class="fas fa-brain me-2"></i>Интеллектуальное
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-btn category-horror" onclick="toggleCategoryFilter('HORROR')">
|
<div class="filter-btn category-horror" data-type="category" data-value="HORROR">
|
||||||
<i class="fas fa-ghost me-2"></i>Хоррор
|
<i class="fas fa-ghost me-2"></i>Хоррор
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-btn category-cozy" onclick="toggleCategoryFilter('COZY')">
|
<div class="filter-btn category-cozy" data-type="category" data-value="COZY">
|
||||||
<i class="fas fa-mug-hot me-2"></i>Уютное
|
<i class="fas fa-mug-hot me-2"></i>Уютное
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-btn category-mystery" onclick="toggleCategoryFilter('MYSTERY')">
|
<div class="filter-btn category-mystery" data-type="category" data-value="MYSTERY">
|
||||||
<i class="fas fa-search me-2"></i>Тайна
|
<i class="fas fa-search me-2"></i>Тайна
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -63,23 +61,23 @@ function initPlaceFilters($filtersContainer) {
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h5 class="mb-3">Бюджет</h5>
|
<h5 class="mb-3">Бюджет</h5>
|
||||||
<div class="d-flex flex-wrap mb-4">
|
<div class="d-flex flex-wrap mb-4">
|
||||||
<div class="filter-btn category-budget" onclick="togglePriceFilter('BUDGET')">
|
<div class="filter-btn category-budget" data-type="price" data-value="BUDGET">
|
||||||
<i class="fas fa-wallet me-2"></i>Эконом (до 2,000₽)
|
<i class="fas fa-wallet me-2"></i>Эконом (до 2,000₽)
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-btn category-luxury" onclick="togglePriceFilter('LUXURY')">
|
<div class="filter-btn category-luxury" data-type="price" data-value="LUXURY">
|
||||||
<i class="fas fa-gem me-2"></i>Премиум (от 5,000₽)
|
<i class="fas fa-gem me-2"></i>Премиум (от 5,000₽)
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h5 class="mb-3">Время</h5>
|
<h5 class="mb-3">Время</h5>
|
||||||
<div class="d-flex flex-wrap">
|
<div class="d-flex flex-wrap">
|
||||||
<div class="filter-btn" onclick="toggleTimeFilter('DAY')">
|
<div class="filter-btn" data-type="time" data-value="DAY">
|
||||||
<i class="fas fa-sun me-2"></i>День
|
<i class="fas fa-sun me-2"></i>День
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-btn" onclick="toggleTimeFilter('EVENING')">
|
<div class="filter-btn" data-type="time" data-value="EVENING">
|
||||||
<i class="fas fa-moon me-2"></i>Вечер
|
<i class="fas fa-moon me-2"></i>Вечер
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-btn" onclick="toggleTimeFilter('NIGHT')">
|
<div class="filter-btn" data-type="time" data-value="NIGHT">
|
||||||
<i class="fas fa-star me-2"></i>Ночь
|
<i class="fas fa-star me-2"></i>Ночь
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -89,5 +87,9 @@ function initPlaceFilters($filtersContainer) {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
// Вешаем один обработчик на все кнопки
|
||||||
|
$filters.on('click', '.filter-btn', toggleFilter);
|
||||||
|
|
||||||
$filtersContainer.append($filters);
|
$filtersContainer.append($filters);
|
||||||
}
|
}
|
||||||
35
src/main/resources/static/js/site/blocks/places-block.js
Normal file
35
src/main/resources/static/js/site/blocks/places-block.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import {createCard} from "./single-place-card.js";
|
||||||
|
|
||||||
|
export function initPlacesBlock($container) {
|
||||||
|
console.log("initPlacesBlock")
|
||||||
|
$container.append(
|
||||||
|
$(`
|
||||||
|
<div class="container">
|
||||||
|
<div class="row" id="placesContainer">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`)
|
||||||
|
)
|
||||||
|
|
||||||
|
function loadPlaces(filters = {}) {
|
||||||
|
$('#placesContainer').empty().append('<div class="text-center">Загрузка...</div>');
|
||||||
|
|
||||||
|
// Задержка 500ms перед отрисовкой
|
||||||
|
setTimeout(() => {
|
||||||
|
$('#placesContainer').empty();
|
||||||
|
console.log("новые фильтры в loadPlaces: ", filters)
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
$('#placesContainer').append($(createCard()));
|
||||||
|
}
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on('filtersChanged', (e, filters) => {
|
||||||
|
console.log('Фильтры изменились:', filters);
|
||||||
|
loadPlaces(filters);
|
||||||
|
});
|
||||||
|
|
||||||
|
// первая загрузка
|
||||||
|
loadPlaces()
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
export function createCard() {
|
||||||
|
return `
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card place-card">
|
||||||
|
<div class="position-relative">
|
||||||
|
<img src="https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80" class="place-img" alt="Ресторан 'Панорама'">
|
||||||
|
<div class="place-category romantic-badge">Романтическое</div>
|
||||||
|
<div class="heart-counter">
|
||||||
|
<i class="fas fa-heart"></i> 128
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Ресторан 'Панорама'</h5>
|
||||||
|
<p class="card-text text-muted">Ресторан на 25-м этаже с панорамным видом на город. Идеальное место для романтического ужина при све...</p>
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<span class="rating">
|
||||||
|
★★★★½
|
||||||
|
<small class="text-muted ms-1">4.8</small>
|
||||||
|
</span>
|
||||||
|
<div class="price-tag mt-1">4500₽</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-heart btn-sm" onclick="viewPlaceDetails(1)">
|
||||||
|
<i class="fas fa-info-circle me-1"></i>Подробнее
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
6
src/main/resources/static/js/site/pages/home/home.js
Normal file
6
src/main/resources/static/js/site/pages/home/home.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import {initPlacesBlock} from "../../blocks/places-block.js";
|
||||||
|
import {initPlaceFilters} from "../../blocks/place-filters.js";
|
||||||
|
|
||||||
|
|
||||||
|
initPlaceFilters($('#mainPageContainer'));
|
||||||
|
initPlacesBlock($('#mainPageContainer'));
|
||||||
@@ -28,7 +28,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<script src="/js/site/blocks/place-filters.js"></script>
|
<script type="module" src="/js/site/pages/home/home.js"></script>
|
||||||
<script>
|
|
||||||
initPlaceFilters($('#mainPageContainer'))
|
|
||||||
</script>
|
|
||||||
Reference in New Issue
Block a user