feat: added review block
This commit is contained in:
@@ -719,13 +719,81 @@ img {
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.reviews {
|
||||
--reviews-visible: 3;
|
||||
--reviews-gap: 24px;
|
||||
background: linear-gradient(90deg, #293133, #20272a);
|
||||
}
|
||||
.reviews .section__head {
|
||||
margin-bottom: 44px;
|
||||
}
|
||||
.reviews__slider {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
.reviews__viewport {
|
||||
overflow: hidden;
|
||||
}
|
||||
.reviews__track {
|
||||
display: flex;
|
||||
gap: var(--reviews-gap);
|
||||
transition: transform 0.45s ease;
|
||||
will-change: transform;
|
||||
}
|
||||
.reviews__nav {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.22);
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
color: rgba(255, 255, 255, 0.88);
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s ease, border-color 0.2s ease, background-color 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
.reviews__nav:hover:not(:disabled) {
|
||||
transform: translateY(-1px);
|
||||
border-color: rgba(207, 23, 23, 0.75);
|
||||
background: rgba(207, 23, 23, 0.18);
|
||||
}
|
||||
.reviews__nav:disabled {
|
||||
opacity: 0.35;
|
||||
cursor: default;
|
||||
}
|
||||
.reviews__dots {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
.reviews__dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border: 0;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.28);
|
||||
cursor: pointer;
|
||||
transition: width 0.2s ease, background-color 0.2s ease;
|
||||
}
|
||||
.reviews__dot.is-active {
|
||||
width: 26px;
|
||||
background: #cf1717;
|
||||
}
|
||||
|
||||
.review-card {
|
||||
background: rgba(18, 18, 18, 0.4);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
min-height: 206px;
|
||||
padding: 33px;
|
||||
flex: 0 0 calc((100% - (var(--reviews-visible) - 1) * var(--reviews-gap)) / var(--reviews-visible));
|
||||
min-height: 250px;
|
||||
padding: 30px 28px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
transition: transform 0.3s ease, border-color 0.3s ease;
|
||||
}
|
||||
.review-card:hover {
|
||||
@@ -740,15 +808,29 @@ img {
|
||||
}
|
||||
.review-card strong {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.review-card span {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-size: 16px;
|
||||
line-height: 1.2;
|
||||
.review-card__meta {
|
||||
padding-top: 14px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
.review-card__meta a {
|
||||
color: #ffd2d2;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
text-decoration-thickness: 1px;
|
||||
text-decoration-color: rgba(255, 210, 210, 0.75);
|
||||
transition: color 0.2s ease, text-decoration-color 0.2s ease;
|
||||
}
|
||||
.review-card__meta a:hover {
|
||||
color: #ffe4e4;
|
||||
text-decoration-color: #ffe4e4;
|
||||
}
|
||||
|
||||
.stats {
|
||||
@@ -1414,6 +1496,9 @@ img {
|
||||
.hero__actions {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.reviews {
|
||||
--reviews-visible: 2;
|
||||
}
|
||||
.highlights__grid,
|
||||
.gallery__grid,
|
||||
.reviews__grid,
|
||||
@@ -1477,6 +1562,16 @@ img {
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 768px) {
|
||||
.reviews {
|
||||
--reviews-visible: 1;
|
||||
}
|
||||
.reviews__slider {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
.reviews__nav {
|
||||
display: none;
|
||||
}
|
||||
.container {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
2
assets/css/main.min.css
vendored
2
assets/css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -122,6 +122,119 @@
|
||||
});
|
||||
})();
|
||||
|
||||
(() => {
|
||||
const slider = document.querySelector("[data-reviews-slider]");
|
||||
if (!slider) return;
|
||||
|
||||
const viewport = slider.querySelector("[data-reviews-viewport]");
|
||||
const track = slider.querySelector("[data-reviews-track]");
|
||||
const prevButton = slider.querySelector("[data-reviews-prev]");
|
||||
const nextButton = slider.querySelector("[data-reviews-next]");
|
||||
const dotsContainer = document.querySelector("[data-reviews-dots]");
|
||||
const cards = Array.from(track?.querySelectorAll(".review-card") ?? []);
|
||||
|
||||
if (!viewport || !track || !prevButton || !nextButton || !dotsContainer || cards.length < 2) return;
|
||||
|
||||
let currentIndex = 0;
|
||||
let touchStartX = 0;
|
||||
|
||||
const readVisibleSlides = () => {
|
||||
const visibleValue = Number.parseInt(getComputedStyle(slider).getPropertyValue("--reviews-visible"), 10);
|
||||
return Number.isFinite(visibleValue) && visibleValue > 0 ? visibleValue : 1;
|
||||
};
|
||||
|
||||
const readTrackGap = () => {
|
||||
const styles = getComputedStyle(track);
|
||||
const gapValue = styles.gap || styles.columnGap || "0";
|
||||
const parsedGap = Number.parseFloat(gapValue);
|
||||
return Number.isFinite(parsedGap) ? parsedGap : 0;
|
||||
};
|
||||
|
||||
const maxIndex = () => Math.max(0, cards.length - readVisibleSlides());
|
||||
|
||||
const renderDots = () => {
|
||||
const total = maxIndex() + 1;
|
||||
dotsContainer.innerHTML = "";
|
||||
|
||||
for (let index = 0; index < total; index += 1) {
|
||||
const dot = document.createElement("button");
|
||||
dot.type = "button";
|
||||
dot.className = "reviews__dot";
|
||||
dot.setAttribute("aria-label", `Показать отзыв ${index + 1}`);
|
||||
dot.addEventListener("click", () => {
|
||||
currentIndex = index;
|
||||
update();
|
||||
});
|
||||
dotsContainer.appendChild(dot);
|
||||
}
|
||||
};
|
||||
|
||||
const update = () => {
|
||||
const max = maxIndex();
|
||||
currentIndex = Math.min(Math.max(currentIndex, 0), max);
|
||||
|
||||
const cardWidth = cards[0].getBoundingClientRect().width;
|
||||
const offset = (cardWidth + readTrackGap()) * currentIndex;
|
||||
track.style.transform = `translateX(${-offset}px)`;
|
||||
|
||||
prevButton.disabled = currentIndex === 0;
|
||||
nextButton.disabled = currentIndex === max;
|
||||
|
||||
const dots = Array.from(dotsContainer.querySelectorAll(".reviews__dot"));
|
||||
dots.forEach((dot, index) => {
|
||||
dot.classList.toggle("is-active", index === currentIndex);
|
||||
dot.setAttribute("aria-current", index === currentIndex ? "true" : "false");
|
||||
});
|
||||
};
|
||||
|
||||
prevButton.addEventListener("click", () => {
|
||||
currentIndex -= 1;
|
||||
update();
|
||||
});
|
||||
|
||||
nextButton.addEventListener("click", () => {
|
||||
currentIndex += 1;
|
||||
update();
|
||||
});
|
||||
|
||||
viewport.addEventListener("touchstart", (event) => {
|
||||
touchStartX = event.changedTouches[0].clientX;
|
||||
}, { passive: true });
|
||||
|
||||
viewport.addEventListener("touchend", (event) => {
|
||||
const deltaX = event.changedTouches[0].clientX - touchStartX;
|
||||
const threshold = 48;
|
||||
|
||||
if (deltaX > threshold) {
|
||||
currentIndex -= 1;
|
||||
update();
|
||||
return;
|
||||
}
|
||||
|
||||
if (deltaX < -threshold) {
|
||||
currentIndex += 1;
|
||||
update();
|
||||
}
|
||||
}, { passive: true });
|
||||
|
||||
const handleResize = () => {
|
||||
renderDots();
|
||||
update();
|
||||
};
|
||||
|
||||
let resizeRaf = null;
|
||||
window.addEventListener("resize", () => {
|
||||
if (resizeRaf) return;
|
||||
resizeRaf = window.requestAnimationFrame(() => {
|
||||
resizeRaf = null;
|
||||
handleResize();
|
||||
});
|
||||
});
|
||||
|
||||
renderDots();
|
||||
update();
|
||||
})();
|
||||
|
||||
(() => {
|
||||
const bookingForm = document.getElementById("booking-form");
|
||||
const successModal = document.getElementById("booking-success-modal");
|
||||
|
||||
@@ -741,10 +741,88 @@ img {
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.reviews {
|
||||
--reviews-visible: 3;
|
||||
--reviews-gap: 24px;
|
||||
background: linear-gradient(90deg, $color-surface, $color-surface-2);
|
||||
|
||||
.section__head {
|
||||
margin-bottom: 44px;
|
||||
}
|
||||
|
||||
&__slider {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
&__viewport {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__track {
|
||||
display: flex;
|
||||
gap: var(--reviews-gap);
|
||||
transition: transform 0.45s ease;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
&__nav {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.22);
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
color: rgba(255, 255, 255, 0.88);
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s ease, border-color 0.2s ease, background-color 0.2s ease, opacity 0.2s ease;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
transform: translateY(-1px);
|
||||
border-color: rgba(207, 23, 23, 0.75);
|
||||
background: rgba(207, 23, 23, 0.18);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.35;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
&__dots {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
&__dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border: 0;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.28);
|
||||
cursor: pointer;
|
||||
transition: width 0.2s ease, background-color 0.2s ease;
|
||||
|
||||
&.is-active {
|
||||
width: 26px;
|
||||
background: $color-accent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.review-card {
|
||||
@include card;
|
||||
min-height: 206px;
|
||||
padding: 33px;
|
||||
flex: 0 0 calc((100% - (var(--reviews-visible) - 1) * var(--reviews-gap)) / var(--reviews-visible));
|
||||
min-height: 250px;
|
||||
padding: 30px 28px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
transition: transform 0.3s ease, border-color 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
@@ -761,16 +839,32 @@ img {
|
||||
|
||||
strong {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
span {
|
||||
color: $color-text-muted;
|
||||
font-size: 16px;
|
||||
line-height: 1.2;
|
||||
&__meta {
|
||||
padding-top: 14px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||||
|
||||
a {
|
||||
color: #ffd2d2;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
text-decoration-thickness: 1px;
|
||||
text-decoration-color: rgba(255, 210, 210, 0.75);
|
||||
transition: color 0.2s ease, text-decoration-color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: #ffe4e4;
|
||||
text-decoration-color: #ffe4e4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1565,6 +1659,10 @@ img {
|
||||
}
|
||||
}
|
||||
|
||||
.reviews {
|
||||
--reviews-visible: 2;
|
||||
}
|
||||
|
||||
.highlights__grid,
|
||||
.gallery__grid,
|
||||
.reviews__grid,
|
||||
@@ -1650,6 +1748,19 @@ img {
|
||||
}
|
||||
|
||||
@include respond($bp-md) {
|
||||
.reviews {
|
||||
--reviews-visible: 1;
|
||||
|
||||
&__slider {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
&__nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user