mirror of
https://git.kh3group.com/georgebiri/khy_website.git
synced 2026-07-02 06:23:33 +00:00
refactor: remove blog and quote pages along with related scripts and data, streamline navigation and enhance overall site structure
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
be36d6aa3c
commit
8fe919c449
11 changed files with 274 additions and 3127 deletions
530
blog.html
530
blog.html
|
|
@ -1,530 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Blog - KHY</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Read our latest blog posts about furniture design and interior styling."
|
||||
/>
|
||||
<link rel="stylesheet" href="styles/main.css" />
|
||||
<style>
|
||||
/* Smooth scrolling for the entire page */
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* Active navigation link styling */
|
||||
.nav-link.active {
|
||||
color: #b8873f !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Force responsive behavior */
|
||||
@media (min-width: 640px) {
|
||||
.sm\:hidden {
|
||||
display: none !important;
|
||||
}
|
||||
.sm\:flex {
|
||||
display: flex !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&family=Playfair+Display:wght@100;200;300;400;500;600;700&family=Poppins:wght@400;500;600&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
<body class="bg-white font-sans text-gray-800">
|
||||
<!-- Header -->
|
||||
<header
|
||||
class="fixed w-full h-20 sm:h-28 top-0 left-0 bg-white shadow-[0_8px_24px_rgba(0,0,0,0.06)] border-b border-black/10 z-50"
|
||||
>
|
||||
<nav class="h-full">
|
||||
<div
|
||||
class="max-w-7xl mx-auto h-full flex items-center justify-between px-5"
|
||||
>
|
||||
<!-- Logo Section -->
|
||||
<div class="flex items-center">
|
||||
<img
|
||||
src="assets/images/khy_logo.png"
|
||||
alt="KHY Logo"
|
||||
class="h-12 sm:h-20 w-auto drop-shadow-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Desktop Navigation -->
|
||||
<ul class="hidden sm:flex space-x-10">
|
||||
<li>
|
||||
<a
|
||||
href="index.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Home</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#products"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#projects-button"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#clients"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#about"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>About</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="contact.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Mobile Quote Button and Hamburger -->
|
||||
<div class="sm:hidden flex items-center space-x-3">
|
||||
<!-- Quote Button -->
|
||||
<a
|
||||
href="quote.html"
|
||||
class="px-3 py-1 border border-black text-black font-playfair text-sm font-normal tracking-wider hover:bg-black hover:text-white transition-colors"
|
||||
>
|
||||
Quote
|
||||
</a>
|
||||
|
||||
<!-- Hamburger Button -->
|
||||
<button
|
||||
id="mobile-menu-button"
|
||||
class="text-black hover:text-gray-600 transition-colors"
|
||||
aria-label="Open mobile menu"
|
||||
>
|
||||
<svg
|
||||
class="w-7 h-7"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6h16M4 12h16M4 18h16"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<!-- Mobile Menu Overlay -->
|
||||
<div
|
||||
id="mobile-menu-overlay"
|
||||
class="fixed inset-0 bg-black bg-opacity-50 z-40 hidden transition-opacity duration-300 sm:hidden"
|
||||
></div>
|
||||
|
||||
<!-- Mobile Menu -->
|
||||
<div
|
||||
id="mobile-menu"
|
||||
class="fixed top-0 right-0 h-full w-80 bg-white shadow-xl z-50 transform translate-x-full transition-transform duration-300 sm:hidden"
|
||||
>
|
||||
<!-- Mobile Menu Header -->
|
||||
<div
|
||||
class="flex items-center justify-between p-5 border-b border-gray-200"
|
||||
>
|
||||
<img
|
||||
src="assets/images/khy_logo.png"
|
||||
alt="KHY Logo"
|
||||
class="h-10 w-auto"
|
||||
/>
|
||||
<button
|
||||
id="mobile-menu-close"
|
||||
class="p-2 text-black hover:text-gray-600 transition-colors"
|
||||
aria-label="Close mobile menu"
|
||||
>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Menu Items -->
|
||||
<nav class="p-5">
|
||||
<ul class="flex flex-col space-y-4">
|
||||
<li>
|
||||
<a
|
||||
href="index.html"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Home</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#products"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#projects-button"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#clients"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#about"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>About</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="contact.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<main>
|
||||
<!-- Hero Section -->
|
||||
<section class="relative h-80 mt-20 sm:mt-28">
|
||||
<!-- Background Image -->
|
||||
<div class="absolute inset-0 w-full h-full">
|
||||
<img
|
||||
src="assets/images/first_homepage.jpg"
|
||||
alt="Modern office interior"
|
||||
class="w-full h-full object-cover object-center"
|
||||
style="filter: blur(3px)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- White Overlay -->
|
||||
<div class="absolute inset-0 bg-white bg-opacity-60"></div>
|
||||
|
||||
<!-- Overlay Content -->
|
||||
<div
|
||||
class="absolute z-10 inset-0 flex items-center justify-center text-center text-black"
|
||||
>
|
||||
<h1
|
||||
class="font-playfair font-medium text-4xl md:text-5xl lg:text-6xl leading-tight"
|
||||
>
|
||||
Blog
|
||||
</h1>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Blog Content Section -->
|
||||
<section class="relative bg-white py-20">
|
||||
<div class="max-w-7xl mx-auto px-5">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-16">
|
||||
<!-- Main Blog Content -->
|
||||
<div class="lg:col-span-2 order-2 lg:order-1">
|
||||
<div id="main-blog-content">
|
||||
<!-- Blog posts will be dynamically loaded here -->
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div
|
||||
id="blog-pagination"
|
||||
class="flex items-center justify-center space-x-4 mt-10"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
data-page="1"
|
||||
class="blog-page-btn inline-flex items-center justify-center px-6 py-2 bg-uc-gold text-white font-playfair font-normal text-xl rounded-full shadow-sm"
|
||||
>
|
||||
1
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-page="2"
|
||||
class="blog-page-btn inline-flex items-center justify-center px-6 py-2 bg-linen text-black font-playfair font-normal text-xl rounded-full hover:bg-uc-gold hover:text-white transition-all shadow-sm"
|
||||
>
|
||||
2
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-page="3"
|
||||
class="blog-page-btn inline-flex items-center justify-center px-6 py-2 bg-linen text-black font-playfair font-normal text-xl rounded-full hover:bg-uc-gold hover:text-white transition-all shadow-sm"
|
||||
>
|
||||
3
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
id="blog-next-btn"
|
||||
class="inline-flex items-center justify-center px-6 py-2 bg-linen text-black font-playfair font-normal text-xl rounded-full hover:bg-uc-gold hover:text-white transition-all shadow-sm"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div class="lg:col-span-1 order-1 lg:order-2 flex flex-col">
|
||||
<!-- Search -->
|
||||
<div
|
||||
class="bg-white p-6 rounded-lg shadow-sm mb-8 order-3 lg:order-1"
|
||||
>
|
||||
<div class="relative">
|
||||
<input
|
||||
id="blog-search-input"
|
||||
type="text"
|
||||
placeholder="Search..."
|
||||
class="w-full px-4 py-3 font-playfair font-normal text-base text-gray-500 bg-white border border-gray-300 rounded-lg focus:outline-none focus:border-uc-gold pr-12"
|
||||
/>
|
||||
<img
|
||||
src="assets/icons/search.png"
|
||||
alt="Search"
|
||||
class="absolute right-4 top-1/2 transform -translate-y-1/2 w-6 h-6"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Categories -->
|
||||
<div
|
||||
class="bg-white p-6 rounded-lg shadow-sm mb-8 order-2 lg:order-2"
|
||||
>
|
||||
<h3 class="font-playfair font-medium text-2xl text-black mb-6">
|
||||
Categories
|
||||
</h3>
|
||||
<div id="blog-categories" class="space-y-4">
|
||||
<!-- Categories will be dynamically loaded here -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Posts -->
|
||||
<div class="bg-white p-6 rounded-lg shadow-sm order-1 lg:order-3">
|
||||
<h3 class="font-playfair font-medium text-2xl text-black mb-6">
|
||||
Recent Posts
|
||||
</h3>
|
||||
<div id="recent-posts" class="space-y-6">
|
||||
<!-- Recent posts will be dynamically loaded here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="bg-white border-t border-black border-opacity-20">
|
||||
<!-- Main Footer Content -->
|
||||
<div class="max-w-7xl mx-auto px-5 py-16">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
<!-- Company Information -->
|
||||
<div class="space-y-1">
|
||||
<!-- Logo -->
|
||||
<div class="w-16 h-20 -mt-6">
|
||||
<a
|
||||
href="index.html"
|
||||
aria-label="Go to KHY home"
|
||||
title="KHY Home"
|
||||
class="inline-block w-full h-full group focus:outline-none focus-visible:ring-2 focus-visible:ring-uc-gold rounded-md transition"
|
||||
>
|
||||
<img
|
||||
src="assets/images/khy_logo.png"
|
||||
alt="KHY logo"
|
||||
loading="lazy"
|
||||
class="w-full h-full object-contain transition-transform duration-300 group-hover:scale-105"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Address -->
|
||||
<p
|
||||
class="font-playfair font-normal text-base leading-relaxed text-gray-600 -mt-4"
|
||||
>
|
||||
5 Labone Crescent, Greater Accra, Ghana
|
||||
</p>
|
||||
|
||||
<!-- Contact Info -->
|
||||
<div class="space-y-1 -mt-2">
|
||||
<!-- Phone -->
|
||||
<div class="flex items-center space-x-3 -mt-1">
|
||||
<img
|
||||
src="assets/images/phone.png"
|
||||
alt="Phone"
|
||||
class="w-4 h-4"
|
||||
/>
|
||||
<span class="font-playfair font-normal text-base text-gray-800">
|
||||
+233 (555) 76677
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Email -->
|
||||
<div class="flex items-center space-x-3 -mt-1">
|
||||
<img src="assets/images/mail.png" alt="Email" class="w-4 h-4" />
|
||||
<span class="font-playfair font-normal text-base text-gray-800">
|
||||
design@khyltd.com
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Links -->
|
||||
<div class="space-y-6">
|
||||
<h3
|
||||
class="font-playfair font-normal text-md leading-relaxed tracking-wider text-eerie-black uppercase"
|
||||
>
|
||||
Quick Links
|
||||
</h3>
|
||||
<div class="space-y-4">
|
||||
<a
|
||||
href="#"
|
||||
class="block font-playfair font-normal text-base leading-relaxed tracking-wider text-gray-800 hover:text-black transition-colors"
|
||||
>
|
||||
Home
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block font-playfair font-normal text-base leading-relaxed tracking-wider text-gray-800 hover:text-black transition-colors"
|
||||
>
|
||||
Products
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block font-playfair font-normal text-base leading-relaxed tracking-wider text-gray-800 hover:text-black transition-colors"
|
||||
>
|
||||
About
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Help -->
|
||||
<div class="space-y-6">
|
||||
<h3
|
||||
class="font-playfair font-normal text-md leading-relaxed tracking-wider text-eerie-black uppercase"
|
||||
>
|
||||
Help
|
||||
</h3>
|
||||
<div class="space-y-4">
|
||||
<a
|
||||
href="#"
|
||||
class="block font-playfair font-normal text-base leading-relaxed tracking-wider text-gray-800 hover:text-black transition-colors"
|
||||
>
|
||||
Contact Us
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block font-playfair font-normal text-base leading-relaxed tracking-wider text-gray-800 hover:text-black transition-colors"
|
||||
>
|
||||
Privacy Policies
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block font-playfair font-normal text-base leading-relaxed tracking-wider text-gray-800 hover:text-black transition-colors"
|
||||
>
|
||||
Terms and Conditions
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Newsletter -->
|
||||
<div class="space-y-6">
|
||||
<h3
|
||||
class="font-playfair font-normal text-md leading-relaxed tracking-wider text-eerie-black uppercase"
|
||||
>
|
||||
Newsletter
|
||||
</h3>
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center space-x-4">
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Enter Your Email Address"
|
||||
class="flex-1 font-playfair font-normal text-sm leading-relaxed tracking-wider text-taupe-gray bg-transparent border-b border-black focus:outline-none focus:border-black"
|
||||
/>
|
||||
<button
|
||||
class="font-playfair font-normal text-sm leading-relaxed tracking-wider text-gray-800 border-b border-black hover:text-black transition-colors"
|
||||
>
|
||||
Subscribe
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Copyright Section -->
|
||||
<div class="border-t border-light-silver">
|
||||
<div class="max-w-7xl mx-auto px-5 py-4">
|
||||
<p
|
||||
class="font-playfair font-normal text-xs leading-relaxed text-davys-grey"
|
||||
>
|
||||
© 2025 khy. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="scripts/main.js?v=4.2"></script>
|
||||
</body>
|
||||
</html>
|
||||
185
contact.html
185
contact.html
|
|
@ -70,20 +70,6 @@
|
|||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#projects-button"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#clients"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#about"
|
||||
|
|
@ -98,32 +84,10 @@
|
|||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Mobile Quote Button and Hamburger -->
|
||||
<div class="sm:hidden flex items-center space-x-3">
|
||||
<!-- Quote Button -->
|
||||
<a
|
||||
href="quote.html"
|
||||
class="px-3 py-1 border border-black text-black font-playfair text-sm font-normal tracking-wider hover:bg-black hover:text-white transition-colors"
|
||||
>
|
||||
Quote
|
||||
</a>
|
||||
|
||||
<!-- Mobile Hamburger -->
|
||||
<div class="sm:hidden flex items-center">
|
||||
<!-- Hamburger Button -->
|
||||
<button
|
||||
id="mobile-menu-button"
|
||||
|
|
@ -161,14 +125,7 @@
|
|||
class="fixed top-0 right-0 h-full w-80 bg-white shadow-xl z-50 transform translate-x-full transition-transform duration-300 sm:hidden"
|
||||
>
|
||||
<!-- Mobile Menu Header -->
|
||||
<div
|
||||
class="flex items-center justify-between p-5 border-b border-gray-200"
|
||||
>
|
||||
<img
|
||||
src="assets/images/khy_logo.png"
|
||||
alt="KHY Logo"
|
||||
class="h-10 w-auto"
|
||||
/>
|
||||
<div class="flex items-center justify-end p-5 border-b border-gray-200">
|
||||
<button
|
||||
id="mobile-menu-close"
|
||||
class="p-2 text-black hover:text-gray-600 transition-colors"
|
||||
|
|
@ -207,20 +164,6 @@
|
|||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#projects-button"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#clients"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#about"
|
||||
|
|
@ -235,20 +178,6 @@
|
|||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
@ -472,6 +401,114 @@
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quote Request Section -->
|
||||
<div class="mt-20 bg-gray-50 p-8 rounded-lg">
|
||||
<div class="text-center mb-8">
|
||||
<h3
|
||||
class="font-playfair font-bold text-2xl md:text-3xl leading-tight text-black mb-4"
|
||||
>
|
||||
Need a Quote?
|
||||
</h3>
|
||||
<p
|
||||
class="font-playfair font-normal text-base leading-relaxed text-gray-600 max-w-2xl mx-auto"
|
||||
>
|
||||
Looking for a custom quote for your furniture needs? Simply
|
||||
provide your contact information above and mention "Quote
|
||||
Request" in your message. Our team will get back to you with a
|
||||
personalized quote tailored to your requirements.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 text-center">
|
||||
<div class="bg-white p-6 rounded-lg shadow-sm">
|
||||
<div
|
||||
class="w-12 h-12 bg-uc-gold 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="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h4 class="font-playfair font-semibold text-lg text-black mb-2">
|
||||
Quick Response
|
||||
</h4>
|
||||
<p class="font-playfair font-normal text-sm text-gray-600">
|
||||
We'll get back to you within 24 hours with your personalized
|
||||
quote.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-white p-6 rounded-lg shadow-sm">
|
||||
<div
|
||||
class="w-12 h-12 bg-uc-gold 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="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h4 class="font-playfair font-semibold text-lg text-black mb-2">
|
||||
Competitive Pricing
|
||||
</h4>
|
||||
<p class="font-playfair font-normal text-sm text-gray-600">
|
||||
Get the best value with our competitive and transparent
|
||||
pricing.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-white p-6 rounded-lg shadow-sm">
|
||||
<div
|
||||
class="w-12 h-12 bg-uc-gold 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="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>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h4 class="font-playfair font-semibold text-lg text-black mb-2">
|
||||
Local Service
|
||||
</h4>
|
||||
<p class="font-playfair font-normal text-sm text-gray-600">
|
||||
Serving Greater Accra with quality furniture and excellent
|
||||
service.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
|
|||
104
data/blog.json
104
data/blog.json
|
|
@ -1,104 +0,0 @@
|
|||
{
|
||||
"posts": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Going all-in with millennial design",
|
||||
"excerpt": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Mus mauris vitae ultricies leo integer malesuada nunc. In nulla posuere sollicitudin aliquam ultrices. Morbi blandit cursus risus at ultrices mi tempus imperdiet. Libero enim sed faucibus turpis in. Cursus mattis molestie a iaculis at erat. Nibh cras pulvinar mattis nunc sed blandit libero. Pellentesque elit ullamcorper dignissim cras tincidunt. Pharetra et ultrices neque ornare aenean euismod elementum. The millennial generation has redefined what it means to create a home that reflects both personal style and contemporary values. This design philosophy embraces clean lines, sustainable materials, and multifunctional spaces that adapt to the ever-changing needs of modern life. From open-concept layouts that foster social interaction to smart home technology that enhances daily convenience, millennial design prioritizes both aesthetics and functionality.",
|
||||
"content": [
|
||||
"Quis hendrerit dolor magna eget est lorem ipsum. Bibendum arcu vitae elementum curabitur vitae nunc sed velit dignissim sodales. Non tellus orci ac auctor augue mauris augue neque gravida in. Nisl condimentum id venenatis a condimentum vitae sapien pellentesque habitant. Sit amet volutpat consequat mauris nunc congue nisi vitae suscipit. Integer enim neque volutpat ac tincidunt vitae semper quis lectus. Nibh tellus molestie nunc non blandit massa enim nec. Amet consectetur adipiscing elit ut aliquam purus sit amet luctus.",
|
||||
"At tellus at urna condimentum mattis pellentesque id nibh tortor id. Non quam lacus suspendisse faucibus interdum. Interdum velit euismod in pellentesque massa placerat duis ultricies. Platea dictumst quisque sagittis purus sit amet volutpat consequat. Sem viverra aliquet eget sit amet tellus cras adipiscing. Eget lorem dolor sed viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis a cras.",
|
||||
"Mattis rhoncus urna neque viverra justo nec. Aliquet porttitor lacus luctus accumsan tortor posuere ac ut consequat semper viverra nam libero justo laoreet sit amet cursus sit amet dictum sit amet justo. Risus at ultrices mi tempus imperdiet nulla malesuada pellentesque elit.",
|
||||
"The millennial generation has redefined what it means to create a home that reflects both personal style and contemporary values. This design philosophy embraces clean lines, sustainable materials, and multifunctional spaces that adapt to the ever-changing needs of modern life. From open-concept layouts that foster social interaction to smart home technology that enhances daily convenience, millennial design prioritizes both aesthetics and functionality.",
|
||||
"One of the most significant aspects of millennial design is its emphasis on sustainability and ethical consumption. Young homeowners are increasingly choosing furniture and decor that not only looks good but also aligns with their environmental values. This includes pieces made from responsibly sourced materials, vintage and upcycled items that reduce waste, and locally crafted goods that support small businesses and reduce carbon footprints.",
|
||||
"The color palette of millennial design often features neutral tones as a foundation, with strategic pops of color that reflect personal taste and current trends. Soft grays, warm whites, and natural wood tones create a calming backdrop, while accent colors like sage green, dusty rose, and deep navy add personality without overwhelming the space. This approach allows for easy updates and seasonal changes without requiring major renovations.",
|
||||
"Technology integration is another hallmark of millennial design, with smart home features seamlessly incorporated into the aesthetic. From hidden charging stations to voice-controlled lighting systems, technology enhances the living experience without compromising the visual appeal of the space. This balance between high-tech functionality and timeless design creates homes that are both modern and enduring."
|
||||
],
|
||||
"author": "Admin",
|
||||
"date": "2022-10-14",
|
||||
"tags": ["design"],
|
||||
"image": "assets/images/blog_post_1.png",
|
||||
"thumbnail": "assets/images/blog_thumb_1.png",
|
||||
"alt": "Going all-in with millennial design"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "How to create the perfect living room",
|
||||
"excerpt": "Designing the perfect living room requires careful consideration of space, functionality, and personal style. From choosing the right furniture pieces to creating a cohesive color scheme, every element plays a crucial role in crafting a space that feels both welcoming and reflective of your lifestyle. Let's explore the key principles that make a living room truly exceptional. The foundation of any great living room begins with understanding the space you're working with. Consider the room's dimensions, natural light sources, and traffic flow. These factors will guide your furniture placement and help you create a layout that maximizes both comfort and functionality. When selecting furniture, prioritize pieces that serve multiple purposes and create a harmonious balance between form and function.",
|
||||
"content": [
|
||||
"The foundation of any great living room begins with understanding the space you're working with. Consider the room's dimensions, natural light sources, and traffic flow. These factors will guide your furniture placement and help you create a layout that maximizes both comfort and functionality.",
|
||||
"When selecting furniture, prioritize pieces that serve multiple purposes. A comfortable sofa that can accommodate family gatherings, an accent chair that adds personality, and a coffee table that provides both surface area and storage can transform your living room into a versatile space that adapts to your daily needs.",
|
||||
"Color and texture play vital roles in creating atmosphere. Choose a color palette that reflects your personal style while maintaining harmony throughout the space. Layer different textures through rugs, throw pillows, and decorative elements to add depth and visual interest."
|
||||
],
|
||||
"author": "Admin",
|
||||
"date": "2022-11-05",
|
||||
"tags": ["design"],
|
||||
"image": "assets/images/conference_room.jpg",
|
||||
"thumbnail": "assets/images/conference_room.jpg",
|
||||
"alt": "Perfect living room design"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Sustainable furniture choices for modern homes",
|
||||
"excerpt": "As environmental consciousness grows, more homeowners are seeking sustainable furniture options that align with their values. From responsibly sourced materials to eco-friendly manufacturing processes, sustainable furniture offers both environmental benefits and long-term value. Discover how to make informed choices that benefit both your home and the planet. Sustainable furniture begins with the materials used in its construction. Look for pieces made from responsibly harvested wood, such as FSC-certified timber, or consider alternatives like bamboo, which grows rapidly and requires minimal resources. These materials not only reduce environmental impact but also often provide superior durability and timeless appeal.",
|
||||
"content": [
|
||||
"Sustainable furniture begins with the materials used in its construction. Look for pieces made from responsibly harvested wood, such as FSC-certified timber, or consider alternatives like bamboo, which grows rapidly and requires minimal resources. These materials not only reduce environmental impact but also often provide superior durability.",
|
||||
"Manufacturing processes also play a crucial role in sustainability. Choose furniture from companies that prioritize energy-efficient production methods, minimize waste, and use non-toxic finishes. Many sustainable furniture makers also offer repair services and replacement parts, extending the lifespan of your investment.",
|
||||
"Consider the full lifecycle of your furniture choices. Opt for timeless designs that won't quickly go out of style, and invest in quality pieces that can be passed down through generations. This approach reduces the need for frequent replacements and creates a more sustainable consumption pattern."
|
||||
],
|
||||
"author": "Admin",
|
||||
"date": "2022-12-20",
|
||||
"tags": ["sustainability"],
|
||||
"image": "assets/images/kitchen.JPG",
|
||||
"thumbnail": "assets/images/kitchen.JPG",
|
||||
"alt": "Sustainable furniture choices"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"title": "The art of mixing vintage and contemporary pieces",
|
||||
"excerpt": "Creating a home that feels both timeless and current requires mastering the art of mixing vintage and contemporary furniture. This approach allows you to tell a story through your decor while maintaining a cohesive and functional space. Learn how to balance different eras and styles to create a home that's uniquely yours. The key to successfully mixing vintage and contemporary pieces lies in finding common threads that unite them. Look for shared design elements such as similar lines, complementary colors, or matching materials. A vintage wooden table might pair beautifully with modern chairs if they share similar wood tones or geometric shapes.",
|
||||
"content": [
|
||||
"The key to successfully mixing vintage and contemporary pieces lies in finding common threads that unite them. Look for shared design elements such as similar lines, complementary colors, or matching materials. A vintage wooden table might pair beautifully with modern chairs if they share similar wood tones or geometric shapes.",
|
||||
"Scale and proportion are crucial when combining different eras. Ensure that vintage and contemporary pieces work together in terms of size and visual weight. A large vintage armoire might overwhelm a room filled with delicate modern furniture, while smaller vintage accents can add character without dominating the space.",
|
||||
"Don't be afraid to experiment with unexpected combinations. Sometimes the most interesting interiors come from pairing pieces that seem to have nothing in common. The contrast between a sleek modern sofa and a rustic vintage coffee table can create a dynamic and engaging space that reflects your personal style."
|
||||
],
|
||||
"author": "Admin",
|
||||
"date": "2023-01-15",
|
||||
"tags": ["vintage"],
|
||||
"image": "assets/images/lounge_chair.jpg",
|
||||
"thumbnail": "assets/images/lounge_chair.jpg",
|
||||
"alt": "Mixing vintage and contemporary furniture"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"title": "Maximizing small spaces with smart furniture solutions",
|
||||
"excerpt": "Living in a smaller space doesn't mean sacrificing style or functionality. With the right furniture choices and design strategies, you can create a home that feels spacious, organized, and beautiful. Discover innovative solutions that make the most of every square foot while maintaining your personal aesthetic. Multi-functional furniture is essential in small spaces. Look for pieces that serve multiple purposes, such as ottomans with hidden storage, sofa beds for guest accommodation, or dining tables that can expand when needed. These versatile pieces help you maximize functionality without cluttering your space.",
|
||||
"content": [
|
||||
"Multi-functional furniture is essential in small spaces. Look for pieces that serve multiple purposes, such as ottomans with hidden storage, sofa beds for guest accommodation, or dining tables that can expand when needed. These versatile pieces help you maximize functionality without cluttering your space.",
|
||||
"Vertical storage solutions can dramatically increase your usable space. Wall-mounted shelves, tall bookcases, and hanging organizers keep your belongings organized while freeing up valuable floor space. Consider custom storage solutions that fit perfectly into awkward corners or underutilized areas.",
|
||||
"The right color palette and lighting can make a small space feel much larger. Light, neutral colors reflect natural light and create an airy atmosphere, while strategic lighting can highlight focal points and create depth. Mirrors are also excellent tools for making small spaces feel more expansive."
|
||||
],
|
||||
"author": "Admin",
|
||||
"date": "2023-02-28",
|
||||
"tags": ["design"],
|
||||
"image": "assets/images/storage.jpg",
|
||||
"thumbnail": "assets/images/storage.jpg",
|
||||
"alt": "Small space furniture solutions"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"title": "Color psychology in home design",
|
||||
"excerpt": "Colors have a profound impact on our emotions, mood, and overall well-being. Understanding color psychology can help you create spaces that not only look beautiful but also support your desired atmosphere and lifestyle. Explore how different colors can transform your home and enhance your daily experience. Warm colors like red, orange, and yellow create energy and excitement, making them perfect for social spaces like dining rooms and living areas. These colors stimulate conversation and appetite, making them ideal for areas where you entertain guests or share meals with family.",
|
||||
"content": [
|
||||
"Warm colors like red, orange, and yellow create energy and excitement, making them perfect for social spaces like dining rooms and living areas. These colors stimulate conversation and appetite, making them ideal for areas where you entertain guests or share meals with family.",
|
||||
"Cool colors such as blue, green, and purple promote calmness and relaxation. These hues are excellent choices for bedrooms, bathrooms, and home offices where you want to create a peaceful, focused environment. Different shades can evoke different moods - deep navy creates sophistication while soft lavender promotes tranquility.",
|
||||
"Neutral colors provide a versatile foundation that allows you to experiment with accent colors and seasonal changes. Whites, grays, and beiges create a timeless backdrop that can be easily updated with colorful accessories, artwork, or seasonal decor without requiring major furniture changes."
|
||||
],
|
||||
"author": "Admin",
|
||||
"date": "2023-03-12",
|
||||
"tags": ["vintage"],
|
||||
"image": "assets/images/chairs.jpg",
|
||||
"thumbnail": "assets/images/chairs.jpg",
|
||||
"alt": "Color psychology in home design"
|
||||
}
|
||||
]
|
||||
}
|
||||
90
index.html
90
index.html
|
|
@ -207,20 +207,6 @@
|
|||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#projects-button"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#clients"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#about"
|
||||
|
|
@ -235,32 +221,10 @@
|
|||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Mobile Quote Button and Hamburger -->
|
||||
<div class="sm:hidden flex items-center space-x-3">
|
||||
<!-- Quote Button -->
|
||||
<a
|
||||
href="quote.html"
|
||||
class="px-3 py-1 border border-black text-black font-playfair text-sm font-normal tracking-wider hover:bg-black hover:text-white transition-colors"
|
||||
>
|
||||
Quote
|
||||
</a>
|
||||
|
||||
<!-- Mobile Hamburger -->
|
||||
<div class="sm:hidden flex items-center">
|
||||
<!-- Hamburger Button -->
|
||||
<button
|
||||
id="mobile-menu-button"
|
||||
|
|
@ -298,14 +262,7 @@
|
|||
class="fixed top-0 right-0 h-full w-80 bg-white shadow-xl z-50 transform translate-x-full transition-transform duration-300 sm:hidden"
|
||||
>
|
||||
<!-- Mobile Menu Header -->
|
||||
<div
|
||||
class="flex items-center justify-between p-5 border-b border-gray-200"
|
||||
>
|
||||
<img
|
||||
src="assets/images/khy_logo.png"
|
||||
alt="KHY Logo"
|
||||
class="h-10 w-auto"
|
||||
/>
|
||||
<div class="flex items-center justify-end p-5 border-b border-gray-200">
|
||||
<button
|
||||
id="mobile-menu-close"
|
||||
class="p-2 text-black hover:text-gray-600 transition-colors"
|
||||
|
|
@ -344,20 +301,6 @@
|
|||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#projects-button"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#clients"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#about"
|
||||
|
|
@ -372,20 +315,6 @@
|
|||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
@ -527,7 +456,7 @@
|
|||
<!-- Section Header -->
|
||||
<div class="text-center mb-16">
|
||||
<h2
|
||||
class="font-playfair font-bold text-xl md:text-2xl lg:text-3xl leading-tight text-black"
|
||||
class="font-playfair font-bold text-3xl md:text-3xl lg:text-4xl leading-tight text-black"
|
||||
>
|
||||
Our Story
|
||||
</h2>
|
||||
|
|
@ -536,7 +465,7 @@
|
|||
<!-- Main Content -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-28 items-center">
|
||||
<!-- Left Side - Image -->
|
||||
<div id="hero-image" class="relative">
|
||||
<div id="hero-image" class="relative order-2 lg:order-1">
|
||||
<img
|
||||
src="assets/images/our_story.jpg"
|
||||
alt="Modern office interior"
|
||||
|
|
@ -592,7 +521,7 @@
|
|||
</div>
|
||||
|
||||
<!-- Right Side - Text Content -->
|
||||
<div class="space-y-16">
|
||||
<div class="space-y-16 order-1 lg:order-2">
|
||||
<h3
|
||||
class="font-playfair font-normal text-3xl md:text-4xl lg:text-5xl leading-loose text-black"
|
||||
>
|
||||
|
|
@ -611,13 +540,6 @@
|
|||
Khy brings timeless, curated furniture and decor to offices that
|
||||
tell a story.
|
||||
</p>
|
||||
|
||||
<button
|
||||
id="projects-button"
|
||||
class="bg-black bg-opacity-70 text-white font-playfair font-normal text-xl md:text-2xl lg:text-3xl leading-tight tracking-wider px-8 py-4 rounded-lg hover:bg-opacity-80 transition-all text-center max-w-sm attention-animation"
|
||||
>
|
||||
Explore past projects
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -53,20 +53,6 @@
|
|||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#projects-button"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#clients"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#about"
|
||||
|
|
@ -81,31 +67,10 @@
|
|||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Mobile Quote Button and Hamburger -->
|
||||
<div class="sm:hidden flex items-center space-x-3">
|
||||
<!-- Quote Button -->
|
||||
<a
|
||||
href="quote.html"
|
||||
class="px-3 py-1 border border-black text-black font-playfair text-sm font-normal tracking-wider hover:bg-black hover:text-white transition-colors"
|
||||
>
|
||||
Quote
|
||||
</a>
|
||||
<!-- Mobile Hamburger -->
|
||||
<div class="sm:hidden flex items-center">
|
||||
|
||||
<!-- Hamburger Button -->
|
||||
<button
|
||||
|
|
@ -144,12 +109,7 @@
|
|||
class="fixed top-0 right-0 h-full w-80 bg-white shadow-xl z-50 transform translate-x-full transition-transform duration-300 sm:hidden"
|
||||
>
|
||||
<!-- Mobile Menu Header -->
|
||||
<div class="flex items-center justify-between p-5 border-b border-gray-200">
|
||||
<img
|
||||
src="assets/images/khy_logo.png"
|
||||
alt="KHY Logo"
|
||||
class="h-10 w-auto"
|
||||
/>
|
||||
<div class="flex items-center justify-end p-5 border-b border-gray-200">
|
||||
<button
|
||||
id="mobile-menu-close"
|
||||
class="p-2 text-black hover:text-gray-600 transition-colors"
|
||||
|
|
@ -178,20 +138,6 @@
|
|||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#projects-button"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#clients"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#about"
|
||||
|
|
@ -206,20 +152,6 @@
|
|||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -62,20 +62,6 @@
|
|||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#projects-button"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#clients"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#about"
|
||||
|
|
@ -90,32 +76,10 @@
|
|||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Mobile Quote Button and Hamburger -->
|
||||
<div class="sm:hidden flex items-center space-x-3">
|
||||
<!-- Quote Button -->
|
||||
<a
|
||||
href="quote.html"
|
||||
class="px-3 py-1 border border-black text-black font-playfair text-sm font-normal tracking-wider hover:bg-black hover:text-white transition-colors"
|
||||
>
|
||||
Quote
|
||||
</a>
|
||||
|
||||
<!-- Mobile Hamburger -->
|
||||
<div class="sm:hidden flex items-center">
|
||||
<!-- Hamburger Button -->
|
||||
<button
|
||||
id="mobile-menu-button"
|
||||
|
|
@ -153,14 +117,7 @@
|
|||
class="fixed top-0 right-0 h-full w-80 bg-white shadow-xl z-50 transform translate-x-full transition-transform duration-300 sm:hidden"
|
||||
>
|
||||
<!-- Mobile Menu Header -->
|
||||
<div
|
||||
class="flex items-center justify-between p-5 border-b border-gray-200"
|
||||
>
|
||||
<img
|
||||
src="assets/images/khy_logo.png"
|
||||
alt="KHY Logo"
|
||||
class="h-10 w-auto"
|
||||
/>
|
||||
<div class="flex items-center justify-end p-5 border-b border-gray-200">
|
||||
<button
|
||||
id="mobile-menu-close"
|
||||
class="p-2 text-black hover:text-gray-600 transition-colors"
|
||||
|
|
@ -199,20 +156,6 @@
|
|||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#projects-button"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#clients"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#about"
|
||||
|
|
@ -227,20 +170,6 @@
|
|||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
@ -859,25 +788,17 @@
|
|||
<!-- Column 1: Empty space -->
|
||||
<div class="flex-1"></div>
|
||||
|
||||
<!-- Column 2: Add To Quote Button for Asgaard Sofa -->
|
||||
<!-- Column 2: Empty for spacing -->
|
||||
<div class="flex-1 px-6 border-l border-gray-200">
|
||||
<div class="text-center">
|
||||
<button
|
||||
class="bg-uc-gold text-white px-6 py-3 rounded-lg font-playfair font-semibold text-base hover:bg-uc-gold/90 transition-colors"
|
||||
>
|
||||
Add To Quote
|
||||
</button>
|
||||
<!-- Reserved for future functionality -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Column 3: Add To Quote Button for Outdoor Sofa Set -->
|
||||
<!-- Column 3: Empty for spacing -->
|
||||
<div class="flex-1 px-6 border-l border-gray-200 ml-8">
|
||||
<div class="text-center">
|
||||
<button
|
||||
class="bg-uc-gold text-white px-6 py-3 rounded-lg font-playfair font-semibold text-base hover:bg-uc-gold/90 transition-colors"
|
||||
>
|
||||
Add To Quote
|
||||
</button>
|
||||
<!-- Reserved for future functionality -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -55,20 +55,6 @@
|
|||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#projects-button"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#clients"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#about"
|
||||
|
|
@ -83,32 +69,10 @@
|
|||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Mobile Quote Button and Hamburger -->
|
||||
<div class="sm:hidden flex items-center space-x-3">
|
||||
<!-- Quote Button -->
|
||||
<a
|
||||
href="quote.html"
|
||||
class="px-3 py-1 border border-black text-black font-playfair text-sm font-normal tracking-wider hover:bg-black hover:text-white transition-colors"
|
||||
>
|
||||
Quote
|
||||
</a>
|
||||
|
||||
<!-- Mobile Hamburger -->
|
||||
<div class="sm:hidden flex items-center">
|
||||
<!-- Hamburger Button -->
|
||||
<button
|
||||
id="mobile-menu-button"
|
||||
|
|
@ -146,14 +110,7 @@
|
|||
class="fixed top-0 right-0 h-full w-80 bg-white shadow-xl z-50 transform translate-x-full transition-transform duration-300 sm:hidden"
|
||||
>
|
||||
<!-- Mobile Menu Header -->
|
||||
<div
|
||||
class="flex items-center justify-between p-5 border-b border-gray-200"
|
||||
>
|
||||
<img
|
||||
src="assets/images/khy_logo.png"
|
||||
alt="KHY Logo"
|
||||
class="h-10 w-auto"
|
||||
/>
|
||||
<div class="flex items-center justify-end p-5 border-b border-gray-200">
|
||||
<button
|
||||
id="mobile-menu-close"
|
||||
class="p-2 text-black hover:text-gray-600 transition-colors"
|
||||
|
|
@ -192,20 +149,6 @@
|
|||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#projects-button"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#clients"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#about"
|
||||
|
|
@ -220,20 +163,6 @@
|
|||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
@ -415,12 +344,12 @@
|
|||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<button
|
||||
id="add-to-quote-btn"
|
||||
class="inline-flex items-center justify-center w-full md:w-[380px] h-[64px] min-h-[64px] bg-white text-black font-playfair font-light text-[20px] leading-none rounded-[15px] border border-quick-silver hover:bg-uc-gold hover:text-white hover:border-uc-gold hover:shadow-lg transform hover:-translate-y-0.5 transition-all duration-200 box-border whitespace-nowrap"
|
||||
<a
|
||||
href="contact.html"
|
||||
class="inline-flex items-center justify-center w-full md:w-[440px] h-[64px] min-h-[64px] bg-white text-black font-playfair font-light text-[20px] leading-none rounded-[15px] border border-quick-silver hover:bg-black hover:text-white hover:shadow-lg transform hover:-translate-y-0.5 transition-all duration-200 box-border whitespace-nowrap mb-4"
|
||||
>
|
||||
Add To Quote
|
||||
</button>
|
||||
Request a Quote
|
||||
</a>
|
||||
<button
|
||||
id="compare-products-btn"
|
||||
class="inline-flex items-center justify-center w-full md:w-[440px] h-[64px] min-h-[64px] bg-white text-black font-playfair font-light text-[20px] leading-none rounded-[15px] border border-quick-silver hover:bg-black hover:text-white hover:shadow-lg transform hover:-translate-y-0.5 transition-all duration-200 box-border whitespace-nowrap"
|
||||
|
|
@ -736,6 +665,5 @@
|
|||
</footer>
|
||||
|
||||
<script src="scripts/main.js?v=3.5"></script>
|
||||
<script src="scripts/quote.js?v=3.5"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
669
quote.html
669
quote.html
|
|
@ -1,669 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Quote - KHY</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Request a quote for KHY furniture and design services."
|
||||
/>
|
||||
<link rel="stylesheet" href="styles/main.css" />
|
||||
<style>
|
||||
/* Smooth scrolling for the entire page */
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* Active navigation link styling */
|
||||
.nav-link.active {
|
||||
color: #b8873f !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Force responsive behavior */
|
||||
@media (min-width: 640px) {
|
||||
.sm\:hidden {
|
||||
display: none !important;
|
||||
}
|
||||
.sm\:flex {
|
||||
display: flex !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&family=Playfair+Display:wght@100;200;300;400;500;600;700&family=Poppins:wght@400;500;600&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
<body class="bg-white font-sans text-gray-800">
|
||||
<!-- Header -->
|
||||
<header
|
||||
class="fixed w-full h-20 sm:h-28 top-0 left-0 bg-white shadow-[0_8px_24px_rgba(0,0,0,0.06)] border-b border-black/10 z-50"
|
||||
>
|
||||
<nav class="h-full">
|
||||
<div
|
||||
class="max-w-7xl mx-auto h-full flex items-center justify-between px-5"
|
||||
>
|
||||
<!-- Logo Section -->
|
||||
<div class="flex items-center">
|
||||
<img
|
||||
src="assets/images/khy_logo.png"
|
||||
alt="KHY Logo"
|
||||
class="h-12 sm:h-20 w-auto drop-shadow-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Desktop Navigation -->
|
||||
<ul class="hidden sm:flex space-x-10">
|
||||
<li>
|
||||
<a
|
||||
href="index.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Home</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#products"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#projects-button"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#clients"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#about"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>About</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="contact.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="nav-link text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="nav-link active text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors text-shadow-default"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Mobile Quote Button and Hamburger -->
|
||||
<div class="sm:hidden flex items-center space-x-3">
|
||||
<!-- Quote Button -->
|
||||
<a
|
||||
href="quote.html"
|
||||
class="px-3 py-1 border border-black text-black font-playfair text-sm font-normal tracking-wider hover:bg-black hover:text-white transition-colors"
|
||||
>
|
||||
Quote
|
||||
</a>
|
||||
|
||||
<!-- Hamburger Button -->
|
||||
<button
|
||||
id="mobile-menu-button"
|
||||
class="text-black hover:text-gray-600 transition-colors"
|
||||
aria-label="Open mobile menu"
|
||||
>
|
||||
<svg
|
||||
class="w-7 h-7"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6h16M4 12h16M4 18h16"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<!-- Mobile Menu Overlay -->
|
||||
<div
|
||||
id="mobile-menu-overlay"
|
||||
class="fixed inset-0 bg-black bg-opacity-50 z-40 hidden transition-opacity duration-300 sm:hidden"
|
||||
></div>
|
||||
|
||||
<!-- Mobile Menu -->
|
||||
<div
|
||||
id="mobile-menu"
|
||||
class="fixed top-0 right-0 h-full w-80 bg-white shadow-xl z-50 transform translate-x-full transition-transform duration-300 sm:hidden"
|
||||
>
|
||||
<!-- Mobile Menu Header -->
|
||||
<div
|
||||
class="flex items-center justify-between p-5 border-b border-gray-200"
|
||||
>
|
||||
<img
|
||||
src="assets/images/khy_logo.png"
|
||||
alt="KHY Logo"
|
||||
class="h-10 w-auto"
|
||||
/>
|
||||
<button
|
||||
id="mobile-menu-close"
|
||||
class="p-2 text-black hover:text-gray-600 transition-colors"
|
||||
aria-label="Close mobile menu"
|
||||
>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Menu Items -->
|
||||
<nav class="p-5">
|
||||
<ul class="flex flex-col space-y-4">
|
||||
<li>
|
||||
<a
|
||||
href="index.html"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Home</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#products"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#projects-button"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Projects</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#clients"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Clients</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="index.html#about"
|
||||
class="nav-link block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>About</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="contact.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Contact</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="blog.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="quote.html"
|
||||
class="block text-black hover:text-gray-600 font-playfair text-md font-extralight tracking-wider transition-colors py-2"
|
||||
>Quote</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<main>
|
||||
<!-- Hero Section -->
|
||||
<section class="relative h-80 mt-20 sm:mt-28">
|
||||
<!-- Background Image -->
|
||||
<div class="absolute inset-0 w-full h-full">
|
||||
<img
|
||||
src="assets/images/our_story.jpg"
|
||||
alt="Quote background"
|
||||
class="w-full h-full object-cover object-center"
|
||||
style="filter: blur(3px)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- White Overlay -->
|
||||
<div class="absolute inset-0 bg-white bg-opacity-60"></div>
|
||||
|
||||
<!-- Overlay Content -->
|
||||
<div
|
||||
class="absolute z-10 inset-0 flex items-center justify-center text-center text-black"
|
||||
>
|
||||
<h1
|
||||
class="font-playfair font-medium text-3xl md:text-4xl lg:text-5xl leading-tight"
|
||||
>
|
||||
Request a Quote
|
||||
</h1>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Quote Items Section -->
|
||||
<section class="bg-white py-16">
|
||||
<div class="max-w-7xl mx-auto px-5">
|
||||
<!-- Section Header -->
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="font-playfair font-semibold text-3xl text-black mb-4">
|
||||
Your Quote Items
|
||||
</h2>
|
||||
<p
|
||||
class="font-playfair font-normal text-lg text-gray-600 max-w-2xl mx-auto"
|
||||
>
|
||||
Review and manage the items you've selected for your quote. You
|
||||
can modify quantities, remove items, or continue shopping.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Quote Items Container -->
|
||||
<div id="quote-items-container" class="space-y-6">
|
||||
<!-- Items will be dynamically loaded here -->
|
||||
<div id="empty-quote-message" class="text-center py-12">
|
||||
<div class="text-gray-400 mb-4">
|
||||
<svg
|
||||
class="w-16 h-16 mx-auto"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3
|
||||
class="font-playfair font-semibold text-xl text-gray-600 mb-2"
|
||||
>
|
||||
Your quote is empty
|
||||
</h3>
|
||||
<p class="font-playfair font-normal text-base text-gray-500 mb-6">
|
||||
Start building your quote by adding products from our catalog.
|
||||
</p>
|
||||
<a
|
||||
href="product-catalog.html"
|
||||
class="inline-block bg-uc-gold text-white px-8 py-3 rounded-lg font-playfair font-semibold text-base hover:bg-uc-gold/90 transition-colors"
|
||||
>
|
||||
Browse Products
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quote Actions -->
|
||||
<div
|
||||
id="quote-actions"
|
||||
class="hidden mt-12 pt-8 border-t border-gray-200"
|
||||
>
|
||||
<div
|
||||
class="flex flex-col md:flex-row justify-between items-center gap-6"
|
||||
>
|
||||
<div class="flex gap-4">
|
||||
<button
|
||||
id="clear-quote-btn"
|
||||
class="px-6 py-3 border border-gray-300 text-gray-700 rounded-lg font-playfair font-semibold text-base hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
Clear Quote
|
||||
</button>
|
||||
<a
|
||||
href="product-catalog.html"
|
||||
class="px-6 py-3 border border-uc-gold text-uc-gold rounded-lg font-playfair font-semibold text-base hover:bg-uc-gold hover:text-white transition-colors"
|
||||
>
|
||||
Continue Shopping
|
||||
</a>
|
||||
</div>
|
||||
<button
|
||||
id="request-quote-btn"
|
||||
class="px-8 py-3 bg-uc-gold text-white rounded-lg font-playfair font-semibold text-base hover:bg-uc-gold/90 transition-colors"
|
||||
>
|
||||
Request Quote
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Quote Request Form Modal -->
|
||||
<div
|
||||
id="quote-modal"
|
||||
class="fixed inset-0 bg-black bg-opacity-50 z-50 hidden"
|
||||
>
|
||||
<div class="flex items-center justify-center min-h-screen p-4">
|
||||
<div
|
||||
class="bg-white rounded-lg max-w-2xl w-full max-h-[90vh] overflow-y-auto"
|
||||
>
|
||||
<!-- Modal Header -->
|
||||
<div
|
||||
class="flex justify-between items-center p-6 border-b border-gray-200"
|
||||
>
|
||||
<h3 class="font-playfair font-semibold text-2xl text-black">
|
||||
Request Quote
|
||||
</h3>
|
||||
<button
|
||||
id="close-modal-btn"
|
||||
class="text-gray-400 hover:text-gray-600 transition-colors"
|
||||
>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<!-- Modal Content -->
|
||||
<div class="p-6">
|
||||
<form id="quote-form" class="space-y-6">
|
||||
<!-- Contact Information -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label
|
||||
for="quote-name"
|
||||
class="block font-playfair font-semibold text-base text-black mb-2"
|
||||
>
|
||||
Full Name *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="quote-name"
|
||||
name="name"
|
||||
required
|
||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg font-playfair font-normal text-base focus:outline-none focus:ring-2 focus:ring-uc-gold focus:border-transparent"
|
||||
placeholder="Enter your full name"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
for="quote-email"
|
||||
class="block font-playfair font-semibold text-base text-black mb-2"
|
||||
>
|
||||
Email Address *
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="quote-email"
|
||||
name="email"
|
||||
required
|
||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg font-playfair font-normal text-base focus:outline-none focus:ring-2 focus:ring-uc-gold focus:border-transparent"
|
||||
placeholder="Enter your email address"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label
|
||||
for="quote-phone"
|
||||
class="block font-playfair font-semibold text-base text-black mb-2"
|
||||
>
|
||||
Phone Number
|
||||
</label>
|
||||
<input
|
||||
type="tel"
|
||||
id="quote-phone"
|
||||
name="phone"
|
||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg font-playfair font-normal text-base focus:outline-none focus:ring-2 focus:ring-uc-gold focus:border-transparent"
|
||||
placeholder="Enter your phone number"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
for="quote-company"
|
||||
class="block font-playfair font-semibold text-base text-black mb-2"
|
||||
>
|
||||
Company
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="quote-company"
|
||||
name="company"
|
||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg font-playfair font-normal text-base focus:outline-none focus:ring-2 focus:ring-uc-gold focus:border-transparent"
|
||||
placeholder="Enter your company name"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
for="quote-project"
|
||||
class="block font-playfair font-semibold text-base text-black mb-2"
|
||||
>
|
||||
Project Description
|
||||
</label>
|
||||
<textarea
|
||||
id="quote-project"
|
||||
name="project"
|
||||
rows="4"
|
||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg font-playfair font-normal text-base focus:outline-none focus:ring-2 focus:ring-uc-gold focus:border-transparent"
|
||||
placeholder="Tell us about your project requirements, timeline, or any special considerations..."
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Quote Summary -->
|
||||
<div class="border-t border-gray-200 pt-6">
|
||||
<h4
|
||||
class="font-playfair font-semibold text-lg text-black mb-4"
|
||||
>
|
||||
Quote Summary
|
||||
</h4>
|
||||
<div id="quote-summary" class="space-y-3">
|
||||
<!-- Quote items will be displayed here -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<div class="flex justify-end pt-6">
|
||||
<button
|
||||
type="submit"
|
||||
class="px-8 py-3 bg-uc-gold text-white rounded-lg font-playfair font-semibold text-base hover:bg-uc-gold/90 transition-colors"
|
||||
>
|
||||
Submit Quote Request
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Footer Separator -->
|
||||
<div class="border-t border-gray-200"></div>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="bg-white">
|
||||
<!-- Main Footer Content -->
|
||||
<div class="max-w-7xl mx-auto px-5 py-16">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
<!-- Company Information -->
|
||||
<div class="space-y-2">
|
||||
<!-- Logo -->
|
||||
<div class="w-16 h-20">
|
||||
<img
|
||||
src="assets/images/khy_logo.png"
|
||||
alt="khy"
|
||||
class="w-full h-full object-contain"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Address -->
|
||||
<p
|
||||
class="font-playfair font-normal text-base leading-relaxed text-gray-600"
|
||||
>
|
||||
5 Labone Crescent, Greater Accra, Ghana
|
||||
</p>
|
||||
|
||||
<!-- Contact Info -->
|
||||
<div class="space-y-1">
|
||||
<!-- Phone -->
|
||||
<div class="flex items-center space-x-3">
|
||||
<img
|
||||
src="assets/images/phone.png"
|
||||
alt="Phone"
|
||||
class="w-4 h-4"
|
||||
/>
|
||||
<span class="font-playfair font-normal text-base text-gray-800">
|
||||
+233 (555) 76677
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Email -->
|
||||
<div class="flex items-center space-x-3">
|
||||
<img src="assets/images/mail.png" alt="Email" class="w-4 h-4" />
|
||||
<span class="font-playfair font-normal text-base text-gray-800">
|
||||
design@khyltd.com
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Links -->
|
||||
<div class="space-y-6">
|
||||
<h3
|
||||
class="font-playfair font-normal text-md leading-relaxed tracking-wider text-eerie-black uppercase"
|
||||
>
|
||||
Quick Links
|
||||
</h3>
|
||||
<div class="space-y-4">
|
||||
<a
|
||||
href="#"
|
||||
class="block font-playfair font-normal text-base leading-relaxed tracking-wider text-gray-800 hover:text-black transition-colors"
|
||||
>
|
||||
Home
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block font-playfair font-normal text-base leading-relaxed tracking-wider text-gray-800 hover:text-black transition-colors"
|
||||
>
|
||||
Products
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block font-playfair font-normal text-base leading-relaxed tracking-wider text-gray-800 hover:text-black transition-colors"
|
||||
>
|
||||
About
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Help -->
|
||||
<div class="space-y-6">
|
||||
<h3
|
||||
class="font-playfair font-normal text-md leading-relaxed tracking-wider text-eerie-black uppercase"
|
||||
>
|
||||
Help
|
||||
</h3>
|
||||
<div class="space-y-4">
|
||||
<a
|
||||
href="#"
|
||||
class="block font-playfair font-normal text-base leading-relaxed tracking-wider text-gray-800 hover:text-black transition-colors"
|
||||
>
|
||||
Contact Us
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block font-playfair font-normal text-base leading-relaxed tracking-wider text-gray-800 hover:text-black transition-colors"
|
||||
>
|
||||
Privacy Policies
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block font-playfair font-normal text-base leading-relaxed tracking-wider text-gray-800 hover:text-black transition-colors"
|
||||
>
|
||||
Terms and Conditions
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Newsletter -->
|
||||
<div class="space-y-6">
|
||||
<h3
|
||||
class="font-playfair font-normal text-md leading-relaxed tracking-wider text-eerie-black uppercase"
|
||||
>
|
||||
Newsletter
|
||||
</h3>
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center space-x-4">
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Enter Your Email Address"
|
||||
class="flex-1 font-playfair font-normal text-sm leading-relaxed tracking-wider text-taupe-gray bg-transparent border-b border-black focus:outline-none focus:border-black"
|
||||
/>
|
||||
<button
|
||||
class="font-playfair font-normal text-sm leading-relaxed tracking-wider text-gray-800 border-b border-black hover:text-black transition-colors"
|
||||
>
|
||||
Subscribe
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Copyright Section -->
|
||||
<div class="border-t border-light-silver">
|
||||
<div class="max-w-7xl mx-auto px-5 py-4">
|
||||
<p
|
||||
class="font-playfair font-normal text-xs leading-relaxed text-davys-grey"
|
||||
>
|
||||
© 2025 khy. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="scripts/main.js?v=3.4"></script>
|
||||
<script src="scripts/quote.js?v=3.5"></script>
|
||||
</body>
|
||||
</html>
|
||||
825
scripts/main.js
825
scripts/main.js
|
|
@ -160,445 +160,6 @@ function initSite() {
|
|||
}
|
||||
})();
|
||||
|
||||
// Blog functionality (only runs on blog page)
|
||||
(async function initBlog() {
|
||||
const blogSearchInput = document.getElementById("blog-search-input");
|
||||
const mainBlogContent = document.getElementById("main-blog-content");
|
||||
const blogCategories = document.getElementById("blog-categories");
|
||||
const recentPosts = document.getElementById("recent-posts");
|
||||
const pagination = document.getElementById("blog-pagination");
|
||||
const pageButtons = document.querySelectorAll(
|
||||
"#blog-pagination .blog-page-btn"
|
||||
);
|
||||
const nextButton = document.getElementById("blog-next-btn");
|
||||
|
||||
if (!blogSearchInput || !mainBlogContent) return;
|
||||
|
||||
let allPosts = [];
|
||||
let filteredPosts = [];
|
||||
let activeTag = "";
|
||||
let currentPage = 1;
|
||||
const pageSize = 4;
|
||||
|
||||
// Load blog data from JSON
|
||||
try {
|
||||
const response = await fetch("data/blog.json", { cache: "no-store" });
|
||||
const data = await response.json();
|
||||
allPosts = Array.isArray(data.posts) ? data.posts : [];
|
||||
|
||||
// Sort posts by date (newest first)
|
||||
allPosts.sort((a, b) => new Date(b.date) - new Date(a.date));
|
||||
|
||||
console.log("Blog posts loaded:", allPosts.length);
|
||||
} catch (error) {
|
||||
console.error("Failed to load blog posts:", error);
|
||||
return;
|
||||
}
|
||||
|
||||
function normalize(text) {
|
||||
return (text || "")
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, " ")
|
||||
.trim();
|
||||
}
|
||||
|
||||
function formatDate(dateString) {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString("en-US", {
|
||||
day: "numeric",
|
||||
month: "short",
|
||||
year: "numeric",
|
||||
});
|
||||
}
|
||||
|
||||
function getFilteredPosts() {
|
||||
const query = normalize(blogSearchInput.value.trim());
|
||||
return allPosts.filter((post) => {
|
||||
const title = post.title || "";
|
||||
const excerpt = post.excerpt || "";
|
||||
const haystack = normalize(`${title} ${excerpt}`);
|
||||
const matchesQuery = query === "" || haystack.includes(query);
|
||||
const matchesTag = activeTag === "" || post.tags.includes(activeTag);
|
||||
return matchesQuery && matchesTag;
|
||||
});
|
||||
}
|
||||
|
||||
function renderBlogPost(post) {
|
||||
const tagsHtml = post.tags
|
||||
.map(
|
||||
(tag) =>
|
||||
`<span class="font-playfair font-normal text-base text-gray-500">${
|
||||
tag.charAt(0).toUpperCase() + tag.slice(1)
|
||||
}</span>`
|
||||
)
|
||||
.join(", ");
|
||||
|
||||
const contentHtml = post.content
|
||||
.map((paragraph) => `<p class="mb-4">${paragraph}</p>`)
|
||||
.join("");
|
||||
|
||||
return `
|
||||
<article class="mb-16" data-tags="${post.tags.join(",")}" data-date="${
|
||||
post.date
|
||||
}">
|
||||
<!-- Featured Image -->
|
||||
<div class="mb-8">
|
||||
<img
|
||||
src="${post.image}"
|
||||
alt="${post.alt || post.title}"
|
||||
class="w-full h-96 object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Post Meta -->
|
||||
<div class="flex items-center space-x-8 mb-6">
|
||||
<!-- Admin -->
|
||||
<div class="flex items-center space-x-2">
|
||||
<img src="assets/icons/admin.png" alt="Admin" class="w-5 h-5" />
|
||||
<span class="font-playfair font-normal text-base text-gray-500">
|
||||
${post.author}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Date -->
|
||||
<div class="flex items-center space-x-2">
|
||||
<img src="assets/icons/calendar.png" alt="Calendar" class="w-5 h-5" />
|
||||
<span class="font-playfair font-normal text-base text-gray-500">
|
||||
${formatDate(post.date)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Category -->
|
||||
<div class="flex items-center space-x-2">
|
||||
<img src="assets/icons/tag.png" alt="Tag" class="w-6 h-6" />
|
||||
<span class="font-playfair font-normal text-base text-gray-500">
|
||||
${
|
||||
post.tags[0]
|
||||
? post.tags[0].charAt(0).toUpperCase() +
|
||||
post.tags[0].slice(1)
|
||||
: "Uncategorized"
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Post Title -->
|
||||
<h2 class="font-playfair font-medium text-3xl md:text-4xl leading-tight text-black mb-6">
|
||||
${post.title}
|
||||
</h2>
|
||||
|
||||
<!-- Post Excerpt -->
|
||||
<p class="font-playfair font-normal text-base leading-relaxed text-gray-500 mb-8 text-justify">
|
||||
${post.excerpt}
|
||||
</p>
|
||||
|
||||
<!-- Read More Link -->
|
||||
<button
|
||||
type="button"
|
||||
class="read-more-toggle inline-block font-playfair font-normal text-base text-black border-b border-black hover:text-gray-600 hover:border-gray-600 transition-colors"
|
||||
>
|
||||
Read more
|
||||
</button>
|
||||
|
||||
<!-- Full content (initially hidden) -->
|
||||
<div class="full-content hidden font-playfair font-normal text-base leading-relaxed text-gray-500 mt-6 text-justify">
|
||||
${contentHtml}
|
||||
</div>
|
||||
</article>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderBlogPosts() {
|
||||
const start = (currentPage - 1) * pageSize;
|
||||
const end = start + pageSize;
|
||||
const postsToShow = filteredPosts.slice(start, end);
|
||||
|
||||
mainBlogContent.innerHTML = postsToShow
|
||||
.map((post) => renderBlogPost(post))
|
||||
.join("");
|
||||
|
||||
// Re-initialize read more functionality
|
||||
initReadMore();
|
||||
}
|
||||
|
||||
function renderCategories() {
|
||||
const tagCounts = {};
|
||||
allPosts.forEach((post) => {
|
||||
post.tags.forEach((tag) => {
|
||||
tagCounts[tag] = (tagCounts[tag] || 0) + 1;
|
||||
});
|
||||
});
|
||||
|
||||
const categoriesHtml = Object.entries(tagCounts)
|
||||
.map(
|
||||
([tag, count]) => `
|
||||
<button
|
||||
type="button"
|
||||
class="flex justify-between items-center w-full text-left tag-filter px-4 py-3 rounded-lg border border-gray-300 hover:border-uc-gold hover:bg-gray-50 transition-colors"
|
||||
data-tag="${tag}"
|
||||
aria-pressed="false"
|
||||
>
|
||||
<span class="font-playfair font-normal text-base">
|
||||
${tag.charAt(0).toUpperCase() + tag.slice(1)}
|
||||
</span>
|
||||
<span class="font-playfair font-normal text-base">
|
||||
(${count})
|
||||
</span>
|
||||
</button>
|
||||
`
|
||||
)
|
||||
.join("");
|
||||
|
||||
blogCategories.innerHTML = categoriesHtml;
|
||||
|
||||
// Add event listeners to category buttons
|
||||
const categoryButtons = blogCategories.querySelectorAll(".tag-filter");
|
||||
categoryButtons.forEach((btn) => {
|
||||
btn.addEventListener("click", () => {
|
||||
const clickedTag = btn.getAttribute("data-tag");
|
||||
activeTag = activeTag === clickedTag ? "" : clickedTag;
|
||||
|
||||
categoryButtons.forEach((b) => {
|
||||
b.classList.remove("border-uc-gold", "bg-gray-50", "text-uc-gold");
|
||||
b.setAttribute("aria-pressed", "false");
|
||||
});
|
||||
|
||||
if (activeTag) {
|
||||
btn.classList.add("border-uc-gold", "bg-gray-50", "text-uc-gold");
|
||||
btn.setAttribute("aria-pressed", "true");
|
||||
}
|
||||
|
||||
currentPage = 1;
|
||||
filteredPosts = getFilteredPosts();
|
||||
renderBlogPosts();
|
||||
renderPagination();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderRecentPosts() {
|
||||
const recentPostsHtml = allPosts
|
||||
.slice(0, 3)
|
||||
.map(
|
||||
(post) => `
|
||||
<div class="flex space-x-4">
|
||||
<img
|
||||
src="${post.thumbnail}"
|
||||
alt="${post.alt || post.title}"
|
||||
class="w-20 h-20 object-cover rounded-lg"
|
||||
/>
|
||||
<div>
|
||||
<h4 class="font-playfair font-normal text-sm text-black mb-2 leading-tight">
|
||||
${post.title}
|
||||
</h4>
|
||||
<p class="font-playfair font-normal text-xs text-gray-500">
|
||||
${formatDate(post.date)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
)
|
||||
.join("");
|
||||
|
||||
recentPosts.innerHTML = recentPostsHtml;
|
||||
}
|
||||
|
||||
function renderPagination() {
|
||||
const total = filteredPosts.length;
|
||||
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
||||
currentPage = Math.min(Math.max(1, currentPage), totalPages);
|
||||
|
||||
if (pagination) {
|
||||
const hasQuery = blogSearchInput.value.trim().length > 0;
|
||||
pagination.style.display = hasQuery ? "none" : "flex";
|
||||
|
||||
pageButtons.forEach((btn) => {
|
||||
const p = Number(btn.getAttribute("data-page"));
|
||||
btn.classList.toggle("bg-uc-gold", p === currentPage);
|
||||
btn.classList.toggle("text-white", p === currentPage);
|
||||
btn.classList.toggle("bg-linen", p !== currentPage);
|
||||
btn.classList.toggle("text-black", p !== currentPage);
|
||||
btn.style.display = p <= totalPages ? "inline-flex" : "none";
|
||||
});
|
||||
|
||||
if (nextButton) {
|
||||
nextButton.style.display = totalPages > 1 ? "inline-flex" : "none";
|
||||
nextButton.disabled = currentPage >= totalPages;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initReadMore() {
|
||||
const articles = document.querySelectorAll("#main-blog-content article");
|
||||
|
||||
articles.forEach((article) => {
|
||||
const excerptP = article.querySelector("p");
|
||||
const readMoreBtn = article.querySelector(".read-more-toggle");
|
||||
if (!excerptP || !readMoreBtn) return;
|
||||
|
||||
const fullExcerpt = excerptP.textContent || "";
|
||||
const { text: truncated, truncated: isTruncated } = truncateToWords(
|
||||
fullExcerpt,
|
||||
80
|
||||
);
|
||||
|
||||
if (isTruncated) {
|
||||
excerptP.dataset.excerptFull = fullExcerpt;
|
||||
excerptP.textContent = truncated;
|
||||
readMoreBtn.style.display = "inline-block";
|
||||
} else {
|
||||
readMoreBtn.style.display = "none";
|
||||
}
|
||||
|
||||
readMoreBtn.addEventListener("click", (ev) => {
|
||||
ev.preventDefault();
|
||||
if (excerptP.dataset.excerptFull) {
|
||||
excerptP.textContent = excerptP.dataset.excerptFull;
|
||||
delete excerptP.dataset.excerptFull;
|
||||
}
|
||||
const fullBlock = article.querySelector(".full-content");
|
||||
if (fullBlock) fullBlock.classList.remove("hidden");
|
||||
readMoreBtn.style.display = "none";
|
||||
|
||||
// Add "Show less" button at the end of the article
|
||||
const showLessBtn = document.createElement("button");
|
||||
showLessBtn.type = "button";
|
||||
showLessBtn.className =
|
||||
"show-less-toggle inline-block font-playfair font-normal text-base text-black border-b border-black hover:text-gray-600 hover:border-gray-600 transition-colors mt-4";
|
||||
showLessBtn.textContent = "Show less";
|
||||
showLessBtn.addEventListener("click", (ev) => {
|
||||
ev.preventDefault();
|
||||
// Restore truncated excerpt
|
||||
excerptP.textContent = truncated;
|
||||
excerptP.dataset.excerptFull = fullExcerpt;
|
||||
// Hide full content
|
||||
if (fullBlock) fullBlock.classList.add("hidden");
|
||||
// Show "Read more" button again
|
||||
readMoreBtn.style.display = "inline-block";
|
||||
// Remove "Show less" button
|
||||
showLessBtn.remove();
|
||||
});
|
||||
// Insert at the end of the article
|
||||
article.appendChild(showLessBtn);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Event listeners
|
||||
blogSearchInput.addEventListener("input", () => {
|
||||
currentPage = 1;
|
||||
filteredPosts = getFilteredPosts();
|
||||
renderBlogPosts();
|
||||
renderPagination();
|
||||
});
|
||||
|
||||
pageButtons.forEach((btn) =>
|
||||
btn.addEventListener("click", () => {
|
||||
currentPage = Number(btn.getAttribute("data-page")) || 1;
|
||||
renderBlogPosts();
|
||||
renderPagination();
|
||||
})
|
||||
);
|
||||
|
||||
if (nextButton) {
|
||||
nextButton.addEventListener("click", () => {
|
||||
currentPage += 1;
|
||||
renderBlogPosts();
|
||||
renderPagination();
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize everything
|
||||
filteredPosts = getFilteredPosts();
|
||||
renderBlogPosts();
|
||||
renderCategories();
|
||||
renderRecentPosts();
|
||||
renderPagination();
|
||||
})();
|
||||
|
||||
// Inline "Read more" expansion for blog posts
|
||||
const articlesForExcerpt = document.querySelectorAll(
|
||||
"#main-blog-content article"
|
||||
);
|
||||
|
||||
function truncateToWords(text, maxWords) {
|
||||
const words = (text || "").trim().split(/\s+/);
|
||||
if (words.length <= maxWords) return { text, truncated: false };
|
||||
return { text: words.slice(0, maxWords).join(" ") + "…", truncated: true };
|
||||
}
|
||||
|
||||
articlesForExcerpt.forEach((article) => {
|
||||
const excerptP = article.querySelector("p");
|
||||
const readMoreBtn = article.querySelector(".read-more-toggle");
|
||||
if (!excerptP || !readMoreBtn) return;
|
||||
|
||||
const fullExcerpt = excerptP.textContent || "";
|
||||
const { text: truncated, truncated: isTruncated } = truncateToWords(
|
||||
fullExcerpt,
|
||||
80
|
||||
);
|
||||
|
||||
if (isTruncated) {
|
||||
// Store full text and show truncated preview
|
||||
excerptP.dataset.excerptFull = fullExcerpt;
|
||||
excerptP.textContent = truncated;
|
||||
readMoreBtn.style.display = "inline-block";
|
||||
} else {
|
||||
// Nothing to expand; hide the control
|
||||
readMoreBtn.style.display = "none";
|
||||
}
|
||||
|
||||
// Click to expand (delegated fallback added below as well)
|
||||
readMoreBtn.addEventListener("click", (ev) => {
|
||||
ev.preventDefault();
|
||||
if (excerptP.dataset.excerptFull) {
|
||||
excerptP.textContent = excerptP.dataset.excerptFull;
|
||||
delete excerptP.dataset.excerptFull;
|
||||
}
|
||||
const fullBlock = article.querySelector(".full-content");
|
||||
if (fullBlock) fullBlock.classList.remove("hidden");
|
||||
readMoreBtn.style.display = "none";
|
||||
|
||||
// Add "Show less" button at the end of the article
|
||||
const showLessBtn = document.createElement("button");
|
||||
showLessBtn.type = "button";
|
||||
showLessBtn.className =
|
||||
"show-less-toggle inline-block font-playfair font-normal text-base text-black border-b border-black hover:text-gray-600 hover:border-gray-600 transition-colors mt-4";
|
||||
showLessBtn.textContent = "Show less";
|
||||
showLessBtn.addEventListener("click", (ev) => {
|
||||
ev.preventDefault();
|
||||
// Restore truncated excerpt
|
||||
excerptP.textContent = truncated;
|
||||
excerptP.dataset.excerptFull = fullExcerpt;
|
||||
// Hide full content
|
||||
if (fullBlock) fullBlock.classList.add("hidden");
|
||||
// Show "Read more" button again
|
||||
readMoreBtn.style.display = "inline-block";
|
||||
// Remove "Show less" button
|
||||
showLessBtn.remove();
|
||||
});
|
||||
// Insert at the end of the article
|
||||
article.appendChild(showLessBtn);
|
||||
});
|
||||
});
|
||||
|
||||
// Safety net: delegated handler in case markup changes
|
||||
document.addEventListener("click", (e) => {
|
||||
const trigger = e.target.closest(".read-more-toggle");
|
||||
if (!trigger) return;
|
||||
e.preventDefault();
|
||||
const article = trigger.closest("article");
|
||||
if (!article) return;
|
||||
const excerptP = article.querySelector("p");
|
||||
if (excerptP?.dataset?.excerptFull) {
|
||||
excerptP.textContent = excerptP.dataset.excerptFull;
|
||||
delete excerptP.dataset.excerptFull;
|
||||
}
|
||||
const fullBlock = article.querySelector(".full-content");
|
||||
if (fullBlock) fullBlock.classList.remove("hidden");
|
||||
trigger.style.display = "none";
|
||||
});
|
||||
|
||||
// Footer newsletter subscribe validation and feedback (works on all pages)
|
||||
const siteFooter = document.querySelector("footer");
|
||||
if (siteFooter) {
|
||||
|
|
@ -1108,113 +669,12 @@ function initProductComparison() {
|
|||
|
||||
// Update View More link with current comparison state
|
||||
updateViewMoreLink(product1Id, product2Id);
|
||||
|
||||
// Wire Add To Quote buttons (first -> product1, second -> product2)
|
||||
wireComparisonAddToQuote(cmpProduct1, cmpProduct2);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error loading products:", error);
|
||||
});
|
||||
}
|
||||
|
||||
// Bind the two Add To Quote buttons on the comparison page
|
||||
function wireComparisonAddToQuote(prod1, prod2) {
|
||||
try {
|
||||
const addButtons = Array.from(document.querySelectorAll("button")).filter(
|
||||
(b) => (b.textContent || "").trim() === "Add To Quote"
|
||||
);
|
||||
|
||||
if (addButtons.length === 0) {
|
||||
console.log("[Comparison] No Add To Quote buttons found");
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure deterministic order: the first encountered is for product 1
|
||||
const btn1 = addButtons[0] || null;
|
||||
const btn2 = addButtons[1] || null;
|
||||
|
||||
function toQuotePayload(p) {
|
||||
if (!p) return null;
|
||||
return {
|
||||
id: Number(p.id),
|
||||
name: p.name || "Product",
|
||||
image: p.image || "",
|
||||
color:
|
||||
(p.colors &&
|
||||
p.colors[0] &&
|
||||
(p.colors[0].name || p.colors[0].value)) ||
|
||||
"Default",
|
||||
size: (p.sizes && p.sizes[0]) || "Standard",
|
||||
quantity: 1,
|
||||
};
|
||||
}
|
||||
|
||||
if (btn1) {
|
||||
btn1.type = btn1.getAttribute("type") || "button";
|
||||
btn1.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const payload = toQuotePayload(prod1);
|
||||
if (!payload) return;
|
||||
payload.quantity = 1; // force 1 for comparison adds
|
||||
if (typeof addToQuote === "function") {
|
||||
addToQuote(payload);
|
||||
} else {
|
||||
addToQuoteFallback(payload);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (btn2) {
|
||||
btn2.type = btn2.getAttribute("type") || "button";
|
||||
btn2.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const payload = toQuotePayload(prod2);
|
||||
if (!payload) return;
|
||||
payload.quantity = 1; // force 1 for comparison adds
|
||||
if (typeof addToQuote === "function") {
|
||||
addToQuote(payload);
|
||||
} else {
|
||||
addToQuoteFallback(payload);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Delegated fallback (in case DOM changes after load)
|
||||
document.addEventListener("click", (e) => {
|
||||
const t = e.target.closest && e.target.closest("button");
|
||||
if (!t) return;
|
||||
const label = (t.textContent || "").trim();
|
||||
if (label !== "Add To Quote") return;
|
||||
// Determine which button index this is relative to current NodeList
|
||||
const currentButtons = Array.from(
|
||||
document.querySelectorAll("button")
|
||||
).filter((b) => (b.textContent || "").trim() === "Add To Quote");
|
||||
const idx = currentButtons.indexOf(t);
|
||||
if (idx === 0) {
|
||||
const payload = toQuotePayload(prod1);
|
||||
if (payload) {
|
||||
payload.quantity = 1;
|
||||
(typeof addToQuote === "function" ? addToQuote : addToQuoteFallback)(
|
||||
payload
|
||||
);
|
||||
}
|
||||
} else if (idx === 1) {
|
||||
const payload = toQuotePayload(prod2);
|
||||
if (payload) {
|
||||
payload.quantity = 1;
|
||||
(typeof addToQuote === "function" ? addToQuote : addToQuoteFallback)(
|
||||
payload
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("[Comparison] Failed to wire Add To Quote buttons:", err);
|
||||
}
|
||||
}
|
||||
|
||||
function updateProductCard(slotNumber, product) {
|
||||
console.log(`=== UPDATING PRODUCT CARD ${slotNumber} ===`);
|
||||
console.log("Product data:", product);
|
||||
|
|
@ -1610,297 +1070,14 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
updateFontClasses();
|
||||
});
|
||||
|
||||
// Initialize quote badge on all pages
|
||||
function initQuoteBadge() {
|
||||
// Load quote items from localStorage
|
||||
const storageKey = "khy_quote_items";
|
||||
let quoteItems = [];
|
||||
|
||||
try {
|
||||
const stored = localStorage.getItem(storageKey);
|
||||
quoteItems = stored ? JSON.parse(stored) : [];
|
||||
} catch (error) {
|
||||
console.error("Error loading quote items:", error);
|
||||
}
|
||||
|
||||
// Calculate total count
|
||||
const count = quoteItems.reduce((total, item) => total + item.quantity, 0);
|
||||
|
||||
// Update quote badge on all quote links (desktop nav, mobile button, mobile menu)
|
||||
const quoteLinks = document.querySelectorAll('a[href="quote.html"]');
|
||||
quoteLinks.forEach((quoteLink) => {
|
||||
// Remove existing badge
|
||||
const existingBadge = quoteLink.querySelector(".quote-badge");
|
||||
if (existingBadge) {
|
||||
existingBadge.remove();
|
||||
}
|
||||
|
||||
// Add new badge if there are items
|
||||
if (count > 0) {
|
||||
const badge = document.createElement("span");
|
||||
badge.className =
|
||||
"quote-badge absolute -top-2 -right-2 bg-uc-gold text-white text-xs rounded-full w-5 h-5 flex items-center justify-center font-semibold";
|
||||
badge.textContent = count > 99 ? "99+" : count;
|
||||
quoteLink.style.position = "relative";
|
||||
quoteLink.appendChild(badge);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize Add To Quote functionality on product detail pages
|
||||
function initAddToQuote() {
|
||||
const addToQuoteBtn = document.getElementById("add-to-quote-btn");
|
||||
if (addToQuoteBtn) {
|
||||
try {
|
||||
// Ensure button is not treated as a submit in case inside a form
|
||||
if (!addToQuoteBtn.getAttribute("type")) {
|
||||
addToQuoteBtn.setAttribute("type", "button");
|
||||
}
|
||||
|
||||
addToQuoteBtn.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.log("[AddToQuote] Direct click captured");
|
||||
|
||||
const productData = getProductDataFromPage();
|
||||
console.log("[AddToQuote] productData:", productData);
|
||||
if (productData) {
|
||||
if (typeof addToQuote === "function") {
|
||||
addToQuote(productData);
|
||||
} else {
|
||||
addToQuoteFallback(productData);
|
||||
}
|
||||
} else {
|
||||
console.warn(
|
||||
"[AddToQuote] No product data found. Check URL id and DOM."
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("[AddToQuote] Failed to bind direct listener:", err);
|
||||
}
|
||||
}
|
||||
|
||||
// Delegated fallback in case the button is replaced dynamically
|
||||
document.addEventListener("click", function (e) {
|
||||
const btn = e.target.closest && e.target.closest("#add-to-quote-btn");
|
||||
if (!btn) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.log("[AddToQuote] Delegated click captured");
|
||||
try {
|
||||
const productData = getProductDataFromPage();
|
||||
console.log("[AddToQuote][delegated] productData:", productData);
|
||||
if (productData) {
|
||||
if (typeof addToQuote === "function") {
|
||||
addToQuote(productData);
|
||||
} else {
|
||||
addToQuoteFallback(productData);
|
||||
}
|
||||
} else {
|
||||
console.warn("[AddToQuote][delegated] No product data found.");
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("[AddToQuote][delegated] Error handling click:", err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Get product data from the current page
|
||||
function getProductDataFromPage() {
|
||||
// Get product ID from URL
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const productId = urlParams.get("id");
|
||||
|
||||
if (!productId) {
|
||||
console.error("No product ID found in URL");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get selected color and size
|
||||
const selectedColor = getSelectedColor();
|
||||
const selectedSize = getSelectedSize();
|
||||
const selectedQuantity = getSelectedQuantity();
|
||||
|
||||
// Get product name and a best-effort product image
|
||||
const productName =
|
||||
document.querySelector("h1")?.textContent?.trim() || "Product";
|
||||
let productImage = "";
|
||||
|
||||
// Helper to guard against invalid selectors (e.g., unescaped brackets)
|
||||
function qsSafe(selector) {
|
||||
try {
|
||||
return document.querySelector(selector);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Try a series of selectors safely
|
||||
const imageCandidates = [
|
||||
".w-\\[500px\\].h-\\[500px\\] img",
|
||||
".w-[500px].h-[500px] img",
|
||||
".bg-floral-white img",
|
||||
"section img[alt]",
|
||||
];
|
||||
|
||||
for (const sel of imageCandidates) {
|
||||
const el = qsSafe(sel);
|
||||
if (el && el.src) {
|
||||
productImage = el.src;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!productImage) {
|
||||
const anyImg = qsSafe("img[alt]") || qsSafe("section img") || qsSafe("img");
|
||||
productImage = anyImg?.src || "";
|
||||
}
|
||||
|
||||
return {
|
||||
id: parseInt(productId),
|
||||
name: productName,
|
||||
image: productImage,
|
||||
color: selectedColor,
|
||||
size: selectedSize,
|
||||
quantity: selectedQuantity,
|
||||
};
|
||||
}
|
||||
|
||||
// Get selected color from the page
|
||||
function getSelectedColor() {
|
||||
const colorButtons = document.querySelectorAll("button[data-color]");
|
||||
for (let button of colorButtons) {
|
||||
if (
|
||||
button.classList.contains("selected") ||
|
||||
button.classList.contains("border-black")
|
||||
) {
|
||||
return button.getAttribute("data-color") || "Default";
|
||||
}
|
||||
}
|
||||
return "Default";
|
||||
}
|
||||
|
||||
// Get selected size from the page
|
||||
function getSelectedSize() {
|
||||
const sizeButtons = document.querySelectorAll("button[data-size]");
|
||||
for (let button of sizeButtons) {
|
||||
if (
|
||||
button.classList.contains("selected") ||
|
||||
button.classList.contains("bg-uc-gold")
|
||||
) {
|
||||
return button.getAttribute("data-size") || "Standard";
|
||||
}
|
||||
}
|
||||
return "Standard";
|
||||
}
|
||||
|
||||
// Get selected quantity from the page
|
||||
function getSelectedQuantity() {
|
||||
const quantitySpan = document.getElementById("qty-value");
|
||||
if (quantitySpan) {
|
||||
return parseInt(quantitySpan.textContent) || 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Fallback function to add to quote directly
|
||||
function addToQuoteFallback(productData) {
|
||||
const storageKey = "khy_quote_items";
|
||||
let quoteItems = [];
|
||||
|
||||
try {
|
||||
const stored = localStorage.getItem(storageKey);
|
||||
quoteItems = stored ? JSON.parse(stored) : [];
|
||||
} catch (error) {
|
||||
console.error("Error loading quote items:", error);
|
||||
quoteItems = [];
|
||||
}
|
||||
|
||||
// Check if item already exists with same specifications
|
||||
const existingItemIndex = quoteItems.findIndex(
|
||||
(item) =>
|
||||
item.id === productData.id &&
|
||||
item.color === productData.color &&
|
||||
item.size === productData.size
|
||||
);
|
||||
|
||||
if (existingItemIndex !== -1) {
|
||||
// Update quantity of existing item
|
||||
quoteItems[existingItemIndex].quantity += productData.quantity;
|
||||
} else {
|
||||
// Add new item
|
||||
const newItem = {
|
||||
...productData,
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
quoteItems.push(newItem);
|
||||
}
|
||||
|
||||
// Save to localStorage
|
||||
try {
|
||||
localStorage.setItem(storageKey, JSON.stringify(quoteItems));
|
||||
|
||||
// Update quote badge
|
||||
initQuoteBadge();
|
||||
|
||||
// Show success message
|
||||
showAddToQuoteSuccess();
|
||||
} catch (error) {
|
||||
console.error("Error saving quote items:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// Show success message when item is added
|
||||
function showAddToQuoteSuccess() {
|
||||
// Create success notification
|
||||
const notification = document.createElement("div");
|
||||
notification.className =
|
||||
"fixed top-24 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg z-50 transform transition-all duration-300 translate-x-full";
|
||||
notification.innerHTML = `
|
||||
<div class="flex items-center space-x-2">
|
||||
<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="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<span class="font-playfair font-semibold">Added to quote!</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
// Animate in
|
||||
setTimeout(() => {
|
||||
notification.classList.remove("translate-x-full");
|
||||
}, 100);
|
||||
|
||||
// Remove after 3 seconds
|
||||
setTimeout(() => {
|
||||
notification.classList.add("translate-x-full");
|
||||
setTimeout(() => {
|
||||
if (document.body.contains(notification)) {
|
||||
document.body.removeChild(notification);
|
||||
}
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// Initialize quote badge immediately if DOM is already loaded
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", initQuoteBadge);
|
||||
} else {
|
||||
initQuoteBadge();
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", initSite);
|
||||
} else {
|
||||
initSite();
|
||||
}
|
||||
|
||||
// Initialize quote badge on page load
|
||||
// Initialize page functionality
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
initQuoteBadge();
|
||||
initAddToQuote();
|
||||
initHeroCarousel();
|
||||
initMobileMenu();
|
||||
});
|
||||
|
|
|
|||
605
scripts/quote.js
605
scripts/quote.js
|
|
@ -1,605 +0,0 @@
|
|||
// Quote Management System
|
||||
class QuoteManager {
|
||||
constructor() {
|
||||
this.storageKey = "khy_quote_items";
|
||||
this.quoteItems = this.loadQuoteItems();
|
||||
this.init();
|
||||
}
|
||||
|
||||
// Load quote items from localStorage
|
||||
loadQuoteItems() {
|
||||
try {
|
||||
const stored = localStorage.getItem(this.storageKey);
|
||||
return stored ? JSON.parse(stored) : [];
|
||||
} catch (error) {
|
||||
console.error("Error loading quote items:", error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Save quote items to localStorage
|
||||
saveQuoteItems() {
|
||||
try {
|
||||
localStorage.setItem(this.storageKey, JSON.stringify(this.quoteItems));
|
||||
this.updateQuoteBadge();
|
||||
} catch (error) {
|
||||
console.error("Error saving quote items:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// Add item to quote
|
||||
addToQuote(productData) {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
image,
|
||||
color = "Default",
|
||||
size = "Standard",
|
||||
quantity = 1,
|
||||
} = productData;
|
||||
|
||||
// Check if item already exists with same specifications
|
||||
const existingItemIndex = this.quoteItems.findIndex(
|
||||
(item) => item.id === id && item.color === color && item.size === size
|
||||
);
|
||||
|
||||
if (existingItemIndex !== -1) {
|
||||
// Update quantity of existing item
|
||||
this.quoteItems[existingItemIndex].quantity += quantity;
|
||||
} else {
|
||||
// Add new item
|
||||
const newItem = {
|
||||
id,
|
||||
name,
|
||||
image,
|
||||
color,
|
||||
size,
|
||||
quantity,
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
this.quoteItems.push(newItem);
|
||||
}
|
||||
|
||||
this.saveQuoteItems();
|
||||
this.renderQuoteItems();
|
||||
this.showAddToQuoteSuccess();
|
||||
}
|
||||
|
||||
// Remove item from quote
|
||||
removeFromQuote(itemIndex) {
|
||||
this.quoteItems.splice(itemIndex, 1);
|
||||
this.saveQuoteItems();
|
||||
this.renderQuoteItems();
|
||||
}
|
||||
|
||||
// Update item quantity
|
||||
updateQuantity(itemIndex, newQuantity) {
|
||||
if (newQuantity > 0) {
|
||||
this.quoteItems[itemIndex].quantity = newQuantity;
|
||||
this.saveQuoteItems();
|
||||
this.renderQuoteItems();
|
||||
} else {
|
||||
this.removeFromQuote(itemIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Edit a quote item
|
||||
editQuoteItem(itemIndex) {
|
||||
const item = this.quoteItems[itemIndex];
|
||||
if (!item) return;
|
||||
|
||||
// Create edit modal
|
||||
const modal = document.createElement("div");
|
||||
modal.id = "edit-quote-modal";
|
||||
modal.className =
|
||||
"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50";
|
||||
modal.innerHTML = `
|
||||
<div class="bg-white rounded-lg p-8 max-w-md w-full mx-4 max-h-[90vh] overflow-y-auto">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h3 class="font-playfair font-semibold text-xl text-black">Edit Quote Item</h3>
|
||||
<button onclick="quoteManager.closeEditModal()" class="text-gray-500 hover:text-gray-700">
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center space-x-4 mb-6">
|
||||
<img src="${item.image}" alt="${
|
||||
item.name
|
||||
}" class="w-16 h-16 object-cover rounded-lg">
|
||||
<div>
|
||||
<h4 class="font-playfair font-semibold text-lg text-black">${
|
||||
item.name
|
||||
}</h4>
|
||||
<p class="text-sm text-gray-600">Product ID: ${item.id}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="edit-quote-form" class="space-y-6">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Quantity</label>
|
||||
<div class="flex items-center space-x-3">
|
||||
<button type="button" onclick="quoteManager.decrementEditQuantity()" class="w-8 h-8 rounded-full border border-gray-300 flex items-center justify-center hover:bg-gray-100 transition-colors">
|
||||
<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="M20 12H4"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<input type="number" id="edit-quantity" value="${
|
||||
item.quantity
|
||||
}" min="1" class="w-20 text-center border border-gray-300 rounded-lg px-3 py-2 font-playfair">
|
||||
<button type="button" onclick="quoteManager.incrementEditQuantity()" class="w-8 h-8 rounded-full border border-gray-300 flex items-center justify-center hover:bg-gray-100 transition-colors">
|
||||
<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="M12 4v16m8-8H4"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Color</label>
|
||||
<select id="edit-color" class="w-full border border-gray-300 rounded-lg px-3 py-2 font-playfair">
|
||||
<option value="Black" ${
|
||||
item.color === "Black" ? "selected" : ""
|
||||
}>Black</option>
|
||||
<option value="White" ${
|
||||
item.color === "White" ? "selected" : ""
|
||||
}>White</option>
|
||||
<option value="Brown" ${
|
||||
item.color === "Brown" ? "selected" : ""
|
||||
}>Brown</option>
|
||||
<option value="Gray" ${
|
||||
item.color === "Gray" ? "selected" : ""
|
||||
}>Gray</option>
|
||||
<option value="Beige" ${
|
||||
item.color === "Beige" ? "selected" : ""
|
||||
}>Beige</option>
|
||||
<option value="Navy" ${
|
||||
item.color === "Navy" ? "selected" : ""
|
||||
}>Navy</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Size</label>
|
||||
<select id="edit-size" class="w-full border border-gray-300 rounded-lg px-3 py-2 font-playfair">
|
||||
<option value="S" ${
|
||||
item.size === "S" ? "selected" : ""
|
||||
}>Small (S)</option>
|
||||
<option value="M" ${
|
||||
item.size === "M" ? "selected" : ""
|
||||
}>Medium (M)</option>
|
||||
<option value="L" ${
|
||||
item.size === "L" ? "selected" : ""
|
||||
}>Large (L)</option>
|
||||
<option value="XL" ${
|
||||
item.size === "XL" ? "selected" : ""
|
||||
}>Extra Large (XL)</option>
|
||||
<option value="Standard" ${
|
||||
item.size === "Standard" ? "selected" : ""
|
||||
}>Standard</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="flex space-x-3 pt-4">
|
||||
<button type="button" onclick="quoteManager.closeEditModal()" class="flex-1 bg-gray-300 text-gray-700 px-4 py-2 rounded-lg font-playfair hover:bg-gray-400 transition-colors">
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit" class="flex-1 bg-uc-gold text-white px-4 py-2 rounded-lg font-playfair hover:bg-amber-600 transition-colors">
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(modal);
|
||||
|
||||
// Add form submission handler
|
||||
const form = modal.querySelector("#edit-quote-form");
|
||||
form.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
this.saveEditChanges(itemIndex);
|
||||
});
|
||||
|
||||
// Close modal when clicking outside
|
||||
modal.addEventListener("click", (e) => {
|
||||
if (e.target === modal) {
|
||||
this.closeEditModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Close edit modal
|
||||
closeEditModal() {
|
||||
const modal = document.getElementById("edit-quote-modal");
|
||||
if (modal) {
|
||||
modal.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Increment quantity in edit modal
|
||||
incrementEditQuantity() {
|
||||
const input = document.getElementById("edit-quantity");
|
||||
if (input) {
|
||||
input.value = parseInt(input.value) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Decrement quantity in edit modal
|
||||
decrementEditQuantity() {
|
||||
const input = document.getElementById("edit-quantity");
|
||||
if (input && parseInt(input.value) > 1) {
|
||||
input.value = parseInt(input.value) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Save changes from edit modal
|
||||
saveEditChanges(itemIndex) {
|
||||
const quantity = parseInt(document.getElementById("edit-quantity").value);
|
||||
const color = document.getElementById("edit-color").value;
|
||||
const size = document.getElementById("edit-size").value;
|
||||
|
||||
if (quantity < 1) {
|
||||
alert("Quantity must be at least 1");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the item
|
||||
this.quoteItems[itemIndex] = {
|
||||
...this.quoteItems[itemIndex],
|
||||
quantity: quantity,
|
||||
color: color,
|
||||
size: size,
|
||||
};
|
||||
|
||||
this.saveQuoteItems();
|
||||
this.renderQuoteItems();
|
||||
this.closeEditModal();
|
||||
|
||||
// Show success message
|
||||
this.showEditSuccess();
|
||||
}
|
||||
|
||||
// Show success message for edit
|
||||
showEditSuccess() {
|
||||
const notification = document.createElement("div");
|
||||
notification.className =
|
||||
"fixed top-24 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg z-50 transform transition-all duration-300 translate-x-full";
|
||||
notification.innerHTML = `
|
||||
<div class="flex items-center space-x-2">
|
||||
<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="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<span class="font-playfair font-semibold">Quote item updated!</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
// Animate in
|
||||
setTimeout(() => {
|
||||
notification.classList.remove("translate-x-full");
|
||||
}, 100);
|
||||
|
||||
// Remove after 3 seconds
|
||||
setTimeout(() => {
|
||||
notification.classList.add("translate-x-full");
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(notification);
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// Clear all quote items
|
||||
clearQuote() {
|
||||
this.quoteItems = [];
|
||||
this.saveQuoteItems();
|
||||
this.renderQuoteItems();
|
||||
}
|
||||
|
||||
// Get quote items count
|
||||
getQuoteCount() {
|
||||
return this.quoteItems.reduce((total, item) => total + item.quantity, 0);
|
||||
}
|
||||
|
||||
// Update quote badge in navigation
|
||||
updateQuoteBadge() {
|
||||
const count = this.getQuoteCount();
|
||||
const quoteLinks = document.querySelectorAll('a[href="quote.html"]');
|
||||
|
||||
quoteLinks.forEach((quoteLink) => {
|
||||
// Remove existing badge
|
||||
const existingBadge = quoteLink.querySelector(".quote-badge");
|
||||
if (existingBadge) {
|
||||
existingBadge.remove();
|
||||
}
|
||||
|
||||
// Add new badge if there are items
|
||||
if (count > 0) {
|
||||
const badge = document.createElement("span");
|
||||
badge.className =
|
||||
"quote-badge absolute -top-2 -right-2 bg-uc-gold text-white text-xs rounded-full w-5 h-5 flex items-center justify-center font-semibold";
|
||||
badge.textContent = count > 99 ? "99+" : count;
|
||||
quoteLink.style.position = "relative";
|
||||
quoteLink.appendChild(badge);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Show success message when item is added
|
||||
showAddToQuoteSuccess() {
|
||||
// Create success notification
|
||||
const notification = document.createElement("div");
|
||||
notification.className =
|
||||
"fixed top-24 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg z-50 transform transition-all duration-300 translate-x-full";
|
||||
notification.innerHTML = `
|
||||
<div class="flex items-center space-x-2">
|
||||
<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="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<span class="font-playfair font-semibold">Added to quote!</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
// Animate in
|
||||
setTimeout(() => {
|
||||
notification.classList.remove("translate-x-full");
|
||||
}, 100);
|
||||
|
||||
// Remove after 3 seconds
|
||||
setTimeout(() => {
|
||||
notification.classList.add("translate-x-full");
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(notification);
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// Render quote items on the quote page
|
||||
renderQuoteItems() {
|
||||
const container = document.getElementById("quote-items-container");
|
||||
const emptyMessage = document.getElementById("empty-quote-message");
|
||||
const quoteActions = document.getElementById("quote-actions");
|
||||
|
||||
if (!container) return;
|
||||
|
||||
if (this.quoteItems.length === 0) {
|
||||
// Show empty state
|
||||
if (emptyMessage) emptyMessage.style.display = "block";
|
||||
if (quoteActions) quoteActions.classList.add("hidden");
|
||||
// Clear any existing items but keep the empty message
|
||||
const itemsToRemove = container.querySelectorAll(".bg-gray-50");
|
||||
itemsToRemove.forEach((item) => item.remove());
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide empty message and show actions
|
||||
if (emptyMessage) emptyMessage.style.display = "none";
|
||||
if (quoteActions) quoteActions.classList.remove("hidden");
|
||||
|
||||
// Remove any existing items first
|
||||
const itemsToRemove = container.querySelectorAll(".bg-gray-50");
|
||||
itemsToRemove.forEach((item) => item.remove());
|
||||
|
||||
// Render new items
|
||||
this.quoteItems.forEach((item, index) => {
|
||||
const itemElement = document.createElement("div");
|
||||
itemElement.className =
|
||||
"bg-gray-50 rounded-lg p-6 border border-gray-200";
|
||||
itemElement.innerHTML = `
|
||||
<div class="flex items-center space-x-6">
|
||||
<!-- Product Image -->
|
||||
<div class="w-24 h-24 flex-shrink-0">
|
||||
<img
|
||||
src="${item.image}"
|
||||
alt="${item.name}"
|
||||
class="w-full h-full object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Product Details -->
|
||||
<div class="flex-1">
|
||||
<h3 class="font-playfair font-semibold text-xl text-black mb-2">
|
||||
${item.name}
|
||||
</h3>
|
||||
<div class="flex items-center space-x-6 text-sm text-gray-600">
|
||||
<span><strong>Color:</strong> ${item.color}</span>
|
||||
<span><strong>Size:</strong> ${item.size}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quantity Controls -->
|
||||
<div class="flex items-center space-x-3">
|
||||
<button
|
||||
onclick="quoteManager.updateQuantity(${index}, ${
|
||||
item.quantity - 1
|
||||
})"
|
||||
class="w-8 h-8 rounded-full border border-gray-300 flex items-center justify-center hover:bg-gray-100 transition-colors"
|
||||
>
|
||||
<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="M20 12H4"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<span class="font-playfair font-semibold text-lg text-black min-w-[2rem] text-center">
|
||||
${item.quantity}
|
||||
</span>
|
||||
<button
|
||||
onclick="quoteManager.updateQuantity(${index}, ${
|
||||
item.quantity + 1
|
||||
})"
|
||||
class="w-8 h-8 rounded-full border border-gray-300 flex items-center justify-center hover:bg-gray-100 transition-colors"
|
||||
>
|
||||
<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="M12 4v16m8-8H4"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Edit Button -->
|
||||
<button
|
||||
onclick="quoteManager.editQuoteItem(${index})"
|
||||
class="text-blue-500 hover:text-blue-700 transition-colors mr-2"
|
||||
title="Edit item"
|
||||
>
|
||||
<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="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- Remove Button -->
|
||||
<button
|
||||
onclick="quoteManager.removeFromQuote(${index})"
|
||||
class="text-red-500 hover:text-red-700 transition-colors"
|
||||
title="Remove item"
|
||||
>
|
||||
<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="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(itemElement);
|
||||
});
|
||||
}
|
||||
|
||||
// Render quote summary in modal
|
||||
renderQuoteSummary() {
|
||||
const summaryContainer = document.getElementById("quote-summary");
|
||||
if (!summaryContainer) return;
|
||||
|
||||
summaryContainer.innerHTML = this.quoteItems
|
||||
.map(
|
||||
(item) => `
|
||||
<div class="flex justify-between items-center py-2 border-b border-gray-100">
|
||||
<div class="flex-1">
|
||||
<h5 class="font-playfair font-semibold text-base text-black">${item.name}</h5>
|
||||
<p class="text-sm text-gray-600">${item.color} • ${item.size} • Qty: ${item.quantity}</p>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
)
|
||||
.join("");
|
||||
}
|
||||
|
||||
// Initialize quote manager
|
||||
init() {
|
||||
this.updateQuoteBadge();
|
||||
this.renderQuoteItems();
|
||||
this.setupEventListeners();
|
||||
}
|
||||
|
||||
// Setup event listeners
|
||||
setupEventListeners() {
|
||||
// Clear quote button
|
||||
const clearBtn = document.getElementById("clear-quote-btn");
|
||||
if (clearBtn) {
|
||||
clearBtn.addEventListener("click", () => {
|
||||
if (confirm("Are you sure you want to clear your quote?")) {
|
||||
this.clearQuote();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Request quote button
|
||||
const requestBtn = document.getElementById("request-quote-btn");
|
||||
if (requestBtn) {
|
||||
requestBtn.addEventListener("click", () => {
|
||||
this.openQuoteModal();
|
||||
});
|
||||
}
|
||||
|
||||
// Modal close button
|
||||
const closeBtn = document.getElementById("close-modal-btn");
|
||||
if (closeBtn) {
|
||||
closeBtn.addEventListener("click", () => {
|
||||
this.closeQuoteModal();
|
||||
});
|
||||
}
|
||||
|
||||
// Modal backdrop click
|
||||
const modal = document.getElementById("quote-modal");
|
||||
if (modal) {
|
||||
modal.addEventListener("click", (e) => {
|
||||
if (e.target === modal) {
|
||||
this.closeQuoteModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Quote form submission
|
||||
const quoteForm = document.getElementById("quote-form");
|
||||
if (quoteForm) {
|
||||
quoteForm.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
this.submitQuoteRequest();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Open quote modal
|
||||
openQuoteModal() {
|
||||
const modal = document.getElementById("quote-modal");
|
||||
if (modal) {
|
||||
this.renderQuoteSummary();
|
||||
modal.classList.remove("hidden");
|
||||
document.body.style.overflow = "hidden";
|
||||
}
|
||||
}
|
||||
|
||||
// Close quote modal
|
||||
closeQuoteModal() {
|
||||
const modal = document.getElementById("quote-modal");
|
||||
if (modal) {
|
||||
modal.classList.add("hidden");
|
||||
document.body.style.overflow = "auto";
|
||||
}
|
||||
}
|
||||
|
||||
// Submit quote request
|
||||
submitQuoteRequest() {
|
||||
const form = document.getElementById("quote-form");
|
||||
const formData = new FormData(form);
|
||||
|
||||
// Get form data
|
||||
const quoteData = {
|
||||
name: formData.get("name"),
|
||||
email: formData.get("email"),
|
||||
phone: formData.get("phone"),
|
||||
company: formData.get("company"),
|
||||
project: formData.get("project"),
|
||||
items: this.quoteItems,
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
|
||||
// Here you would typically send this data to your server
|
||||
console.log("Quote request data:", quoteData);
|
||||
|
||||
// For now, just show success message
|
||||
alert("Thank you for your quote request! We will get back to you soon.");
|
||||
|
||||
// Clear the quote and close modal
|
||||
this.clearQuote();
|
||||
this.closeQuoteModal();
|
||||
|
||||
// Reset form
|
||||
form.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Global quote manager instance
|
||||
const quoteManager = new QuoteManager();
|
||||
|
||||
// Global function to add items to quote (called from other pages)
|
||||
function addToQuote(productData) {
|
||||
quoteManager.addToQuote(productData);
|
||||
}
|
||||
|
||||
// Initialize when DOM is ready
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
// Quote manager is already initialized in constructor
|
||||
});
|
||||
|
||||
// Version: 3.5 - Added edit functionality for quote items
|
||||
138
styles/main.css
138
styles/main.css
|
|
@ -685,6 +685,14 @@ video {
|
|||
top: 20rem;
|
||||
}
|
||||
|
||||
.right-2 {
|
||||
right: 0.5rem;
|
||||
}
|
||||
|
||||
.top-2 {
|
||||
top: 0.5rem;
|
||||
}
|
||||
|
||||
.z-10 {
|
||||
z-index: 10;
|
||||
}
|
||||
|
|
@ -845,6 +853,14 @@ video {
|
|||
margin-bottom: -0.5rem;
|
||||
}
|
||||
|
||||
.mt-2 {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.ml-1 {
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.box-border {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
|
@ -1001,6 +1017,10 @@ video {
|
|||
height: 10rem;
|
||||
}
|
||||
|
||||
.h-48 {
|
||||
height: 12rem;
|
||||
}
|
||||
|
||||
.max-h-\[90vh\] {
|
||||
max-height: 90vh;
|
||||
}
|
||||
|
|
@ -1212,6 +1232,14 @@ video {
|
|||
resize: both;
|
||||
}
|
||||
|
||||
.list-inside {
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
.list-disc {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.appearance-none {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
|
@ -1230,6 +1258,10 @@ video {
|
|||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-cols-2 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.flex-row {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
|
@ -1514,6 +1546,11 @@ video {
|
|||
border-color: rgb(184 135 63 / var(--tw-border-opacity, 1));
|
||||
}
|
||||
|
||||
.border-blue-500 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(59 130 246 / var(--tw-border-opacity, 1));
|
||||
}
|
||||
|
||||
.border-opacity-20 {
|
||||
--tw-border-opacity: 0.2;
|
||||
}
|
||||
|
|
@ -1612,6 +1649,26 @@ video {
|
|||
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-blue-500 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(59 130 246 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-blue-600 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(37 99 235 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-green-100 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(220 252 231 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-yellow-100 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(254 249 195 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-opacity-50 {
|
||||
--tw-bg-opacity: 0.5;
|
||||
}
|
||||
|
|
@ -1838,6 +1895,10 @@ video {
|
|||
font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
}
|
||||
|
||||
.font-mono {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
}
|
||||
|
||||
.text-2xl {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
|
|
@ -1918,6 +1979,10 @@ video {
|
|||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.capitalize {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.leading-6 {
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
|
@ -2042,6 +2107,21 @@ video {
|
|||
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-gray-300 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(209 213 219 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-yellow-400 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(250 204 21 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-yellow-800 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(133 77 14 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-opacity-90 {
|
||||
--tw-text-opacity: 0.9;
|
||||
}
|
||||
|
|
@ -2087,6 +2167,18 @@ video {
|
|||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.shadow {
|
||||
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.shadow-md {
|
||||
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.blur {
|
||||
--tw-blur: blur(8px);
|
||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||
|
|
@ -2153,6 +2245,47 @@ video {
|
|||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.file\:mr-4::file-selector-button {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.file\:rounded-full::file-selector-button {
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
.file\:border-0::file-selector-button {
|
||||
border-width: 0px;
|
||||
}
|
||||
|
||||
.file\:bg-blue-50::file-selector-button {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(239 246 255 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.file\:px-4::file-selector-button {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.file\:py-2::file-selector-button {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.file\:text-sm::file-selector-button {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.file\:font-semibold::file-selector-button {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.file\:text-blue-700::file-selector-button {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(29 78 216 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:-translate-y-0\.5:hover {
|
||||
--tw-translate-y: -0.125rem;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
|
|
@ -2279,6 +2412,11 @@ video {
|
|||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.hover\:file\:bg-blue-100::file-selector-button:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(219 234 254 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.focus\:border-black:focus {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(0 0 0 / var(--tw-border-opacity, 1));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue