1749 lines
59 KiB
HTML
1749 lines
59 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en" class="dark">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>What - KH3</title>
|
|
<link rel="stylesheet" href="styles/main.css" />
|
|
<meta
|
|
name="description"
|
|
content="Explore KH3's portfolio of construction projects, fit-outs, and design developments across Ghana and West Africa."
|
|
/>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link
|
|
href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700;800;900&display=swap"
|
|
rel="stylesheet"
|
|
/>
|
|
</head>
|
|
<body class="bg-kh3-black text-white font-montserrat overflow-x-hidden">
|
|
<!-- Navigation Menu -->
|
|
<div
|
|
class="fixed left-0 top-0 h-full w-5/6 md:w-1/3 bg-kh3-black z-50 hidden shadow-2xl"
|
|
id="navMenu"
|
|
>
|
|
<div class="p-8 flex flex-col h-full">
|
|
<!-- Logo -->
|
|
<div class="flex items-center gap-3 mb-12">
|
|
<a
|
|
href="index.html"
|
|
class="flex items-center gap-3 hover:opacity-80 transition-opacity"
|
|
>
|
|
<img src="assets/images/kh3_logo.png" alt="KH3" class="w-12 h-12" />
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Navigation Links - Inverted C Layout -->
|
|
<nav class="flex-1 relative">
|
|
<div class="absolute inset-0 flex items-center">
|
|
<div class="relative ml-8">
|
|
<!-- Navigation items in inverted C shape -->
|
|
<div class="space-y-6">
|
|
<!-- HOME - Top -->
|
|
<a
|
|
href="index.html"
|
|
class="block text-white text-xl md:text-lg font-medium hover:text-kh3-red transition-colors ml-0 font-montserrat opacity-0 animate-fade-in-left"
|
|
style="
|
|
animation-delay: 0.05s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.3s;
|
|
"
|
|
data-trans="crossfade"
|
|
>
|
|
<span class="md:hidden">HOME</span>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.05s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>H</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.075s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>O</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.1s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>M</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.125s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>E</span
|
|
>
|
|
</a>
|
|
|
|
<!-- WHY - Slightly right -->
|
|
<a
|
|
href="about.html"
|
|
class="block text-white text-xl md:text-lg font-medium hover:text-kh3-red transition-colors ml-0 md:ml-6 font-montserrat opacity-0 animate-fade-in-left"
|
|
style="
|
|
animation-delay: 0.2s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.3s;
|
|
"
|
|
data-trans="crossfade"
|
|
>
|
|
<span class="md:hidden">WHY</span>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.2s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>W</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.225s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>H</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.25s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>Y</span
|
|
>
|
|
</a>
|
|
|
|
<!-- HOW - More right -->
|
|
<a
|
|
href="services.html"
|
|
class="block text-white text-xl md:text-lg font-medium hover:text-kh3-red transition-colors ml-0 md:ml-12 font-montserrat opacity-0 animate-fade-in-left"
|
|
style="
|
|
animation-delay: 0.35s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.3s;
|
|
"
|
|
data-trans="crossfade"
|
|
>
|
|
<span class="md:hidden">HOW</span>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.35s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>H</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.375s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>O</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.4s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>W</span
|
|
>
|
|
</a>
|
|
|
|
<!-- WHAT - Most right -->
|
|
<a
|
|
href="projects.html"
|
|
class="block text-white text-xl md:text-lg font-medium border-b border-white pb-1 ml-0 md:ml-20 font-montserrat opacity-0 animate-fade-in-left"
|
|
style="
|
|
animation-delay: 0.55s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.3s;
|
|
"
|
|
>
|
|
<span class="md:hidden">WHAT</span>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.55s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>W</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.575s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>H</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.6s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>A</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.625s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>T</span
|
|
>
|
|
</a>
|
|
|
|
<!-- WHO - New position -->
|
|
<a
|
|
href="who.html"
|
|
class="block text-white text-xl md:text-lg font-medium hover:text-kh3-red transition-colors ml-0 md:ml-20 font-montserrat opacity-0 animate-fade-in-left"
|
|
style="
|
|
animation-delay: 0.65s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.3s;
|
|
"
|
|
data-trans="crossfade"
|
|
>
|
|
<span class="md:hidden">WHO</span>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.65s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>W</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.675s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>H</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.7s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>O</span
|
|
>
|
|
</a>
|
|
|
|
<!-- CONTACTS - More right -->
|
|
<a
|
|
href="contact.html"
|
|
class="block text-white text-xl md:text-lg font-medium hover:text-kh3-red transition-colors ml-0 md:ml-12 font-montserrat opacity-0 animate-fade-in-left"
|
|
style="
|
|
animation-delay: 0.75s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.3s;
|
|
"
|
|
data-trans="crossfade"
|
|
>
|
|
<span class="md:hidden">CONTACTS</span>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.75s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>C</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.775s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>O</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.8s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>N</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.825s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>T</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.85s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>A</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.875s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>C</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.9s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>T</span
|
|
>
|
|
<span
|
|
class="hidden md:inline"
|
|
style="
|
|
animation-delay: 0.925s;
|
|
animation-fill-mode: forwards;
|
|
animation-duration: 0.15s;
|
|
"
|
|
>S</span
|
|
>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Static Logo and Menu -->
|
|
<div class="fixed top-6 left-8 z-40">
|
|
<a
|
|
href="index.html"
|
|
class="flex items-center gap-3 hover:opacity-80 transition-opacity"
|
|
>
|
|
<img src="assets/images/kh3_logo.png" alt="KH3" class="w-12 h-12" />
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Menu Toggle with Homepage/WHY structure -->
|
|
<div
|
|
class="fixed top-6 right-8 md:bottom-12 md:left-12 md:top-auto md:right-auto z-50"
|
|
>
|
|
<div class="cursor-pointer" id="menuToggle">
|
|
<!-- Desktop view: menuWrap with waves and outline -->
|
|
<div class="relative inline-block hidden md:block" id="menuWrap">
|
|
<div class="menu-waves" aria-hidden="true">
|
|
<span class="wave"></span>
|
|
<span class="wave"></span>
|
|
<span class="wave"></span>
|
|
</div>
|
|
<div class="menu-outline" aria-hidden="true"></div>
|
|
<div class="relative" id="menuGrid">
|
|
<img
|
|
src="assets/icons/closed_petal.png"
|
|
alt="closed petal"
|
|
class="w-6 h-6"
|
|
/>
|
|
</div>
|
|
<div
|
|
id="menuPetal"
|
|
class="absolute inset-0 flex items-center justify-center pointer-events-none opacity-0 transition-opacity"
|
|
>
|
|
<img
|
|
src="assets/icons/open_petal.png"
|
|
alt="petal"
|
|
class="w-8 h-8"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mobile view: simple transparent background -->
|
|
<div class="md:hidden">
|
|
<div
|
|
class="cursor-pointer bg-black/30 backdrop-blur-sm rounded-lg p-3"
|
|
>
|
|
<div class="grid grid-cols-3 gap-1 w-6 h-6" id="menuGridMobile">
|
|
<span class="w-1 h-1 bg-white rounded-full"></span>
|
|
<span class="w-1 h-1 bg-white rounded-full"></span>
|
|
<span class="w-1 h-1 bg-white rounded-full"></span>
|
|
<span class="w-1 h-1 bg-white rounded-full"></span>
|
|
<span class="w-1 h-1 bg-white rounded-full"></span>
|
|
<span class="w-1 h-1 bg-white rounded-full"></span>
|
|
<span class="w-1 h-1 bg-white rounded-full"></span>
|
|
<span class="w-1 h-1 bg-white rounded-full"></span>
|
|
<span class="w-1 h-1 bg-white rounded-full"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Content -->
|
|
<main class="pt-20">
|
|
<!-- Hero Section (Left panel + vertical line + diamond markers, title with horizontal rule) -->
|
|
<section class="relative bg-kh3-black hero-section">
|
|
<div class="grid grid-cols-1 md:grid-cols-2 min-h-[90vh]">
|
|
<!-- Left dark panel -->
|
|
<div class="relative bg-kh3-black flex items-center">
|
|
<!-- Vertical timeline with diamonds -->
|
|
<div
|
|
class="absolute left-12 top-8 bottom-16 flex flex-col items-center opacity-0"
|
|
style="animation: fadeInUp 800ms ease-out 1200ms forwards"
|
|
>
|
|
<div class="w-px flex-1 bg-neutral-800"></div>
|
|
<div class="w-2.5 h-2.5 bg-white transform rotate-45"></div>
|
|
<div class="w-px flex-1 bg-neutral-800"></div>
|
|
<div class="w-2.5 h-2.5 bg-white transform rotate-45"></div>
|
|
<div class="w-px flex-1 bg-neutral-800"></div>
|
|
<div class="w-2.5 h-2.5 bg-white transform rotate-45"></div>
|
|
<div class="w-px flex-1 bg-neutral-800"></div>
|
|
</div>
|
|
|
|
<!-- Title with horizontal ruler -->
|
|
<div class="pl-16 md:pl-28 pr-6 w-full">
|
|
<div
|
|
class="flex items-center gap-6 opacity-0"
|
|
style="animation: fadeInUp 800ms ease-out 1600ms forwards"
|
|
>
|
|
<div class="flex-1 h-px bg-white"></div>
|
|
<h1
|
|
class="whitespace-nowrap text-4xl md:text-6xl tracking-[0.2em] font-bold"
|
|
>
|
|
OUR WHAT
|
|
</h1>
|
|
<div class="flex-1 h-px bg-white"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right image panel -->
|
|
<div class="relative overflow-hidden">
|
|
<img
|
|
id="projectsCurrentImg"
|
|
src="assets/images/room.png"
|
|
alt="KH3 Projects"
|
|
class="w-full h-full object-cover opacity-0"
|
|
style="animation: diagMaskReveal 1500ms ease-out 300ms forwards"
|
|
/>
|
|
<!-- Next image (for transitions) -->
|
|
<img
|
|
id="projectsNextImg"
|
|
src="assets/images/chair.png"
|
|
alt="KH3 Projects"
|
|
class="w-full h-full object-cover opacity-0 absolute inset-0"
|
|
/>
|
|
<!-- Down arrow prompt -->
|
|
<button
|
|
id="projectsScrollArrow"
|
|
class="flex absolute bottom-10 left-6 items-center flex-col text-white/80 hover:text-white transition-colors opacity-0"
|
|
style="animation: fadeInUp 800ms ease-out 1900ms forwards"
|
|
>
|
|
<span class="text-xs tracking-widest mb-2">SCROLL</span>
|
|
<svg
|
|
class="w-5 h-5 animate-arrowPulse"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M19 9l-7 7-7-7"
|
|
/>
|
|
</svg>
|
|
<div class="w-px h-8 bg-white/70"></div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Projects Grid Section -->
|
|
<section class="py-32 bg-kh3-black">
|
|
<div class="container mx-auto px-8 max-w-7xl">
|
|
<!-- Category Filters -->
|
|
<div class="mb-16 text-center">
|
|
<div class="flex flex-wrap justify-center gap-4 mb-8">
|
|
<button
|
|
class="category-filter px-6 py-3 text-white border border-white/30 rounded-full hover:bg-white hover:text-kh3-black transition-all duration-300 active"
|
|
data-category="all"
|
|
>
|
|
ALL PROJECTS
|
|
</button>
|
|
<button
|
|
class="category-filter px-6 py-3 text-white border border-white/30 rounded-full hover:bg-white hover:text-kh3-black transition-all duration-300"
|
|
data-category="Corporate"
|
|
>
|
|
CORPORATE
|
|
</button>
|
|
<button
|
|
class="category-filter px-6 py-3 text-white border border-white/30 rounded-full hover:bg-white hover:text-kh3-black transition-all duration-300"
|
|
data-category="Residential"
|
|
>
|
|
RESIDENTIAL
|
|
</button>
|
|
<button
|
|
class="category-filter px-6 py-3 text-white border border-white/30 rounded-full hover:bg-white hover:text-kh3-black transition-all duration-300"
|
|
data-category="Retail"
|
|
>
|
|
RETAIL
|
|
</button>
|
|
<button
|
|
class="category-filter px-6 py-3 text-white border border-white/30 rounded-full hover:bg-white hover:text-kh3-black transition-all duration-300"
|
|
data-category="Hospitality"
|
|
>
|
|
HOSPITALITY
|
|
</button>
|
|
<button
|
|
class="category-filter px-6 py-3 text-white border border-white/30 rounded-full hover:bg-white hover:text-kh3-black transition-all duration-300"
|
|
data-category="Industrial"
|
|
>
|
|
INDUSTRIAL
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Projects Grid -->
|
|
<div
|
|
id="projectsGrid"
|
|
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"
|
|
>
|
|
<!-- Project cards will be dynamically loaded here -->
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<!-- Project Details Modal -->
|
|
<div
|
|
id="projectModal"
|
|
class="fixed inset-0 bg-black/90 backdrop-blur-sm z-50 hidden"
|
|
>
|
|
<div class="relative w-full h-full flex items-center justify-center p-4">
|
|
<!-- Modal Content -->
|
|
<div
|
|
id="modalContent"
|
|
class="bg-kh3-black border border-white/20 rounded-2xl max-w-6xl w-full max-h-[90vh] overflow-hidden transform scale-95 opacity-0 transition-all duration-500 flex flex-col"
|
|
>
|
|
<!-- Modal Header -->
|
|
<div
|
|
class="flex items-center justify-between p-6 border-b border-white/10"
|
|
>
|
|
<div>
|
|
<h2
|
|
id="modalTitle"
|
|
class="text-2xl md:text-3xl font-bold text-white mb-2"
|
|
></h2>
|
|
<p
|
|
id="modalCategory"
|
|
class="text-kh3-red text-sm font-medium tracking-wider"
|
|
></p>
|
|
</div>
|
|
<button
|
|
id="closeModal"
|
|
class="text-white/70 hover:text-white transition-colors duration-300"
|
|
>
|
|
<svg
|
|
class="w-8 h-8"
|
|
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>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Modal Body -->
|
|
<div class="flex flex-col lg:flex-row flex-1 min-h-0">
|
|
<!-- Image Carousel Section -->
|
|
<div class="lg:w-2/3 relative group">
|
|
<div class="relative h-80 lg:h-full overflow-hidden">
|
|
<!-- Main Image -->
|
|
<img
|
|
id="modalMainImage"
|
|
src=""
|
|
alt=""
|
|
class="w-full h-full object-cover transition-all duration-500 cursor-pointer hover:scale-105"
|
|
onclick="enlargeImage()"
|
|
/>
|
|
|
|
<!-- Image Navigation -->
|
|
<div
|
|
class="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex space-x-2"
|
|
>
|
|
<div id="imageDots" class="flex space-x-2">
|
|
<!-- Dots will be generated here -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Previous/Next Buttons -->
|
|
<button
|
|
id="prevImage"
|
|
class="absolute left-4 top-1/2 transform -translate-y-1/2 bg-black/50 hover:bg-black/70 text-white p-2 rounded-full transition-all duration-300 opacity-0 group-hover:opacity-100"
|
|
>
|
|
<svg
|
|
class="w-6 h-6"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M15 19l-7-7 7-7"
|
|
></path>
|
|
</svg>
|
|
</button>
|
|
<button
|
|
id="nextImage"
|
|
class="absolute right-4 top-1/2 transform -translate-y-1/2 bg-black/50 hover:bg-black/70 text-white p-2 rounded-full transition-all duration-300 opacity-0 group-hover:opacity-100"
|
|
>
|
|
<svg
|
|
class="w-6 h-6"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M9 5l7 7-7 7"
|
|
></path>
|
|
</svg>
|
|
</button>
|
|
|
|
<!-- Image Counter -->
|
|
<div
|
|
class="absolute top-4 right-4 bg-black/50 text-white px-3 py-1 rounded-full text-sm"
|
|
>
|
|
<span id="imageCounter">1</span> /
|
|
<span id="totalImages">1</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Project Details Section -->
|
|
<div
|
|
class="lg:w-1/3 p-6 overflow-y-auto"
|
|
style="max-height: calc(90vh - 120px)"
|
|
>
|
|
<div class="space-y-6">
|
|
<!-- Project Overview -->
|
|
<div>
|
|
<h3
|
|
class="text-lg font-semibold text-white mb-3 border-b border-white/20 pb-2"
|
|
>
|
|
PROJECT OVERVIEW
|
|
</h3>
|
|
<p
|
|
id="modalDescription"
|
|
class="text-white/80 text-sm leading-relaxed"
|
|
></p>
|
|
</div>
|
|
|
|
<!-- Project Details -->
|
|
<div>
|
|
<h3
|
|
class="text-lg font-semibold text-white mb-3 border-b border-white/20 pb-2"
|
|
>
|
|
PROJECT DETAILS
|
|
</h3>
|
|
<div class="space-y-3">
|
|
<div class="flex justify-between gap-4">
|
|
<span class="text-white/60 text-sm">Client:</span>
|
|
<span
|
|
id="modalClient"
|
|
class="text-white text-sm font-medium text-right max-w-[60%]"
|
|
></span>
|
|
</div>
|
|
<div class="flex justify-between gap-4">
|
|
<span class="text-white/60 text-sm">Type of Work:</span>
|
|
<span
|
|
id="modalTypeOfWork"
|
|
class="text-white text-sm font-medium text-right max-w-[60%]"
|
|
></span>
|
|
</div>
|
|
<div class="flex justify-between gap-4">
|
|
<span class="text-white/60 text-sm">Size:</span>
|
|
<span
|
|
id="modalSize"
|
|
class="text-white text-sm font-medium text-right max-w-[60%]"
|
|
></span>
|
|
</div>
|
|
<div class="flex justify-between gap-4">
|
|
<span class="text-white/60 text-sm">Completion:</span>
|
|
<span
|
|
id="modalCompletionDate"
|
|
class="text-white text-sm font-medium text-right max-w-[60%]"
|
|
></span>
|
|
</div>
|
|
<div class="flex justify-between gap-4">
|
|
<span class="text-white/60 text-sm">Location:</span>
|
|
<span
|
|
id="modalLocation"
|
|
class="text-white text-sm font-medium text-right max-w-[60%]"
|
|
></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Project Highlights -->
|
|
<div>
|
|
<h3
|
|
class="text-lg font-semibold text-white mb-3 border-b border-white/20 pb-2"
|
|
>
|
|
HIGHLIGHTS
|
|
</h3>
|
|
<ul id="modalHighlights" class="space-y-2">
|
|
<!-- Highlights will be generated here -->
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="pt-4 border-t border-white/20">
|
|
<a
|
|
href="contact.html"
|
|
class="block w-full bg-kh3-red hover:bg-red-700 text-white py-3 px-6 rounded-lg font-medium transition-all duration-300 transform hover:scale-105 text-center"
|
|
data-trans="crossfade"
|
|
>
|
|
WORK WITH US
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Image Enlargement Modal -->
|
|
<div
|
|
id="imageEnlargeModal"
|
|
class="fixed inset-0 bg-black/95 backdrop-blur-sm z-[60] hidden"
|
|
>
|
|
<div
|
|
class="relative w-full h-full flex items-center justify-center p-4"
|
|
>
|
|
<div class="relative max-w-7xl max-h-full">
|
|
<!-- Enlarged Image -->
|
|
<img
|
|
id="enlargedImage"
|
|
src=""
|
|
alt=""
|
|
class="max-w-full max-h-full object-contain rounded-lg shadow-2xl"
|
|
/>
|
|
|
|
<!-- Close Button -->
|
|
<button
|
|
id="closeEnlargeModal"
|
|
class="absolute -top-4 -right-4 bg-kh3-red hover:bg-red-700 text-white p-3 rounded-full transition-all duration-300 transform hover:scale-110"
|
|
>
|
|
<svg
|
|
class="w-6 h-6"
|
|
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>
|
|
</svg>
|
|
</button>
|
|
|
|
<!-- Image Info -->
|
|
<div
|
|
class="absolute bottom-4 left-4 bg-black/70 text-white px-4 py-2 rounded-lg"
|
|
>
|
|
<span id="enlargedImageCounter">1</span> /
|
|
<span id="enlargedTotalImages">1</span>
|
|
</div>
|
|
|
|
<!-- Navigation Arrows -->
|
|
<button
|
|
id="enlargePrevImage"
|
|
class="absolute left-4 top-1/2 transform -translate-y-1/2 bg-black/50 hover:bg-black/70 text-white p-4 rounded-full transition-all duration-300"
|
|
>
|
|
<svg
|
|
class="w-8 h-8"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M15 19l-7-7 7-7"
|
|
></path>
|
|
</svg>
|
|
</button>
|
|
<button
|
|
id="enlargeNextImage"
|
|
class="absolute right-4 top-1/2 transform -translate-y-1/2 bg-black/50 hover:bg-black/70 text-white p-4 rounded-full transition-all duration-300"
|
|
>
|
|
<svg
|
|
class="w-8 h-8"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M9 5l7 7-7 7"
|
|
></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
/* Project card animations */
|
|
@keyframes projectCardFloat {
|
|
0%,
|
|
100% {
|
|
transform: translateY(0px) scale(1);
|
|
}
|
|
50% {
|
|
transform: translateY(-8px) scale(1.02);
|
|
}
|
|
}
|
|
|
|
@keyframes projectImageZoom {
|
|
0% {
|
|
transform: scale(1);
|
|
}
|
|
100% {
|
|
transform: scale(1.1);
|
|
}
|
|
}
|
|
|
|
@keyframes projectOverlaySlide {
|
|
0% {
|
|
transform: translateY(100%);
|
|
opacity: 0;
|
|
}
|
|
100% {
|
|
transform: translateY(0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.project-card {
|
|
animation: projectCardFloat 6s ease-in-out infinite;
|
|
animation-delay: calc(var(--card-index) * 0.2s);
|
|
}
|
|
|
|
.project-card:hover {
|
|
animation-play-state: paused;
|
|
}
|
|
|
|
.project-card:hover .project-image {
|
|
animation: projectImageZoom 0.6s ease-out forwards;
|
|
}
|
|
|
|
.project-card:hover .project-overlay {
|
|
animation: projectOverlaySlide 0.4s ease-out forwards;
|
|
}
|
|
|
|
.project-overlay {
|
|
transform: translateY(100%);
|
|
opacity: 0;
|
|
}
|
|
|
|
/* Category filter animations */
|
|
.category-filter.active,
|
|
.category-filter.active:hover {
|
|
background: white !important;
|
|
color: #212829 !important;
|
|
border-color: white !important;
|
|
}
|
|
|
|
/* Diagonal mask reveal for hero image */
|
|
@keyframes diagMaskReveal {
|
|
0% {
|
|
opacity: 0;
|
|
clip-path: polygon(100% 0, 100% 0, 100% 100%, 100% 100%);
|
|
transform: scale(1.03);
|
|
}
|
|
55% {
|
|
opacity: 1;
|
|
clip-path: polygon(82% 0, 100% 0, 100% 100%, 64% 100%);
|
|
}
|
|
100% {
|
|
opacity: 1;
|
|
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
|
|
}
|
|
}
|
|
|
|
/* Arrow pulse animation */
|
|
@keyframes arrowPulse {
|
|
0%,
|
|
100% {
|
|
transform: translateY(0);
|
|
opacity: 0.7;
|
|
}
|
|
50% {
|
|
transform: translateY(10px);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.animate-arrowPulse {
|
|
animation: arrowPulse 2s ease-in-out infinite;
|
|
}
|
|
|
|
/* Fade in animations */
|
|
@keyframes fadeInUp {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(30px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
/* Slide transition animations for image carousel */
|
|
@keyframes slideOutLeft {
|
|
0% {
|
|
transform: translateX(0) scale(1);
|
|
opacity: 1;
|
|
}
|
|
100% {
|
|
transform: translateX(-100%) scale(0.8);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes slideOutRight {
|
|
0% {
|
|
transform: translateX(0) scale(1);
|
|
opacity: 1;
|
|
}
|
|
100% {
|
|
transform: translateX(100%) scale(0.8);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes zoomInFromLeft {
|
|
0% {
|
|
transform: translateX(-100%) scale(1.2);
|
|
opacity: 0;
|
|
}
|
|
100% {
|
|
transform: translateX(0) scale(1);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes zoomInFromRight {
|
|
0% {
|
|
transform: translateX(100%) scale(1.2);
|
|
opacity: 0;
|
|
}
|
|
100% {
|
|
transform: translateX(0) scale(1);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
/* Modal animations */
|
|
@keyframes modalFadeIn {
|
|
from {
|
|
opacity: 0;
|
|
transform: scale(0.9) translateY(-20px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: scale(1) translateY(0);
|
|
}
|
|
}
|
|
|
|
@keyframes modalFadeOut {
|
|
from {
|
|
opacity: 1;
|
|
transform: scale(1) translateY(0);
|
|
}
|
|
to {
|
|
opacity: 0;
|
|
transform: scale(0.9) translateY(-20px);
|
|
}
|
|
}
|
|
|
|
/* Image carousel hover effects */
|
|
.group:hover #prevImage,
|
|
.group:hover #nextImage {
|
|
opacity: 1 !important;
|
|
}
|
|
|
|
/* Modal content animations */
|
|
#modalContent {
|
|
animation: modalFadeIn 0.5s ease-out;
|
|
}
|
|
|
|
/* Highlight bullet animations */
|
|
#modalHighlights li {
|
|
opacity: 0;
|
|
transform: translateX(-20px);
|
|
animation: slideInLeft 0.5s ease-out forwards;
|
|
}
|
|
|
|
#modalHighlights li:nth-child(1) {
|
|
animation-delay: 0.1s;
|
|
}
|
|
#modalHighlights li:nth-child(2) {
|
|
animation-delay: 0.2s;
|
|
}
|
|
#modalHighlights li:nth-child(3) {
|
|
animation-delay: 0.3s;
|
|
}
|
|
#modalHighlights li:nth-child(4) {
|
|
animation-delay: 0.4s;
|
|
}
|
|
#modalHighlights li:nth-child(5) {
|
|
animation-delay: 0.5s;
|
|
}
|
|
|
|
@keyframes slideInLeft {
|
|
to {
|
|
opacity: 1;
|
|
transform: translateX(0);
|
|
}
|
|
}
|
|
|
|
/* Image dot hover effects */
|
|
#imageDots button:hover {
|
|
transform: scale(1.2);
|
|
background-color: #dc2626 !important;
|
|
}
|
|
|
|
/* Request quote button hover effect */
|
|
.bg-kh3-red:hover {
|
|
box-shadow: 0 0 20px rgba(220, 38, 38, 0.4);
|
|
}
|
|
|
|
/* Image enlargement modal animations */
|
|
@keyframes enlargeModalFadeIn {
|
|
from {
|
|
opacity: 0;
|
|
transform: scale(0.8);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
#imageEnlargeModal:not(.hidden) {
|
|
animation: enlargeModalFadeIn 0.3s ease-out;
|
|
}
|
|
|
|
/* Enlarged image hover effects */
|
|
#enlargedImage {
|
|
transition: transform 0.3s ease-out;
|
|
}
|
|
|
|
#enlargedImage:hover {
|
|
transform: scale(1.02);
|
|
}
|
|
|
|
/* Enlarged modal navigation button hover effects */
|
|
#enlargePrevImage:hover,
|
|
#enlargeNextImage:hover {
|
|
transform: translateY(-50%) scale(1.1);
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
/* Close button hover effect for enlarged modal */
|
|
#closeEnlargeModal:hover {
|
|
box-shadow: 0 0 20px rgba(220, 38, 38, 0.6);
|
|
}
|
|
|
|
/* Scrollbar styling for project details */
|
|
.overflow-y-auto::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
|
|
.overflow-y-auto::-webkit-scrollbar-track {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.overflow-y-auto::-webkit-scrollbar-thumb {
|
|
background: rgba(220, 38, 38, 0.6);
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.overflow-y-auto::-webkit-scrollbar-thumb:hover {
|
|
background: rgba(220, 38, 38, 0.8);
|
|
}
|
|
|
|
/* Page transition animations */
|
|
@keyframes staggerFadeOut {
|
|
0% {
|
|
opacity: 1;
|
|
transform: translateY(0) scale(1);
|
|
}
|
|
100% {
|
|
opacity: 0;
|
|
transform: translateY(-20px) scale(0.95);
|
|
}
|
|
}
|
|
|
|
/* Hero section class for targeting */
|
|
.hero-section {
|
|
contain: layout;
|
|
}
|
|
|
|
/* Homepage-style menu outline and waves (desktop only) */
|
|
#menuWrap {
|
|
position: relative;
|
|
overflow: visible;
|
|
}
|
|
.menu-outline {
|
|
position: absolute;
|
|
inset: 0;
|
|
z-index: 2;
|
|
pointer-events: none;
|
|
outline: 1px solid rgba(255, 255, 255, 0.6);
|
|
outline-offset: 6px;
|
|
}
|
|
|
|
.menu-waves {
|
|
position: absolute;
|
|
inset: -20px;
|
|
z-index: 1;
|
|
pointer-events: none;
|
|
}
|
|
.menu-waves .wave {
|
|
position: absolute;
|
|
inset: 0;
|
|
border: 1px solid rgba(255, 255, 255, 0.28);
|
|
opacity: 0;
|
|
transform: scale(1);
|
|
animation: waveBurst 5.8s ease-in-out infinite;
|
|
}
|
|
.menu-waves .wave:nth-child(2) {
|
|
animation-delay: 0.3s;
|
|
}
|
|
.menu-waves .wave:nth-child(3) {
|
|
animation-delay: 0.6s;
|
|
}
|
|
#menuWrap.open #menuPetal {
|
|
opacity: 1;
|
|
}
|
|
#menuWrap.open #menuGrid {
|
|
opacity: 0;
|
|
}
|
|
|
|
@keyframes waveBurst {
|
|
0%,
|
|
69% {
|
|
opacity: 0;
|
|
transform: scale(1);
|
|
}
|
|
77% {
|
|
opacity: 0.38;
|
|
transform: scale(1.18, 1.12);
|
|
}
|
|
92% {
|
|
opacity: 0.22;
|
|
transform: scale(1.55, 1.42);
|
|
}
|
|
100% {
|
|
opacity: 0;
|
|
transform: scale(1.95, 1.75);
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<script src="js/main.js"></script>
|
|
<script>
|
|
// Projects page functionality
|
|
let projectsData = [];
|
|
let currentCategory = "all";
|
|
let currentProject = null;
|
|
let currentImageIndex = 0;
|
|
|
|
// Page transition functionality
|
|
function handlePageTransition(e) {
|
|
e.preventDefault();
|
|
const targetUrl = e.currentTarget.href;
|
|
const transitionType =
|
|
e.currentTarget.getAttribute("data-trans") || "crossfade";
|
|
|
|
// Get all elements to animate out
|
|
const elementsToAnimate = [
|
|
document.querySelector(".hero-section"),
|
|
document.querySelector("#projectsGrid"),
|
|
document.querySelector(".category-filter"),
|
|
document.querySelector("main"),
|
|
].filter((el) => el);
|
|
|
|
// Animate elements out in order
|
|
elementsToAnimate.forEach((element, index) => {
|
|
setTimeout(() => {
|
|
if (element) {
|
|
element.style.animation =
|
|
"staggerFadeOut 0.6s ease-in-out forwards";
|
|
}
|
|
}, index * 100);
|
|
});
|
|
|
|
// Navigate after animations complete
|
|
setTimeout(() => {
|
|
window.location.href = targetUrl;
|
|
}, elementsToAnimate.length * 100 + 600);
|
|
}
|
|
|
|
// Add event listeners for page transitions
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const transitionLinks = document.querySelectorAll("[data-trans]");
|
|
transitionLinks.forEach((link) => {
|
|
link.addEventListener("click", handlePageTransition);
|
|
});
|
|
});
|
|
|
|
// Handle back/forward navigation
|
|
window.addEventListener("pageshow", function (event) {
|
|
if (event.persisted) {
|
|
// Page was loaded from cache (back/forward)
|
|
window.location.reload();
|
|
}
|
|
});
|
|
|
|
// Auto-scroll to projects grid after 3 seconds
|
|
setTimeout(() => {
|
|
// Scroll just slightly to hint at content below (1.1 viewport heights)
|
|
const targetScroll = window.innerHeight * 1.1;
|
|
|
|
// Create a smooth, gradual scroll animation
|
|
const startScroll = window.pageYOffset;
|
|
const distance = targetScroll - startScroll;
|
|
const duration = 2000; // 2 seconds for very smooth animation
|
|
let start = null;
|
|
|
|
function animateScroll(currentTime) {
|
|
if (start === null) start = currentTime;
|
|
const timeElapsed = currentTime - start;
|
|
const progress = Math.min(timeElapsed / duration, 1);
|
|
|
|
// Easing function for smooth deceleration
|
|
const easeOutQuart = 1 - Math.pow(1 - progress, 4);
|
|
|
|
window.scrollTo(0, startScroll + distance * easeOutQuart);
|
|
|
|
if (progress < 1) {
|
|
requestAnimationFrame(animateScroll);
|
|
}
|
|
}
|
|
|
|
requestAnimationFrame(animateScroll);
|
|
}, 3000);
|
|
|
|
// Load projects data
|
|
async function loadProjects() {
|
|
try {
|
|
const response = await fetch("data/projects.json");
|
|
projectsData = await response.json();
|
|
renderProjects();
|
|
} catch (error) {
|
|
console.error("Error loading projects:", error);
|
|
}
|
|
}
|
|
|
|
// Render projects
|
|
function renderProjects() {
|
|
const grid = document.getElementById("projectsGrid");
|
|
const filteredProjects =
|
|
currentCategory === "all"
|
|
? projectsData
|
|
: projectsData.filter(
|
|
(project) => project.category === currentCategory
|
|
);
|
|
|
|
grid.innerHTML = filteredProjects
|
|
.map(
|
|
(project, index) => `
|
|
<div class="project-card group relative overflow-hidden rounded-lg bg-kh3-grey/10 border border-white/10 cursor-pointer"
|
|
style="--card-index: ${index};"
|
|
onclick="openProjectDetails('${project.id}')">
|
|
<div class="relative h-64 overflow-hidden">
|
|
<img
|
|
src="${project.images[0]}"
|
|
alt="${project.name}"
|
|
class="project-image w-full h-full object-cover transition-all duration-600"
|
|
/>
|
|
<div class="project-overlay absolute inset-0 bg-black/80 flex items-center justify-center">
|
|
<div class="text-center">
|
|
<div class="w-12 h-12 bg-kh3-red rounded-full flex items-center justify-center mx-auto mb-4">
|
|
<svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
|
|
</svg>
|
|
</div>
|
|
<p class="text-white font-medium">VIEW PROJECT</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="p-6">
|
|
<div class="flex items-center justify-between mb-3">
|
|
<span class="text-kh3-red text-sm font-medium tracking-wider">${project.category}</span>
|
|
<span class="text-white/60 text-sm">${project.completionDate}</span>
|
|
</div>
|
|
<h3 class="text-xl font-bold text-white mb-2 group-hover:text-kh3-red transition-colors duration-300">
|
|
${project.name}
|
|
</h3>
|
|
<p class="text-white/70 text-sm mb-4 line-clamp-2">
|
|
${project.description}
|
|
</p>
|
|
<div class="flex items-center justify-between">
|
|
<span class="text-white/50 text-sm">${project.size}</span>
|
|
<span class="text-white/50 text-sm">${project.location}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`
|
|
)
|
|
.join("");
|
|
}
|
|
|
|
// Modal functionality
|
|
function openProjectDetails(projectId) {
|
|
const project = projectsData.find((p) => p.id === projectId);
|
|
if (!project) return;
|
|
|
|
currentProject = project;
|
|
currentImageIndex = 0;
|
|
|
|
// Populate modal content
|
|
document.getElementById("modalTitle").textContent = project.name;
|
|
document.getElementById("modalCategory").textContent = project.category;
|
|
document.getElementById("modalDescription").textContent =
|
|
project.description;
|
|
document.getElementById("modalClient").textContent = project.client;
|
|
document.getElementById("modalTypeOfWork").textContent =
|
|
project.typeOfWork;
|
|
document.getElementById("modalSize").textContent = project.size;
|
|
document.getElementById("modalCompletionDate").textContent =
|
|
project.completionDate;
|
|
document.getElementById("modalLocation").textContent = project.location;
|
|
|
|
// Populate highlights
|
|
const highlightsList = document.getElementById("modalHighlights");
|
|
highlightsList.innerHTML = project.highlights
|
|
.map(
|
|
(highlight) => `
|
|
<li class="flex items-start space-x-2">
|
|
<div class="w-1.5 h-1.5 bg-kh3-red rounded-full mt-2 flex-shrink-0"></div>
|
|
<span class="text-white/80 text-sm">${highlight}</span>
|
|
</li>
|
|
`
|
|
)
|
|
.join("");
|
|
|
|
// Set up image carousel
|
|
setupImageCarousel(project.images);
|
|
|
|
// Show modal with animation
|
|
const modal = document.getElementById("projectModal");
|
|
const modalContent = document.getElementById("modalContent");
|
|
|
|
modal.classList.remove("hidden");
|
|
document.body.style.overflow = "hidden";
|
|
|
|
// Trigger animation
|
|
setTimeout(() => {
|
|
modalContent.classList.remove("scale-95", "opacity-0");
|
|
modalContent.classList.add("scale-100", "opacity-100");
|
|
}, 10);
|
|
}
|
|
|
|
function closeModal() {
|
|
const modal = document.getElementById("projectModal");
|
|
const modalContent = document.getElementById("modalContent");
|
|
|
|
// Trigger close animation
|
|
modalContent.classList.remove("scale-100", "opacity-100");
|
|
modalContent.classList.add("scale-95", "opacity-0");
|
|
|
|
setTimeout(() => {
|
|
modal.classList.add("hidden");
|
|
document.body.style.overflow = "auto";
|
|
}, 500);
|
|
}
|
|
|
|
function setupImageCarousel(images) {
|
|
const mainImage = document.getElementById("modalMainImage");
|
|
const imageDots = document.getElementById("imageDots");
|
|
const imageCounter = document.getElementById("imageCounter");
|
|
const totalImages = document.getElementById("totalImages");
|
|
const prevButton = document.getElementById("prevImage");
|
|
const nextButton = document.getElementById("nextImage");
|
|
|
|
// Set initial image
|
|
mainImage.src = images[0];
|
|
mainImage.alt = currentProject.name;
|
|
totalImages.textContent = images.length;
|
|
|
|
// Generate dots
|
|
imageDots.innerHTML = images
|
|
.map(
|
|
(_, index) => `
|
|
<button
|
|
class="w-2 h-2 rounded-full transition-all duration-300 ${
|
|
index === 0 ? "bg-kh3-red" : "bg-white/30"
|
|
}"
|
|
onclick="goToImage(${index})"
|
|
></button>
|
|
`
|
|
)
|
|
.join("");
|
|
|
|
// Navigation functions
|
|
window.goToImage = function (index) {
|
|
currentImageIndex = index;
|
|
updateImageCarousel();
|
|
};
|
|
|
|
window.nextImage = function () {
|
|
currentImageIndex = (currentImageIndex + 1) % images.length;
|
|
updateImageCarousel();
|
|
};
|
|
|
|
window.prevImage = function () {
|
|
currentImageIndex =
|
|
currentImageIndex === 0 ? images.length - 1 : currentImageIndex - 1;
|
|
updateImageCarousel();
|
|
};
|
|
|
|
function updateImageCarousel() {
|
|
// Update main image with fade effect
|
|
mainImage.style.opacity = "0";
|
|
setTimeout(() => {
|
|
mainImage.src = images[currentImageIndex];
|
|
mainImage.style.opacity = "1";
|
|
}, 250);
|
|
|
|
// Update counter
|
|
imageCounter.textContent = currentImageIndex + 1;
|
|
|
|
// Update dots
|
|
const dots = imageDots.querySelectorAll("button");
|
|
dots.forEach((dot, index) => {
|
|
dot.classList.toggle("bg-kh3-red", index === currentImageIndex);
|
|
dot.classList.toggle("bg-white/30", index !== currentImageIndex);
|
|
});
|
|
}
|
|
|
|
// Event listeners
|
|
prevButton.onclick = window.prevImage;
|
|
nextButton.onclick = window.nextImage;
|
|
|
|
// Keyboard navigation
|
|
document.addEventListener("keydown", function (e) {
|
|
if (
|
|
!document
|
|
.getElementById("projectModal")
|
|
.classList.contains("hidden")
|
|
) {
|
|
if (e.key === "ArrowLeft") {
|
|
window.prevImage();
|
|
} else if (e.key === "ArrowRight") {
|
|
window.nextImage();
|
|
} else if (e.key === "Escape") {
|
|
closeModal();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Category filter functionality
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
loadProjects();
|
|
|
|
// Category filter buttons
|
|
document.querySelectorAll(".category-filter").forEach((button) => {
|
|
button.addEventListener("click", function () {
|
|
// Remove active class from all buttons
|
|
document
|
|
.querySelectorAll(".category-filter")
|
|
.forEach((btn) => btn.classList.remove("active"));
|
|
// Add active class to clicked button
|
|
this.classList.add("active");
|
|
|
|
// Update current category and re-render
|
|
currentCategory = this.dataset.category;
|
|
renderProjects();
|
|
});
|
|
});
|
|
|
|
// Close modal functionality
|
|
document
|
|
.getElementById("closeModal")
|
|
.addEventListener("click", closeModal);
|
|
|
|
// Close modal when clicking outside
|
|
document
|
|
.getElementById("projectModal")
|
|
.addEventListener("click", function (e) {
|
|
if (e.target === this) {
|
|
closeModal();
|
|
}
|
|
});
|
|
|
|
// Menu toggle functionality
|
|
const menuToggle = document.getElementById("menuToggle");
|
|
const navMenu = document.getElementById("navMenu");
|
|
const menuWrap = document.getElementById("menuWrap");
|
|
const menuGrid = document.getElementById("menuGrid");
|
|
const menuGridMobile = document.getElementById("menuGridMobile");
|
|
|
|
if (menuToggle && navMenu) {
|
|
let isMenuOpen = false;
|
|
let closeBtnEl = null;
|
|
|
|
menuToggle.addEventListener("click", () => {
|
|
if (isMenuOpen) {
|
|
// Close menu
|
|
navMenu.classList.add("hidden");
|
|
if (menuWrap) menuWrap.classList.remove("open");
|
|
isMenuOpen = false;
|
|
} else {
|
|
// Open menu
|
|
navMenu.classList.remove("hidden");
|
|
if (menuWrap) menuWrap.classList.add("open");
|
|
isMenuOpen = true;
|
|
}
|
|
});
|
|
|
|
// Close menu when clicking outside
|
|
document.addEventListener("click", (e) => {
|
|
if (!menuToggle.contains(e.target) && !navMenu.contains(e.target)) {
|
|
navMenu.classList.add("hidden");
|
|
if (menuWrap) menuWrap.classList.remove("open");
|
|
isMenuOpen = false;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// Projects page image carousel
|
|
const projectsImgs = [
|
|
"assets/images/room.png",
|
|
"assets/images/chair.png",
|
|
"assets/images/google.png",
|
|
];
|
|
|
|
const projectsCurrentImg = document.getElementById("projectsCurrentImg");
|
|
const projectsNextImg = document.getElementById("projectsNextImg");
|
|
|
|
if (projectsCurrentImg && projectsNextImg) {
|
|
let currentIndex = 0;
|
|
let isTransitioning = false;
|
|
|
|
const slideDirections = ["left", "right"];
|
|
let slideIndex = 0;
|
|
|
|
function performProjectsSlideZoomTransition() {
|
|
if (isTransitioning) return;
|
|
isTransitioning = true;
|
|
|
|
const nextIndex = (currentIndex + 1) % projectsImgs.length;
|
|
const slideDirection =
|
|
slideDirections[slideIndex % slideDirections.length];
|
|
slideIndex++;
|
|
|
|
projectsNextImg.src = projectsImgs[nextIndex];
|
|
projectsNextImg.style.opacity = "1";
|
|
|
|
if (slideDirection === "left") {
|
|
projectsCurrentImg.style.animation =
|
|
"slideOutLeft 1s ease-in-out forwards";
|
|
projectsNextImg.style.animation =
|
|
"zoomInFromRight 1s ease-in-out forwards";
|
|
} else {
|
|
projectsCurrentImg.style.animation =
|
|
"slideOutRight 1s ease-in-out forwards";
|
|
projectsNextImg.style.animation =
|
|
"zoomInFromLeft 1s ease-in-out forwards";
|
|
}
|
|
|
|
setTimeout(() => {
|
|
projectsCurrentImg.src = projectsImgs[nextIndex];
|
|
projectsCurrentImg.style.animation = "";
|
|
projectsCurrentImg.style.transform = "";
|
|
projectsCurrentImg.style.opacity = "1";
|
|
|
|
projectsNextImg.style.animation = "";
|
|
projectsNextImg.style.transform = "";
|
|
projectsNextImg.style.opacity = "0";
|
|
|
|
currentIndex = nextIndex;
|
|
isTransitioning = false;
|
|
}, 1000);
|
|
}
|
|
|
|
setTimeout(() => {
|
|
setInterval(performProjectsSlideZoomTransition, 10000);
|
|
}, 2000);
|
|
}
|
|
|
|
// Image enlargement functionality
|
|
function enlargeImage() {
|
|
if (!currentProject) return;
|
|
|
|
const enlargedImage = document.getElementById("enlargedImage");
|
|
const enlargedImageCounter = document.getElementById(
|
|
"enlargedImageCounter"
|
|
);
|
|
const enlargedTotalImages = document.getElementById(
|
|
"enlargedTotalImages"
|
|
);
|
|
const enlargePrevButton = document.getElementById("enlargePrevImage");
|
|
const enlargeNextButton = document.getElementById("enlargeNextImage");
|
|
const closeEnlargeModal = document.getElementById("closeEnlargeModal");
|
|
|
|
// Set initial image and counter
|
|
enlargedImage.src = currentProject.images[currentImageIndex];
|
|
enlargedImage.alt = currentProject.name;
|
|
enlargedImageCounter.textContent = currentImageIndex + 1;
|
|
enlargedTotalImages.textContent = currentProject.images.length;
|
|
|
|
// Navigation functions for enlarged image
|
|
window.goToEnlargedImage = function (index) {
|
|
currentImageIndex = index;
|
|
enlargedImageCounter.textContent = index + 1;
|
|
enlargedImage.src = currentProject.images[index];
|
|
|
|
// Update main modal image and dots
|
|
const modalMainImage = document.getElementById("modalMainImage");
|
|
const imageDots = document.getElementById("imageDots");
|
|
|
|
modalMainImage.src = currentProject.images[index];
|
|
modalMainImage.alt = currentProject.name;
|
|
|
|
// Update dots in main modal
|
|
const dots = imageDots.querySelectorAll("button");
|
|
dots.forEach((dot, dotIndex) => {
|
|
dot.classList.toggle("bg-kh3-red", dotIndex === index);
|
|
dot.classList.toggle("bg-white/30", dotIndex !== index);
|
|
});
|
|
|
|
// Update image counter in main modal
|
|
document.getElementById("imageCounter").textContent = index + 1;
|
|
};
|
|
|
|
window.enlargePrevImage = function () {
|
|
const newIndex =
|
|
currentImageIndex === 0
|
|
? currentProject.images.length - 1
|
|
: currentImageIndex - 1;
|
|
goToEnlargedImage(newIndex);
|
|
};
|
|
|
|
window.enlargeNextImage = function () {
|
|
const newIndex =
|
|
currentImageIndex === currentProject.images.length - 1
|
|
? 0
|
|
: currentImageIndex + 1;
|
|
goToEnlargedImage(newIndex);
|
|
};
|
|
|
|
window.closeEnlargeModal = function () {
|
|
document.getElementById("imageEnlargeModal").classList.add("hidden");
|
|
document.body.style.overflow = "auto";
|
|
};
|
|
|
|
// Event listeners for enlarged image
|
|
enlargePrevButton.onclick = window.enlargePrevImage;
|
|
enlargeNextButton.onclick = window.enlargeNextImage;
|
|
closeEnlargeModal.onclick = window.closeEnlargeModal;
|
|
|
|
// Close enlarged modal when clicking outside
|
|
document
|
|
.getElementById("imageEnlargeModal")
|
|
.addEventListener("click", function (e) {
|
|
if (e.target === this) {
|
|
window.closeEnlargeModal();
|
|
}
|
|
});
|
|
|
|
// Keyboard navigation for enlarged image
|
|
document.addEventListener("keydown", function (e) {
|
|
if (
|
|
!document
|
|
.getElementById("imageEnlargeModal")
|
|
.classList.contains("hidden")
|
|
) {
|
|
if (e.key === "ArrowLeft") {
|
|
window.enlargePrevImage();
|
|
} else if (e.key === "ArrowRight") {
|
|
window.enlargeNextImage();
|
|
} else if (e.key === "Escape") {
|
|
window.closeEnlargeModal();
|
|
}
|
|
}
|
|
});
|
|
|
|
document.getElementById("imageEnlargeModal").classList.remove("hidden");
|
|
document.body.style.overflow = "hidden";
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|