first commit

This commit is contained in:
Web-serfer 2026-03-30 20:21:41 +05:00
commit 4a589825c2
297 changed files with 33019 additions and 0 deletions

View file

@ -0,0 +1,160 @@
---
import { CONTACT_CONSTANTS } from '@constants/constants.ts';
interface Props {
variant?: 'full' | 'card' | 'simple';
title?: string;
subtitle?: string;
address?: string;
mapUrl?: string;
showRouteButton?: boolean;
lazyLoad?: boolean;
}
const {
variant = 'full',
title = "Наш офис",
subtitle = "г. Сургут, пр. Комсомольский, 19",
address = CONTACT_CONSTANTS.address,
mapUrl = "https://yandex.ru/maps/-/CDu~yK-j",
showRouteButton = true,
lazyLoad = true
} = Astro.props;
const defaultMapUrl = "https://yandex.ru/map-widget/v1/?um=constructor%3Acdxezk6x&source=constructor";
const currentMapUrl = variant === 'card' ? defaultMapUrl : mapUrl;
---
{variant === 'full' ? (
<div class="w-full px-4 md:container md:mx-auto md:px-4 md:max-w-7xl mb-12">
<section id="map-section" class="relative w-full h-[500px] overflow-hidden rounded-3xl shadow-2xl">
<div class="absolute inset-0 bg-gray-200">
<iframe
data-src={currentMapUrl}
class="map-iframe w-full h-full border-0 grayscale contrast-125 opacity-0 transition-opacity duration-700"
allowfullscreen
loading={lazyLoad ? "lazy" : "eager"}
title="Карта проезда"
></iframe>
</div>
<div class="absolute inset-0 flex items-center justify-center pointer-events-none">
<div class="bg-white/95 backdrop-blur-xl p-8 md:p-10 rounded-2xl shadow-2xl max-w-sm text-center pointer-events-auto border border-white/50 mx-4">
<div class="w-16 h-16 bg-gradient-to-br from-[var(--color-gold)] to-[var(--color-gold-hover)] rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg">
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>
</div>
<h3 class="text-gray-900 font-bold text-lg uppercase tracking-wider mb-3">
{title}
</h3>
<p class="text-gray-600 mb-6 leading-relaxed">
{address}
</p>
{showRouteButton && (
<a
href={currentMapUrl}
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center gap-2 px-6 py-3 bg-gray-900 text-white text-sm font-bold uppercase tracking-wider rounded-xl hover:bg-[var(--color-gold)] transition-colors shadow-lg hover:shadow-xl"
>
Открыть в картах
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/>
</svg>
</a>
)}
</div>
</div>
</section>
</div>
) : variant === 'card' ? (
<div class="relative bg-white/80 backdrop-blur-xl border border-white/50 rounded-3xl overflow-hidden shadow-2xl shadow-gray-900/5 hover:shadow-2xl hover:shadow-[var(--color-blue-primary)]/10 transition-all duration-500 group">
<div class="absolute inset-0 bg-gradient-to-b from-transparent via-transparent to-gray-100/80 pointer-events-none z-10"></div>
<div class="relative z-20 p-8 pb-0 flex flex-col items-center text-center md:flex-row md:items-center md:justify-between gap-4">
<div>
<h2 class="text-xl sm:text-2xl md:text-3xl font-bold text-gray-900 mb-2 flex items-center gap-3 justify-center md:justify-start">
<span class="w-2 h-6 sm:h-8 bg-gradient-to-b from-[var(--color-gold)] to-[var(--color-gold-hover)] rounded-full hidden md:block"></span>
{title}
</h2>
<p class="text-gray-600 text-base sm:text-lg flex items-center gap-2 justify-center md:justify-start">
<svg class="w-4 sm:w-5 h-4 sm:h-5 text-[var(--color-gold)] hidden md:block" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"/>
</svg>
{subtitle}
</p>
</div>
{showRouteButton && (
<a href={currentMapUrl} target="_blank" class="inline-flex items-center justify-center gap-2 px-4 sm:px-6 py-2 sm:py-3 bg-[var(--color-gold)]/10 hover:bg-[var(--color-gold)]/20 text-[var(--color-gold)] font-semibold rounded-xl transition-all duration-300 border border-[var(--color-gold)]/20 hover:border-[var(--color-gold)]/40 self-center md:self-auto">
<span class="text-sm sm:text-base">Маршрут</span>
<svg class="w-4 sm:w-5 h-4 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
<path stroke-linecap="round" stroke-linejoin="round" d="M4 20L20 4" opacity="0.2" stroke-width="1" />
</svg>
</a>
)}
</div>
<div class="relative h-[450px] mt-8 bg-gray-100 overflow-hidden">
<iframe
src={currentMapUrl}
width="100%"
height="100%"
frameborder="0"
class="filter grayscale-[30%] contrast-125 group-hover:grayscale-0 transition-all duration-700"
loading={lazyLoad ? "lazy" : "eager"}
title="Офис на карте Сургута"
></iframe>
<div class="absolute inset-0 flex items-center justify-center bg-gray-900/0 group-hover:bg-gray-900/0 transition-all duration-500 pointer-events-none">
<span class="px-4 sm:px-6 py-2 sm:py-3 bg-white/95 backdrop-blur-sm text-gray-900 rounded-full text-xs sm:text-sm font-bold border border-gray-200 shadow-xl transform translate-y-4 opacity-0 group-hover:translate-y-0 group-hover:opacity-100 transition-all duration-500 pointer-events-auto cursor-pointer hover:bg-[var(--color-gold)] hover:text-white hover:border-[var(--color-gold)]">
Наведите для взаимодействия
</span>
</div>
</div>
</div>
) : (
<div class="relative h-[400px] bg-gray-100 overflow-hidden rounded-xl">
<iframe
src={currentMapUrl}
width="100%"
height="100%"
frameborder="0"
loading={lazyLoad ? "lazy" : "eager"}
title="Карта"
></iframe>
</div>
)}
{lazyLoad && variant === 'full' && (
<script>
const mapSection = document.getElementById('map-section');
const iframe = mapSection?.querySelector('.map-iframe');
if (mapSection && iframe) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const frame = entry.target.querySelector('iframe');
if (frame && frame.dataset.src) {
frame.src = frame.dataset.src;
frame.onload = () => {
frame.classList.remove('opacity-0');
frame.classList.add('opacity-100');
};
observer.unobserve(entry.target);
}
}
});
}, { rootMargin: '200px', threshold: 0.1 });
observer.observe(mapSection);
}
</script>
)}