Performance improvements and Dockerfile update
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
# production
|
# production
|
||||||
/build
|
/build
|
||||||
|
.output/
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
53
Dockerfile
53
Dockerfile
@ -1,8 +1,6 @@
|
|||||||
FROM node:22-alpine AS base
|
FROM node:22-alpine AS base
|
||||||
|
|
||||||
ARG NEXT_PUBLIC_INSTAGRAM_ACCESS_TOKEN
|
# Stage 1: Install dependencies
|
||||||
|
|
||||||
# Install dependencies only when needed
|
|
||||||
FROM base AS deps
|
FROM base AS deps
|
||||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||||
RUN apk add --no-cache libc6-compat
|
RUN apk add --no-cache libc6-compat
|
||||||
@ -18,54 +16,47 @@ RUN \
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Rebuild the source code only when needed
|
# Stage 2: Rebuild the source code only when needed
|
||||||
FROM base AS builder
|
FROM base AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Next.js collects completely anonymous telemetry data about general usage.
|
# Environment variables needed during build time
|
||||||
# Learn more here: https://nextjs.org/telemetry
|
ARG INSTAGRAM_ACCESS_TOKEN
|
||||||
# Uncomment the following line in case you want to disable telemetry during the build.
|
ENV INSTAGRAM_ACCESS_TOKEN=$INSTAGRAM_ACCESS_TOKEN
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
if [ -f yarn.lock ]; then yarn run build; \
|
if [ -f yarn.lock ]; then yarn build; \
|
||||||
elif [ -f package-lock.json ]; then npm run build; \
|
elif [ -f package-lock.json ]; then npm run build; \
|
||||||
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
|
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
|
||||||
else echo "Lockfile not found." && exit 1; \
|
else npm run build; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Production image, copy all the files and run next
|
|
||||||
|
# Stage 3: Production image, copy all the files and run nitro
|
||||||
FROM base AS runner
|
FROM base AS runner
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
# Uncomment the following line in case you want to disable telemetry during runtime.
|
# Set host to 0.0.0.0 to ensure it's accessible outside the container
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
ENV HOST=0.0.0.0
|
||||||
|
ENV PORT=3000
|
||||||
|
|
||||||
RUN addgroup --system --gid 1001 nodejs
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
RUN adduser --system --uid 1001 nextjs
|
RUN adduser --system --uid 1001 nitrojs
|
||||||
|
|
||||||
COPY --from=builder /app/public ./public
|
# Copy the build output from the builder stage
|
||||||
|
# TanStack Start/Nitro builds into the .output directory
|
||||||
|
COPY --from=builder --chown=nitrojs:nodejs /app/.output ./.output
|
||||||
|
|
||||||
# Set the correct permission for prerender cache
|
USER nitrojs
|
||||||
RUN mkdir .next
|
|
||||||
RUN chown nextjs:nodejs .next
|
|
||||||
|
|
||||||
# Automatically leverage output traces to reduce image size
|
|
||||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
|
||||||
|
|
||||||
USER nextjs
|
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
ENV PORT=3000
|
# Health check to ensure the server is responding
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||||
|
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1
|
||||||
|
|
||||||
# server.js is created by next build from the standalone output
|
# server.mjs is created by nitro build
|
||||||
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
|
CMD ["node", ".output/server/index.mjs"]
|
||||||
ENV HOSTNAME="0.0.0.0"
|
|
||||||
CMD ["node", "server.js"]
|
|
||||||
21
Makefile
21
Makefile
@ -4,5 +4,26 @@ build-production: ## Build the production docker image.
|
|||||||
--platform linux/amd64,linux/arm64/v8 \
|
--platform linux/amd64,linux/arm64/v8 \
|
||||||
--tag registry.tanshu.com/mozimo:latest \
|
--tag registry.tanshu.com/mozimo:latest \
|
||||||
$(if $(TAG),--tag registry.tanshu.com/mozimo:$(TAG)) \
|
$(if $(TAG),--tag registry.tanshu.com/mozimo:$(TAG)) \
|
||||||
|
--pull \
|
||||||
--push \
|
--push \
|
||||||
git@github.com:tanshu/mozimo.git
|
git@github.com:tanshu/mozimo.git
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: build-check
|
||||||
|
build-check: ## Multi-arch build without push (compile check)
|
||||||
|
@docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64/v8 \
|
||||||
|
--tag mozimo:test \
|
||||||
|
--pull \
|
||||||
|
--progress=plain \
|
||||||
|
git@git.tanshu.com:tanshu/mozimo.git
|
||||||
|
|
||||||
|
.PHONY: build-check-local
|
||||||
|
build-check-local: ## Multi-arch build without push (compile check)
|
||||||
|
@git archive --format=tar HEAD | docker buildx build \
|
||||||
|
--platform linux/amd64 \
|
||||||
|
--tag barker:test \
|
||||||
|
--pull \
|
||||||
|
--progress=plain \
|
||||||
|
--load \
|
||||||
|
-
|
||||||
|
|||||||
@ -16,7 +16,7 @@ docker_image: "{{ registry }}/{{ title }}:{{ tag }}"
|
|||||||
docker_container: "{{ title }}"
|
docker_container: "{{ title }}"
|
||||||
docker_port: 3000
|
docker_port: 3000
|
||||||
|
|
||||||
instagram_token: IGQWRQSUY4b3RQWU9ZARHlVVUFDaWxJZAWFOUVllM0NxMk1zSHJ5X2JGc2dpRUxyTjBaeDNhUm0yaFZAQeUotVU9VUmFEQkJxU25CdFp3bURSZAGtnLXhCZAHVId21SWUNiNjVzc0pjZAlhPNDRxTDFzZAEQ0ZAXoyVlpUaHcZD
|
instagram_token: IGQWRhYzlibzE4VEpNYzZA2eHEtRkVLUXJiT3NyVU9mNjlNRzM1cmd2NzY0SGxtX1ZAVVGVwb1dkbFl4VlVWaW02aFhEakQzeUp3NjBCSktRR2lQYlgwV3UwMG1seTFsWDBMSzZAHejNYdlE5RFMzU0tqbS1OVEttN0UZD
|
||||||
|
|
||||||
|
|
||||||
caddy_container: caddy
|
caddy_container: caddy
|
||||||
|
|||||||
@ -9,8 +9,6 @@ const compat = new FlatCompat({
|
|||||||
baseDirectory: __dirname,
|
baseDirectory: __dirname,
|
||||||
});
|
});
|
||||||
|
|
||||||
const eslintConfig = [
|
const eslintConfig = [{}];
|
||||||
...compat.extends("next/core-web-vitals", "next/typescript"),
|
|
||||||
];
|
|
||||||
|
|
||||||
export default eslintConfig;
|
export default eslintConfig;
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import { createRootRoute, Outlet, HeadContent, Scripts } from '@tanstack/react-router';
|
import { createRootRoute, Outlet, HeadContent, Scripts } from '@tanstack/react-router';
|
||||||
|
import { LazyMotion } from 'framer-motion';
|
||||||
import appCss from './globals.css?url';
|
import appCss from './globals.css?url';
|
||||||
|
|
||||||
|
const loadFeatures = () => import('framer-motion').then(res => res.domAnimation);
|
||||||
|
|
||||||
export const Route = createRootRoute({
|
export const Route = createRootRoute({
|
||||||
head: () => ({
|
head: () => ({
|
||||||
meta: [
|
meta: [
|
||||||
@ -68,7 +71,9 @@ function RootLayout() {
|
|||||||
Since the Inter Google Font is loaded via the stylesheet above, it will automatically apply
|
Since the Inter Google Font is loaded via the stylesheet above, it will automatically apply
|
||||||
if configured in Tailwind CSS. */}
|
if configured in Tailwind CSS. */}
|
||||||
<body>
|
<body>
|
||||||
<Outlet />
|
<LazyMotion features={loadFeatures} strict>
|
||||||
|
<Outlet />
|
||||||
|
</LazyMotion>
|
||||||
<Scripts />
|
<Scripts />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import { createFileRoute } from "@tanstack/react-router";
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
import { motion } from "framer-motion";
|
import { m } from "framer-motion";
|
||||||
import Header from "@/components/Header";
|
import Header from "@/components/Header";
|
||||||
import Footer from "@/components/Footer";
|
// Footer is lazy loaded
|
||||||
import { Image } from "@unpic/react";
|
import { Image } from "@unpic/react";
|
||||||
|
import { lazy, Suspense } from "react";
|
||||||
|
|
||||||
|
const Footer = lazy(() => import("@/components/Footer"));
|
||||||
export const Route = createFileRoute('/about')({
|
export const Route = createFileRoute('/about')({
|
||||||
component: AboutPage,
|
component: AboutPage,
|
||||||
});
|
});
|
||||||
@ -43,14 +45,14 @@ function AboutPage() {
|
|||||||
{/* Hero Section */}
|
{/* Hero Section */}
|
||||||
<section className="pt-32 md:pt-40 pb-16 md:pb-24">
|
<section className="pt-32 md:pt-40 pb-16 md:pb-24">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
variants={fadeInUp}
|
variants={fadeInUp}
|
||||||
className="text-center space-y-8"
|
className="text-center space-y-8"
|
||||||
>
|
>
|
||||||
<motion.h1
|
<m.h1
|
||||||
className="text-4xl md:text-5xl lg:text-7xl font-bold text-[#3C2A21] font-samantha"
|
className="text-4xl md:text-5xl lg:text-7xl font-bold text-[#3C2A21] font-samantha"
|
||||||
style={{
|
style={{
|
||||||
fontFamily: "MonetaSans-Regular",
|
fontFamily: "MonetaSans-Regular",
|
||||||
@ -64,9 +66,9 @@ function AboutPage() {
|
|||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
>
|
>
|
||||||
Welcome to the World of Mozimo Magic
|
Welcome to the World of Mozimo Magic
|
||||||
</motion.h1>
|
</m.h1>
|
||||||
|
|
||||||
<motion.div
|
<m.div
|
||||||
className="w-full px-8 md:px-16 lg:px-24"
|
className="w-full px-8 md:px-16 lg:px-24"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
@ -85,17 +87,17 @@ function AboutPage() {
|
|||||||
>
|
>
|
||||||
Indulge in the Luxurious. Immerse in the Captivating. Savor the Fresh. At Mozimo, we create a chocolate experience that transports you to a world of opulence, with mesmerizing aromas and visuals, and delights your taste buds with the vibrant flavors of freshly crafted chocolates. Join us on a journey of pure luxury, captivating moments, and a fresh perspective on the art of chocolate-making.
|
Indulge in the Luxurious. Immerse in the Captivating. Savor the Fresh. At Mozimo, we create a chocolate experience that transports you to a world of opulence, with mesmerizing aromas and visuals, and delights your taste buds with the vibrant flavors of freshly crafted chocolates. Join us on a journey of pure luxury, captivating moments, and a fresh perspective on the art of chocolate-making.
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Hero Image */}
|
{/* Hero Image */}
|
||||||
<motion.div
|
<m.div
|
||||||
className="relative w-full mt-12"
|
className="relative w-full mt-12"
|
||||||
initial={{ opacity: 0, y: 30 }}
|
initial={{ opacity: 0, y: 30 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.8, delay: 0.4 }}
|
transition={{ duration: 0.8, delay: 0.4 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
>
|
>
|
||||||
<motion.div
|
<m.div
|
||||||
className="relative w-full h-[400px] md:h-[500px] lg:h-[600px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500 rounded-lg"
|
className="relative w-full h-[400px] md:h-[500px] lg:h-[600px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500 rounded-lg"
|
||||||
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
||||||
>
|
>
|
||||||
@ -106,9 +108,9 @@ function AboutPage() {
|
|||||||
className="w-full h-full object-cover img-premium"
|
className="w-full h-full object-cover img-premium"
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/10 via-transparent to-transparent" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/10 via-transparent to-transparent" />
|
||||||
</motion.div>
|
</m.div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@ -118,14 +120,14 @@ function AboutPage() {
|
|||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-16 items-center">
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-16 items-center">
|
||||||
{/* Founders Image */}
|
{/* Founders Image */}
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
variants={fadeInLeft}
|
variants={fadeInLeft}
|
||||||
className="order-2 lg:order-1"
|
className="order-2 lg:order-1"
|
||||||
>
|
>
|
||||||
<motion.div
|
<m.div
|
||||||
className="relative w-full h-[400px] md:h-[500px] lg:h-[600px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500"
|
className="relative w-full h-[400px] md:h-[500px] lg:h-[600px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500"
|
||||||
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
||||||
>
|
>
|
||||||
@ -136,18 +138,18 @@ function AboutPage() {
|
|||||||
className="w-full h-full object-cover img-premium"
|
className="w-full h-full object-cover img-premium"
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
||||||
</motion.div>
|
</m.div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Founders Text */}
|
{/* Founders Text */}
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
variants={fadeInRight}
|
variants={fadeInRight}
|
||||||
className="space-y-6 md:space-y-8 order-1 lg:order-2 px-8 md:px-16 lg:px-24"
|
className="space-y-6 md:space-y-8 order-1 lg:order-2 px-8 md:px-16 lg:px-24"
|
||||||
>
|
>
|
||||||
<motion.h2
|
<m.h2
|
||||||
className="text-3xl md:text-4xl lg:text-5xl font-bold text-[#3C2A21] font-samantha"
|
className="text-3xl md:text-4xl lg:text-5xl font-bold text-[#3C2A21] font-samantha"
|
||||||
style={{
|
style={{
|
||||||
fontFamily: "MonetaSans-Regular",
|
fontFamily: "MonetaSans-Regular",
|
||||||
@ -161,9 +163,9 @@ function AboutPage() {
|
|||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
>
|
>
|
||||||
Our Founders
|
Our Founders
|
||||||
</motion.h2>
|
</m.h2>
|
||||||
|
|
||||||
<motion.h3
|
<m.h3
|
||||||
className="text-2xl md:text-3xl font-semibold text-[#8B4513] font-renner"
|
className="text-2xl md:text-3xl font-semibold text-[#8B4513] font-renner"
|
||||||
style={{
|
style={{
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
@ -176,9 +178,9 @@ function AboutPage() {
|
|||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
>
|
>
|
||||||
Priyanka and Amritanshu.
|
Priyanka and Amritanshu.
|
||||||
</motion.h3>
|
</m.h3>
|
||||||
|
|
||||||
<motion.p
|
<m.p
|
||||||
className="text-gray-700 leading-relaxed font-renner"
|
className="text-gray-700 leading-relaxed font-renner"
|
||||||
style={{
|
style={{
|
||||||
fontWeight: 300,
|
fontWeight: 300,
|
||||||
@ -193,8 +195,8 @@ function AboutPage() {
|
|||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
>
|
>
|
||||||
are the proud founders of Mozimo, a bean-to-bar chocolate shop that celebrates the rich and distinctive flavors of single origin cocoa beans. Their journey with Mozimo has been a passionate pursuit of creating exceptional chocolate that tantalizes the taste buds and tells the unique story of each cocoa bean's origin.
|
are the proud founders of Mozimo, a bean-to-bar chocolate shop that celebrates the rich and distinctive flavors of single origin cocoa beans. Their journey with Mozimo has been a passionate pursuit of creating exceptional chocolate that tantalizes the taste buds and tells the unique story of each cocoa bean's origin.
|
||||||
</motion.p>
|
</m.p>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -204,14 +206,14 @@ function AboutPage() {
|
|||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-16 items-center">
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-16 items-center">
|
||||||
{/* Italian Chocolate Text */}
|
{/* Italian Chocolate Text */}
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
variants={fadeInLeft}
|
variants={fadeInLeft}
|
||||||
className="order-2 lg:order-1 space-y-6 md:space-y-8 px-8 md:px-16 lg:px-24"
|
className="order-2 lg:order-1 space-y-6 md:space-y-8 px-8 md:px-16 lg:px-24"
|
||||||
>
|
>
|
||||||
<motion.h2
|
<m.h2
|
||||||
className="text-3xl md:text-4xl lg:text-5xl font-bold text-[#3C2A21]"
|
className="text-3xl md:text-4xl lg:text-5xl font-bold text-[#3C2A21]"
|
||||||
style={{
|
style={{
|
||||||
fontFamily: "MonetaSans-Regular",
|
fontFamily: "MonetaSans-Regular",
|
||||||
@ -225,8 +227,8 @@ function AboutPage() {
|
|||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
>
|
>
|
||||||
Capturing the essence of
|
Capturing the essence of
|
||||||
</motion.h2>
|
</m.h2>
|
||||||
<motion.h2
|
<m.h2
|
||||||
className="text-3xl md:text-4xl lg:text-5xl font-bold text-[#3C2A21] font-samantha"
|
className="text-3xl md:text-4xl lg:text-5xl font-bold text-[#3C2A21] font-samantha"
|
||||||
style={{
|
style={{
|
||||||
fontFamily: "Samantha Signature",
|
fontFamily: "Samantha Signature",
|
||||||
@ -240,9 +242,9 @@ function AboutPage() {
|
|||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
>
|
>
|
||||||
Italian Chocolate
|
Italian Chocolate
|
||||||
</motion.h2>
|
</m.h2>
|
||||||
|
|
||||||
<motion.p
|
<m.p
|
||||||
className="text-gray-700 leading-relaxed font-renner"
|
className="text-gray-700 leading-relaxed font-renner"
|
||||||
style={{
|
style={{
|
||||||
fontWeight: 300,
|
fontWeight: 300,
|
||||||
@ -257,18 +259,18 @@ function AboutPage() {
|
|||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
>
|
>
|
||||||
With over 15 years of hospitality experience, these avid travelers scoured the globe for the finest cocoa beans and techniques. Deep in remote cocoa farms, they cultivated relationships with farmers committed to sustainability. Carefully selecting beans, they honor each harvest's stories. In their cozy workshop, they roast, crack, and refine beans with modern techniques, capturing their essence in every Mozimo chocolate bar.
|
With over 15 years of hospitality experience, these avid travelers scoured the globe for the finest cocoa beans and techniques. Deep in remote cocoa farms, they cultivated relationships with farmers committed to sustainability. Carefully selecting beans, they honor each harvest's stories. In their cozy workshop, they roast, crack, and refine beans with modern techniques, capturing their essence in every Mozimo chocolate bar.
|
||||||
</motion.p>
|
</m.p>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Cocoa Farm Image */}
|
{/* Cocoa Farm Image */}
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
variants={fadeInRight}
|
variants={fadeInRight}
|
||||||
className="order-1 lg:order-2"
|
className="order-1 lg:order-2"
|
||||||
>
|
>
|
||||||
<motion.div
|
<m.div
|
||||||
className="relative w-full h-[400px] md:h-[500px] lg:h-[600px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500"
|
className="relative w-full h-[400px] md:h-[500px] lg:h-[600px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500"
|
||||||
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
||||||
>
|
>
|
||||||
@ -279,8 +281,8 @@ function AboutPage() {
|
|||||||
className="w-full h-full object-cover img-premium"
|
className="w-full h-full object-cover img-premium"
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
||||||
</motion.div>
|
</m.div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -289,14 +291,14 @@ function AboutPage() {
|
|||||||
<section className="py-16 md:py-24 bg-white">
|
<section className="py-16 md:py-24 bg-white">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
{/* Two Images Side by Side */}
|
{/* Two Images Side by Side */}
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
variants={staggerContainer}
|
variants={staggerContainer}
|
||||||
className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 mb-12 md:mb-16"
|
className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 mb-12 md:mb-16"
|
||||||
>
|
>
|
||||||
<motion.div
|
<m.div
|
||||||
variants={fadeInLeft}
|
variants={fadeInLeft}
|
||||||
className="relative w-full h-[300px] md:h-[400px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500"
|
className="relative w-full h-[300px] md:h-[400px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500"
|
||||||
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
||||||
@ -308,9 +310,9 @@ function AboutPage() {
|
|||||||
className="w-full h-full object-cover img-premium"
|
className="w-full h-full object-cover img-premium"
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
<motion.div
|
<m.div
|
||||||
variants={fadeInRight}
|
variants={fadeInRight}
|
||||||
className="relative w-full h-[300px] md:h-[400px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500"
|
className="relative w-full h-[300px] md:h-[400px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500"
|
||||||
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
||||||
@ -322,18 +324,18 @@ function AboutPage() {
|
|||||||
className="w-full h-full object-cover img-premium"
|
className="w-full h-full object-cover img-premium"
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
||||||
</motion.div>
|
</m.div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Text Content */}
|
{/* Text Content */}
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
variants={fadeInUp}
|
variants={fadeInUp}
|
||||||
className="w-full space-y-6 md:space-y-8 px-8 md:px-16 lg:px-24"
|
className="w-full space-y-6 md:space-y-8 px-8 md:px-16 lg:px-24"
|
||||||
>
|
>
|
||||||
<motion.p
|
<m.p
|
||||||
className="text-gray-700 leading-relaxed font-renner"
|
className="text-gray-700 leading-relaxed font-renner"
|
||||||
style={{
|
style={{
|
||||||
fontWeight: 300,
|
fontWeight: 300,
|
||||||
@ -348,9 +350,9 @@ function AboutPage() {
|
|||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
>
|
>
|
||||||
Under the mentorship of the master chocolatier Gabriele Rinaudo, Priyanka and Amritanshu dedicated themselves to mastering the intricate art of chocolate making. With unwavering determination and a thirst for knowledge, they immersed themselves in the world of cocoa, learning the nuances of sourcing the finest ingredients and perfecting the delicate techniques that transform raw beans into exquisite chocolate creations.
|
Under the mentorship of the master chocolatier Gabriele Rinaudo, Priyanka and Amritanshu dedicated themselves to mastering the intricate art of chocolate making. With unwavering determination and a thirst for knowledge, they immersed themselves in the world of cocoa, learning the nuances of sourcing the finest ingredients and perfecting the delicate techniques that transform raw beans into exquisite chocolate creations.
|
||||||
</motion.p>
|
</m.p>
|
||||||
|
|
||||||
<motion.p
|
<m.p
|
||||||
className="text-gray-700 leading-relaxed font-renner"
|
className="text-gray-700 leading-relaxed font-renner"
|
||||||
style={{
|
style={{
|
||||||
fontWeight: 300,
|
fontWeight: 300,
|
||||||
@ -365,15 +367,15 @@ function AboutPage() {
|
|||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
>
|
>
|
||||||
In addition to their training under Gabriele Rinaudo, they embarked on a transformative journey to Italy to further enrich their understanding of the art of chocolate making. This immersive experience in Italy not only broadened their knowledge but also deepened their appreciation for the timeless artistry and dedication that define the world of chocolate making.
|
In addition to their training under Gabriele Rinaudo, they embarked on a transformative journey to Italy to further enrich their understanding of the art of chocolate making. This immersive experience in Italy not only broadened their knowledge but also deepened their appreciation for the timeless artistry and dedication that define the world of chocolate making.
|
||||||
</motion.p>
|
</m.p>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Vision and Passion Section */}
|
{/* Vision and Passion Section */}
|
||||||
<section className="py-16 md:py-24 bg-[#F5E6D3]">
|
<section className="py-16 md:py-24 bg-[#F5E6D3]">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
@ -381,7 +383,7 @@ function AboutPage() {
|
|||||||
className="text-center space-y-8 md:space-y-12"
|
className="text-center space-y-8 md:space-y-12"
|
||||||
>
|
>
|
||||||
{/* Founders Outdoor Image */}
|
{/* Founders Outdoor Image */}
|
||||||
<motion.div
|
<m.div
|
||||||
className="relative w-full h-[400px] md:h-[500px] lg:h-[600px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500"
|
className="relative w-full h-[400px] md:h-[500px] lg:h-[600px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500"
|
||||||
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
||||||
>
|
>
|
||||||
@ -392,10 +394,10 @@ function AboutPage() {
|
|||||||
className="w-full h-full object-cover img-premium"
|
className="w-full h-full object-cover img-premium"
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Vision and Passion Text */}
|
{/* Vision and Passion Text */}
|
||||||
<motion.div
|
<m.div
|
||||||
className="w-full space-y-6 md:space-y-8 px-8 md:px-16 lg:px-24"
|
className="w-full space-y-6 md:space-y-8 px-8 md:px-16 lg:px-24"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
@ -414,12 +416,14 @@ function AboutPage() {
|
|||||||
>
|
>
|
||||||
Passionate about chocolate as a medium for creativity and exploration, they view it not just as a confection but as a canvas for artistic expression. Constantly seeking inspiration, they push the boundaries of chocolate-making, committed to crafting sensory experiences that delight the taste buds, eyes, and soul. Proud to be part of the global craft chocolate revolution, they aim to inspire others while championing cocoa diversity and sustainability. Back in the workshop, cacao beans are roasted, cracked, and refined with modern techniques, crafting each bar of Mozimo chocolate into a masterpiece, capturing the essence of its origins.
|
Passionate about chocolate as a medium for creativity and exploration, they view it not just as a confection but as a canvas for artistic expression. Constantly seeking inspiration, they push the boundaries of chocolate-making, committed to crafting sensory experiences that delight the taste buds, eyes, and soul. Proud to be part of the global craft chocolate revolution, they aim to inspire others while championing cocoa diversity and sustainability. Back in the workshop, cacao beans are roasted, cracked, and refined with modern techniques, crafting each bar of Mozimo chocolate into a masterpiece, capturing the essence of its origins.
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<Footer />
|
<Suspense fallback={<div className="h-[300px] w-full skeleton bg-gray-100 animate-pulse" />}>
|
||||||
|
<Footer />
|
||||||
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router';
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
import { motion } from "framer-motion";
|
import { m } from "framer-motion";
|
||||||
import Header from "@/components/Header";
|
import Header from "@/components/Header";
|
||||||
import Footer from "@/components/Footer";
|
// Footer is lazy loaded
|
||||||
import Section from "@/components/Section";
|
import Section from "@/components/Section";
|
||||||
import Button from "@/components/Button";
|
import Button from "@/components/Button";
|
||||||
import BannerSlider from "@/components/BannerSlider";
|
import BannerSlider from "@/components/BannerSlider";
|
||||||
import { Image } from "@unpic/react";
|
import { Image } from "@unpic/react";
|
||||||
import { useState, useEffect, useRef, useCallback } from "react";
|
import { useState, useEffect, useRef, useCallback, lazy, Suspense } from "react";
|
||||||
import ProductCategory from "@/components/ProductCategory";
|
const ProductCategory = lazy(() => import("@/components/ProductCategory"));
|
||||||
import SocialMedia from "@/components/SocialMedia";
|
const Footer = lazy(() => import("@/components/Footer"));
|
||||||
|
|
||||||
export const Route = createFileRoute('/')({
|
export const Route = createFileRoute('/')({
|
||||||
component: Home,
|
component: Home,
|
||||||
@ -17,30 +17,35 @@ export const Route = createFileRoute('/')({
|
|||||||
// Premium animation variants
|
// Premium animation variants
|
||||||
const fadeInUp = {
|
const fadeInUp = {
|
||||||
initial: { opacity: 0, y: 30 },
|
initial: { opacity: 0, y: 30 },
|
||||||
animate: { opacity: 1, y: 0 },
|
animate: { opacity: 1, y: 0, transition: { duration: 0.8, ease: [0.25, 0.46, 0.45, 0.94] as const } },
|
||||||
transition: { duration: 0.8, ease: [0.25, 0.46, 0.45, 0.94] },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const fadeInLeft = {
|
const fadeInLeft = {
|
||||||
initial: { opacity: 0, x: -30 },
|
initial: { opacity: 0, x: -30 },
|
||||||
animate: { opacity: 1, x: 0 },
|
animate: { opacity: 1, x: 0, transition: { duration: 0.8, ease: [0.25, 0.46, 0.45, 0.94] as const } },
|
||||||
transition: { duration: 0.8, ease: [0.25, 0.46, 0.45, 0.94] },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const fadeInRight = {
|
const fadeInRight = {
|
||||||
initial: { opacity: 0, x: 30 },
|
initial: { opacity: 0, x: 30 },
|
||||||
animate: { opacity: 1, x: 0 },
|
animate: { opacity: 1, x: 0, transition: { duration: 0.8, ease: [0.25, 0.46, 0.45, 0.94] as const } },
|
||||||
transition: { duration: 0.8, ease: [0.25, 0.46, 0.45, 0.94] },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const staggerContainer = {
|
const staggerContainer = {
|
||||||
|
initial: { opacity: 0 },
|
||||||
animate: {
|
animate: {
|
||||||
|
opacity: 1,
|
||||||
transition: {
|
transition: {
|
||||||
staggerChildren: 0.2,
|
staggerChildren: 0.2,
|
||||||
|
delayChildren: 0.1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const itemUp = {
|
||||||
|
initial: { opacity: 0, y: 20 },
|
||||||
|
animate: { opacity: 1, y: 0, transition: { duration: 0.6 } }
|
||||||
|
};
|
||||||
|
|
||||||
const categories = [
|
const categories = [
|
||||||
"Bars",
|
"Bars",
|
||||||
"Barks",
|
"Barks",
|
||||||
@ -134,14 +139,14 @@ function Home() {
|
|||||||
<Section background="white" id="about">
|
<Section background="white" id="about">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 items-center">
|
<div className="grid grid-cols-1 lg:grid-cols-2 items-center">
|
||||||
{/* Brand Story - Left Text */}
|
{/* Brand Story - Left Text */}
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
variants={fadeInLeft}
|
variants={fadeInLeft}
|
||||||
className="space-y-6 md:space-y-8 order-2 lg:order-1 px-4 md:px-0" // ← Added mobile padding
|
className="space-y-6 md:space-y-8 order-2 lg:order-1 px-4 md:px-0" // ← Added mobile padding
|
||||||
>
|
>
|
||||||
<motion.h2
|
<m.h2
|
||||||
className="text-3xl md:text-4xl lg:text-5xl font-bold text-[#3C2A21] font-moneta text-gradient p-4 md:p-0"
|
className="text-3xl md:text-4xl lg:text-5xl font-bold text-[#3C2A21] font-moneta text-gradient p-4 md:p-0"
|
||||||
style={{
|
style={{
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
@ -155,7 +160,7 @@ function Home() {
|
|||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
>
|
>
|
||||||
Brand Story
|
Brand Story
|
||||||
</motion.h2>
|
</m.h2>
|
||||||
<div
|
<div
|
||||||
className="space-y-4 md:space-y-6 text-gray-700 leading-relaxed font-renner"
|
className="space-y-4 md:space-y-6 text-gray-700 leading-relaxed font-renner"
|
||||||
style={{
|
style={{
|
||||||
@ -166,7 +171,7 @@ function Home() {
|
|||||||
fontFamily: "Renner*",
|
fontFamily: "Renner*",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<motion.p
|
<m.p
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.6, delay: 0.1 }}
|
transition={{ duration: 0.6, delay: 0.1 }}
|
||||||
@ -175,8 +180,8 @@ function Home() {
|
|||||||
Mozimo's journey is a passionate pursuit of crafting
|
Mozimo's journey is a passionate pursuit of crafting
|
||||||
exceptional chocolate that celebrates the origin of each cocoa
|
exceptional chocolate that celebrates the origin of each cocoa
|
||||||
bean.
|
bean.
|
||||||
</motion.p>
|
</m.p>
|
||||||
<motion.p
|
<m.p
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.6, delay: 0.2 }}
|
transition={{ duration: 0.6, delay: 0.2 }}
|
||||||
@ -184,8 +189,8 @@ function Home() {
|
|||||||
>
|
>
|
||||||
We meticulously roast, crack, winnow, and refine beans in-house,
|
We meticulously roast, crack, winnow, and refine beans in-house,
|
||||||
using modern techniques to highlight their natural flavors.
|
using modern techniques to highlight their natural flavors.
|
||||||
</motion.p>
|
</m.p>
|
||||||
<motion.p
|
<m.p
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.6, delay: 0.3 }}
|
transition={{ duration: 0.6, delay: 0.3 }}
|
||||||
@ -193,9 +198,9 @@ function Home() {
|
|||||||
>
|
>
|
||||||
Each chocolate is a masterpiece, capturing the essence of cocoa
|
Each chocolate is a masterpiece, capturing the essence of cocoa
|
||||||
in its purest form.
|
in its purest form.
|
||||||
</motion.p>
|
</m.p>
|
||||||
</div>
|
</div>
|
||||||
<motion.div
|
<m.div
|
||||||
className="pt-4"
|
className="pt-4"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
@ -205,17 +210,17 @@ function Home() {
|
|||||||
<Button variant="white" size="lg" className="btn-premium">
|
<Button variant="white" size="lg" className="btn-premium">
|
||||||
Discover more
|
Discover more
|
||||||
</Button>
|
</Button>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
{/* Brand Story - Right Image */}
|
{/* Brand Story - Right Image */}
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
variants={fadeInRight}
|
variants={fadeInRight}
|
||||||
className="relative order-1 lg:order-2 w-screen md:w-auto -mx-4 md:mx-0"
|
className="relative order-1 lg:order-2 w-screen md:w-auto -mx-4 md:mx-0"
|
||||||
>
|
>
|
||||||
<motion.div
|
<m.div
|
||||||
className="relative w-full h-[300px] md:h-[400px] lg:h-[500px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500 clip-diagonal-bottom-left"
|
className="relative w-full h-[300px] md:h-[400px] lg:h-[500px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500 clip-diagonal-bottom-left"
|
||||||
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
||||||
>
|
>
|
||||||
@ -227,18 +232,18 @@ function Home() {
|
|||||||
draggable={false}
|
draggable={false}
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
||||||
</motion.div>
|
</m.div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Chocolate Tempering - Left Video */}
|
{/* Chocolate Tempering - Left Video */}
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
variants={fadeInLeft}
|
variants={fadeInLeft}
|
||||||
className="relative order-3 lg:order-3 w-screen md:w-auto -mx-4 md:mx-0 py-4 md:py-0"
|
className="relative order-3 lg:order-3 w-screen md:w-auto -mx-4 md:mx-0 py-4 md:py-0"
|
||||||
>
|
>
|
||||||
<motion.div
|
<m.div
|
||||||
className="relative w-full h-[400px] md:h-[500px] lg:h-[700px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500 clip-diagonal-top-right"
|
className="relative w-full h-[400px] md:h-[500px] lg:h-[700px] overflow-hidden shadow-premium hover:shadow-premium-hover transition-all duration-500 clip-diagonal-top-right"
|
||||||
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
whileHover={{ scale: 1.02, transition: { duration: 0.3 } }}
|
||||||
>
|
>
|
||||||
@ -253,11 +258,11 @@ function Home() {
|
|||||||
aria-label="Chocolate pouring from metallic spout - Mozimo chocolate tempering process"
|
aria-label="Chocolate pouring from metallic spout - Mozimo chocolate tempering process"
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
||||||
</motion.div>
|
</m.div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Chocolate Tempering - Right Text */}
|
{/* Chocolate Tempering - Right Text */}
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
@ -265,7 +270,7 @@ function Home() {
|
|||||||
className="space-y-4 md:space-y-6 order-4 lg:order-4 px-4 md:px-0 ml-4 md:ml-8 lg:ml-12"
|
className="space-y-4 md:space-y-6 order-4 lg:order-4 px-4 md:px-0 ml-4 md:ml-8 lg:ml-12"
|
||||||
>
|
>
|
||||||
<div className="space-y-3 md:space-y-4">
|
<div className="space-y-3 md:space-y-4">
|
||||||
<motion.h2
|
<m.h2
|
||||||
className="text-2xl md:text-3xl lg:text-4xl font-bold text-[#3C2A21] font-renner text-gradient"
|
className="text-2xl md:text-3xl lg:text-4xl font-bold text-[#3C2A21] font-renner text-gradient"
|
||||||
style={{
|
style={{
|
||||||
fontWeight: 200,
|
fontWeight: 200,
|
||||||
@ -279,8 +284,8 @@ function Home() {
|
|||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
>
|
>
|
||||||
Discover the delicate art of our
|
Discover the delicate art of our
|
||||||
</motion.h2>
|
</m.h2>
|
||||||
<motion.h3
|
<m.h3
|
||||||
className="text-4xl md:text-5xl lg:text-7xl font-bold text-[#8B4513] font-samantha"
|
className="text-4xl md:text-5xl lg:text-7xl font-bold text-[#8B4513] font-samantha"
|
||||||
style={{
|
style={{
|
||||||
fontFamily: "Samantha Signature",
|
fontFamily: "Samantha Signature",
|
||||||
@ -295,10 +300,10 @@ function Home() {
|
|||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
>
|
>
|
||||||
Chocolate Tempering
|
Chocolate Tempering
|
||||||
</motion.h3>
|
</m.h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<motion.div
|
<m.div
|
||||||
className="w-100 h-px bg-gradient-to-r from-transparent via-[#8B4513] to-transparent"
|
className="w-100 h-px bg-gradient-to-r from-transparent via-[#8B4513] to-transparent"
|
||||||
initial={{ scaleX: 0 }}
|
initial={{ scaleX: 0 }}
|
||||||
whileInView={{ scaleX: 1 }}
|
whileInView={{ scaleX: 1 }}
|
||||||
@ -306,7 +311,7 @@ function Home() {
|
|||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<motion.p
|
<m.p
|
||||||
className="text-gray-700 leading-relaxed font-renner"
|
className="text-gray-700 leading-relaxed font-renner"
|
||||||
style={{
|
style={{
|
||||||
fontWeight: 300,
|
fontWeight: 300,
|
||||||
@ -325,14 +330,14 @@ function Home() {
|
|||||||
perfectly tempered chocolate: velvety smooth, exquisitely rich,
|
perfectly tempered chocolate: velvety smooth, exquisitely rich,
|
||||||
and artfully balanced. Each bite offers a symphony of nuanced
|
and artfully balanced. Each bite offers a symphony of nuanced
|
||||||
cocoa flavors, melting luxuriously!
|
cocoa flavors, melting luxuriously!
|
||||||
</motion.p>
|
</m.p>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
{/* Our Collections Section */}
|
{/* Our Collections Section */}
|
||||||
<Section background="cream" id="shop">
|
<Section background="cream" id="shop">
|
||||||
<motion.h2
|
<m.h2
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
@ -349,9 +354,9 @@ function Home() {
|
|||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
>
|
>
|
||||||
Our Collections
|
Our Collections
|
||||||
</motion.h2>
|
</m.h2>
|
||||||
|
|
||||||
<motion.div
|
<m.div
|
||||||
className="flex overflow-x-auto no-scrollbar snap-x snap-mandatory gap-4 px-4 sm:px-0 sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:gap-6 md:gap-8"
|
className="flex overflow-x-auto no-scrollbar snap-x snap-mandatory gap-4 px-4 sm:px-0 sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:gap-6 md:gap-8"
|
||||||
variants={staggerContainer}
|
variants={staggerContainer}
|
||||||
initial="initial"
|
initial="initial"
|
||||||
@ -375,7 +380,7 @@ function Home() {
|
|||||||
alt: "Gift Collection - Mozimo packaged chocolate products and gift items",
|
alt: "Gift Collection - Mozimo packaged chocolate products and gift items",
|
||||||
},
|
},
|
||||||
].map((item) => (
|
].map((item) => (
|
||||||
<motion.div
|
<m.div
|
||||||
key={item.title}
|
key={item.title}
|
||||||
variants={fadeInUp}
|
variants={fadeInUp}
|
||||||
className="snap-start w-[calc(50%)] flex-shrink-0 sm:w-auto sm:flex-shrink sm:min-w-0 group flex flex-col items-center justify-end transition-all duration-500 hover:-translate-y-2"
|
className="snap-start w-[calc(50%)] flex-shrink-0 sm:w-auto sm:flex-shrink sm:min-w-0 group flex flex-col items-center justify-end transition-all duration-500 hover:-translate-y-2"
|
||||||
@ -391,9 +396,8 @@ function Home() {
|
|||||||
width={320}
|
width={320}
|
||||||
height={400}
|
height={400}
|
||||||
layout="constrained"
|
layout="constrained"
|
||||||
className="object-contain img-premium group-hover:scale-105 transition-transform duration-500"
|
className="object-contain img-premium group-hover:scale-105 transition-transform duration-500 max-h-[380px] w-full"
|
||||||
draggable={false}
|
draggable={false}
|
||||||
style={{ maxHeight: "380px", width: "100%" }}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="p-4 md:p-6 text-center mb-2 w-full">
|
<div className="p-4 md:p-6 text-center mb-2 w-full">
|
||||||
@ -410,18 +414,20 @@ function Home() {
|
|||||||
{item.title}
|
{item.title}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
))}
|
))}
|
||||||
</motion.div>
|
</m.div>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<ProductCategory />
|
<Suspense fallback={<div className="h-[500px] w-full skeleton bg-gray-100 animate-pulse" />}>
|
||||||
|
<ProductCategory />
|
||||||
|
</Suspense>
|
||||||
{/* Social Media Call to Action */}
|
{/* Social Media Call to Action */}
|
||||||
<SocialMedia />
|
{/* <SocialMedia /> */}
|
||||||
|
|
||||||
{/* In the Spotlight Section */}
|
{/* In the Spotlight Section */}
|
||||||
<Section background="white">
|
<Section background="white">
|
||||||
<motion.h2
|
<m.h2
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
@ -438,10 +444,10 @@ function Home() {
|
|||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
>
|
>
|
||||||
In the Spotlight
|
In the Spotlight
|
||||||
</motion.h2>
|
</m.h2>
|
||||||
<div className="w-full flex justify-center items-center py-8 md:py-12">
|
<div className="w-full flex justify-center items-center py-8 md:py-12">
|
||||||
<div className="w-full max-w-[700px] px-4 overflow-hidden">
|
<div className="w-full max-w-[700px] px-4 overflow-hidden">
|
||||||
<motion.div
|
<m.div
|
||||||
className="flex gap-8 py-6"
|
className="flex gap-8 py-6"
|
||||||
animate={{ x: `-${spotlightIndex * 152}px` }}
|
animate={{ x: `-${spotlightIndex * 152}px` }}
|
||||||
transition={{ type: "spring", stiffness: 80, damping: 18 }}
|
transition={{ type: "spring", stiffness: 80, damping: 18 }}
|
||||||
@ -452,7 +458,7 @@ function Home() {
|
|||||||
const imgIdx = i % partnerImages.length;
|
const imgIdx = i % partnerImages.length;
|
||||||
const img = partnerImages[imgIdx];
|
const img = partnerImages[imgIdx];
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<m.div
|
||||||
key={i}
|
key={i}
|
||||||
className="w-24 h-24 md:w-32 md:h-32 lg:w-36 lg:h-36 bg-white rounded-full flex items-center justify-center shadow-premium hover:shadow-premium-hover flex-shrink-0 transition-all duration-300"
|
className="w-24 h-24 md:w-32 md:h-32 lg:w-36 lg:h-36 bg-white rounded-full flex items-center justify-center shadow-premium hover:shadow-premium-hover flex-shrink-0 transition-all duration-300"
|
||||||
style={{
|
style={{
|
||||||
@ -474,15 +480,17 @@ function Home() {
|
|||||||
className="w-16 h-16 md:w-20 md:h-20 lg:w-20 lg:h-20 object-contain img-premium"
|
className="w-16 h-16 md:w-20 md:h-20 lg:w-20 lg:h-20 object-contain img-premium"
|
||||||
draggable={false}
|
draggable={false}
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</m.div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<Footer />
|
<Suspense fallback={<div className="h-[300px] w-full skeleton bg-gray-100 animate-pulse" />}>
|
||||||
|
<Footer />
|
||||||
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { useState, useEffect, useRef } from "react";
|
import { useState, useEffect, useRef } from "react";
|
||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { m, AnimatePresence } from "framer-motion";
|
||||||
import { Image } from "@unpic/react";
|
import { Image } from "@unpic/react";
|
||||||
|
|
||||||
const banners = [
|
const banners = [
|
||||||
@ -95,7 +95,7 @@ export default function BannerSlider() {
|
|||||||
|
|
||||||
{/* Banner Images with Premium Animations */}
|
{/* Banner Images with Premium Animations */}
|
||||||
<AnimatePresence initial={false} custom={direction} mode="popLayout">
|
<AnimatePresence initial={false} custom={direction} mode="popLayout">
|
||||||
<motion.div
|
<m.div
|
||||||
key={`${currentIndex}-${direction}`}
|
key={`${currentIndex}-${direction}`}
|
||||||
custom={direction}
|
custom={direction}
|
||||||
variants={slideVariants}
|
variants={slideVariants}
|
||||||
@ -130,13 +130,13 @@ export default function BannerSlider() {
|
|||||||
|
|
||||||
{/* Premium overlay with gradient */}
|
{/* Premium overlay with gradient */}
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
|
||||||
</motion.div>
|
</m.div>
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|
||||||
{/* Premium Shop Now Button */}
|
{/* Premium Shop Now Button */}
|
||||||
{currentIndex === 0 && (
|
{currentIndex === 0 && (
|
||||||
<div className="absolute bottom-16 md:bottom-20 left-1/2 transform -translate-x-1/2 z-10">
|
<div className="absolute bottom-16 md:bottom-20 left-1/2 transform -translate-x-1/2 z-10">
|
||||||
<motion.a
|
<m.a
|
||||||
href="https://shop.mozimo.in/"
|
href="https://shop.mozimo.in/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
@ -159,7 +159,7 @@ export default function BannerSlider() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span className="relative z-10">Shop Now</span>
|
<span className="relative z-10">Shop Now</span>
|
||||||
</motion.a>
|
</m.a>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ export default function BannerSlider() {
|
|||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{showArrows && (
|
{showArrows && (
|
||||||
<>
|
<>
|
||||||
<motion.button
|
<m.button
|
||||||
initial={{ opacity: 0, x: -20 }}
|
initial={{ opacity: 0, x: -20 }}
|
||||||
animate={{ opacity: 1, x: 0 }}
|
animate={{ opacity: 1, x: 0 }}
|
||||||
exit={{ opacity: 0, x: -20 }}
|
exit={{ opacity: 0, x: -20 }}
|
||||||
@ -191,9 +191,9 @@ export default function BannerSlider() {
|
|||||||
d="M15 19l-7-7 7-7"
|
d="M15 19l-7-7 7-7"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</motion.button>
|
</m.button>
|
||||||
|
|
||||||
<motion.button
|
<m.button
|
||||||
initial={{ opacity: 0, x: 20 }}
|
initial={{ opacity: 0, x: 20 }}
|
||||||
animate={{ opacity: 1, x: 0 }}
|
animate={{ opacity: 1, x: 0 }}
|
||||||
exit={{ opacity: 0, x: 20 }}
|
exit={{ opacity: 0, x: 20 }}
|
||||||
@ -217,14 +217,14 @@ export default function BannerSlider() {
|
|||||||
d="M9 5l7 7-7 7"
|
d="M9 5l7 7-7 7"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</motion.button>
|
</m.button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|
||||||
{/* Mobile Navigation Arrows */}
|
{/* Mobile Navigation Arrows */}
|
||||||
<div className="md:hidden absolute inset-x-0 top-1/2 transform -translate-y-1/2 z-20 flex justify-between items-center px-4">
|
<div className="md:hidden absolute inset-x-0 top-1/2 transform -translate-y-1/2 z-20 flex justify-between items-center px-4">
|
||||||
<motion.button
|
<m.button
|
||||||
onClick={goToPrevious}
|
onClick={goToPrevious}
|
||||||
className="glass text-white p-3 rounded-full backdrop-blur-sm transition-all duration-300 border border-white/20 hover:border-white/40 shadow-premium"
|
className="glass text-white p-3 rounded-full backdrop-blur-sm transition-all duration-300 border border-white/20 hover:border-white/40 shadow-premium"
|
||||||
whileHover={{ scale: 1.1, rotate: -5 }}
|
whileHover={{ scale: 1.1, rotate: -5 }}
|
||||||
@ -244,9 +244,9 @@ export default function BannerSlider() {
|
|||||||
d="M15 19l-7-7 7-7"
|
d="M15 19l-7-7 7-7"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</motion.button>
|
</m.button>
|
||||||
|
|
||||||
<motion.button
|
<m.button
|
||||||
onClick={goToNext}
|
onClick={goToNext}
|
||||||
className="glass text-white p-3 rounded-full backdrop-blur-sm transition-all duration-300 border border-white/20 hover:border-white/40 shadow-premium"
|
className="glass text-white p-3 rounded-full backdrop-blur-sm transition-all duration-300 border border-white/20 hover:border-white/40 shadow-premium"
|
||||||
whileHover={{ scale: 1.1, rotate: 5 }}
|
whileHover={{ scale: 1.1, rotate: 5 }}
|
||||||
@ -266,13 +266,13 @@ export default function BannerSlider() {
|
|||||||
d="M9 5l7 7-7 7"
|
d="M9 5l7 7-7 7"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</motion.button>
|
</m.button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Premium Dots Indicator */}
|
{/* Premium Dots Indicator */}
|
||||||
<div className="absolute bottom-6 md:bottom-8 left-1/2 transform -translate-x-1/2 z-20 hidden md:flex space-x-2 md:space-x-3">
|
<div className="absolute bottom-6 md:bottom-8 left-1/2 transform -translate-x-1/2 z-20 hidden md:flex space-x-2 md:space-x-3">
|
||||||
{banners.map((_, index) => (
|
{banners.map((_, index) => (
|
||||||
<motion.button
|
<m.button
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => goToSlide(index)}
|
onClick={() => goToSlide(index)}
|
||||||
className={`w-2 h-2 md:w-3 md:h-3 rounded-full transition-all duration-300 ${
|
className={`w-2 h-2 md:w-3 md:h-3 rounded-full transition-all duration-300 ${
|
||||||
@ -289,7 +289,7 @@ export default function BannerSlider() {
|
|||||||
|
|
||||||
{/* Premium Progress Bar */}
|
{/* Premium Progress Bar */}
|
||||||
<div className="absolute bottom-0 left-0 right-0 h-1 bg-white/10 z-20">
|
<div className="absolute bottom-0 left-0 right-0 h-1 bg-white/10 z-20">
|
||||||
<motion.div
|
<m.div
|
||||||
className="h-full bg-gradient-to-r from-[#8B4513] to-[#DAA520]"
|
className="h-full bg-gradient-to-r from-[#8B4513] to-[#DAA520]"
|
||||||
initial={{ width: 0 }}
|
initial={{ width: 0 }}
|
||||||
animate={{ width: "100%" }}
|
animate={{ width: "100%" }}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { motion } from "framer-motion";
|
import { m } from "framer-motion";
|
||||||
import { Image } from "@unpic/react";
|
import { Image } from "@unpic/react";
|
||||||
|
|
||||||
export default function DesktopFooter() {
|
export default function DesktopFooter() {
|
||||||
@ -11,7 +11,7 @@ export default function DesktopFooter() {
|
|||||||
|
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 md:py-12 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8 relative z-10">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 md:py-12 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8 relative z-10">
|
||||||
{/* Column 1: Brand Identity */}
|
{/* Column 1: Brand Identity */}
|
||||||
<motion.div
|
<m.div
|
||||||
className="space-y-4 sm:col-span-2 lg:col-span-1"
|
className="space-y-4 sm:col-span-2 lg:col-span-1"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
@ -41,10 +41,10 @@ export default function DesktopFooter() {
|
|||||||
India's Premier European style bean-to-bar chocolate
|
India's Premier European style bean-to-bar chocolate
|
||||||
experience.
|
experience.
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Column 2: Get in touch */}
|
{/* Column 2: Get in touch */}
|
||||||
<motion.div
|
<m.div
|
||||||
className="space-y-4"
|
className="space-y-4"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
@ -73,7 +73,7 @@ export default function DesktopFooter() {
|
|||||||
fontFamily: "Renner*",
|
fontFamily: "Renner*",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<motion.div
|
<m.div
|
||||||
className="flex items-center space-x-2"
|
className="flex items-center space-x-2"
|
||||||
initial={{ opacity: 0, x: -10 }}
|
initial={{ opacity: 0, x: -10 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
@ -89,8 +89,8 @@ export default function DesktopFooter() {
|
|||||||
<path d="M2 3a1 1 0 011-1h2.153a1 1 0 01.986.836l.74 4.435a1 1 0 01-.54 1.06l-1.548.773a11.037 11.037 0 006.105 6.105l.774-1.548a1 1 0 011.059-.54l4.435.74a1 1 0 01.836.986V17a1 1 0 01-1 1h-2C7.82 18 2 12.18 2 5V3z" />
|
<path d="M2 3a1 1 0 011-1h2.153a1 1 0 01.986.836l.74 4.435a1 1 0 01-.54 1.06l-1.548.773a11.037 11.037 0 006.105 6.105l.774-1.548a1 1 0 011.059-.54l4.435.74a1 1 0 01.836.986V17a1 1 0 01-1 1h-2C7.82 18 2 12.18 2 5V3z" />
|
||||||
</svg>
|
</svg>
|
||||||
<span className="text-xs md:text-sm">0172-4045414</span>
|
<span className="text-xs md:text-sm">0172-4045414</span>
|
||||||
</motion.div>
|
</m.div>
|
||||||
<motion.div
|
<m.div
|
||||||
className="flex items-start space-x-2"
|
className="flex items-start space-x-2"
|
||||||
initial={{ opacity: 0, x: -10 }}
|
initial={{ opacity: 0, x: -10 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
@ -112,12 +112,12 @@ export default function DesktopFooter() {
|
|||||||
<span className="text-xs md:text-sm">
|
<span className="text-xs md:text-sm">
|
||||||
SCO 8, Inner Market, 9-D, Sector 9, Chandigarh, 160009
|
SCO 8, Inner Market, 9-D, Sector 9, Chandigarh, 160009
|
||||||
</span>
|
</span>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Column 3: Know more */}
|
{/* Column 3: Know more */}
|
||||||
<motion.div
|
<m.div
|
||||||
className="space-y-4"
|
className="space-y-4"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
@ -152,7 +152,7 @@ export default function DesktopFooter() {
|
|||||||
"Terms & Conditions",
|
"Terms & Conditions",
|
||||||
"Shipping Policy",
|
"Shipping Policy",
|
||||||
].map((link, index) => (
|
].map((link, index) => (
|
||||||
<motion.li
|
<m.li
|
||||||
key={link}
|
key={link}
|
||||||
initial={{ opacity: 0, x: -10 }}
|
initial={{ opacity: 0, x: -10 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
@ -166,13 +166,13 @@ export default function DesktopFooter() {
|
|||||||
{link}
|
{link}
|
||||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-[#8B4513] to-[#DAA520] transition-all duration-300 group-hover:w-full"></span>
|
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-[#8B4513] to-[#DAA520] transition-all duration-300 group-hover:w-full"></span>
|
||||||
</a>
|
</a>
|
||||||
</motion.li>
|
</m.li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Column 4: FAQ, Store, Ordering, Social Media */}
|
{/* Column 4: FAQ, Store, Ordering, Social Media */}
|
||||||
<motion.div
|
<m.div
|
||||||
className="space-y-4 sm:col-span-2 lg:col-span-1"
|
className="space-y-4 sm:col-span-2 lg:col-span-1"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
@ -191,7 +191,7 @@ export default function DesktopFooter() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{["FAQ", "Locate our store", "Bulk Ordering"].map((link, index) => (
|
{["FAQ", "Locate our store", "Bulk Ordering"].map((link, index) => (
|
||||||
<motion.div
|
<m.div
|
||||||
key={link}
|
key={link}
|
||||||
initial={{ opacity: 0, x: -10 }}
|
initial={{ opacity: 0, x: -10 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
@ -205,7 +205,7 @@ export default function DesktopFooter() {
|
|||||||
{link}
|
{link}
|
||||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-[#8B4513] to-[#DAA520] transition-all duration-300 group-hover:w-full"></span>
|
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-[#8B4513] to-[#DAA520] transition-all duration-300 group-hover:w-full"></span>
|
||||||
</a>
|
</a>
|
||||||
</motion.div>
|
</m.div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ export default function DesktopFooter() {
|
|||||||
</h3>
|
</h3>
|
||||||
<div className="flex space-x-3 md:space-x-4">
|
<div className="flex space-x-3 md:space-x-4">
|
||||||
{/* Facebook */}
|
{/* Facebook */}
|
||||||
<motion.a
|
<m.a
|
||||||
href="https://www.facebook.com/share/16vPmvcQV7/?mibextid=wwXIfr"
|
href="https://www.facebook.com/share/16vPmvcQV7/?mibextid=wwXIfr"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
@ -245,9 +245,9 @@ export default function DesktopFooter() {
|
|||||||
>
|
>
|
||||||
<path d="M22.675 0h-21.35C.595 0 0 .592 0 1.326v21.348C0 23.408.595 24 1.325 24h11.495v-9.294H9.692v-3.622h3.128V8.413c0-3.1 1.893-4.788 4.659-4.788 1.325 0 2.463.099 2.797.143v3.24l-1.918.001c-1.504 0-1.797.715-1.797 1.763v2.313h3.587l-.467 3.622h-3.12V24h6.116C23.406 24 24 23.408 24 22.674V1.326C24 .592 23.406 0 22.675 0" />
|
<path d="M22.675 0h-21.35C.595 0 0 .592 0 1.326v21.348C0 23.408.595 24 1.325 24h11.495v-9.294H9.692v-3.622h3.128V8.413c0-3.1 1.893-4.788 4.659-4.788 1.325 0 2.463.099 2.797.143v3.24l-1.918.001c-1.504 0-1.797.715-1.797 1.763v2.313h3.587l-.467 3.622h-3.12V24h6.116C23.406 24 24 23.408 24 22.674V1.326C24 .592 23.406 0 22.675 0" />
|
||||||
</svg>
|
</svg>
|
||||||
</motion.a>
|
</m.a>
|
||||||
{/* Instagram */}
|
{/* Instagram */}
|
||||||
<motion.a
|
<m.a
|
||||||
href="https://www.instagram.com/mozimo.choc?igsh=bTVzbGo0enV3b3Jn"
|
href="https://www.instagram.com/mozimo.choc?igsh=bTVzbGo0enV3b3Jn"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
@ -267,9 +267,9 @@ export default function DesktopFooter() {
|
|||||||
>
|
>
|
||||||
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 1.366.062 2.633.334 3.608 1.308.974.974 1.246 2.241 1.308 3.608.058 1.266.069 1.646.069 4.85s-.012 3.584-.07 4.85c-.062 1.366-.334 2.633-1.308 3.608-.974.974-2.241 1.246-3.608 1.308-1.266.058-1.646.069-4.85.069s-3.584-.012-4.85-.07c-1.366-.062-2.633-.334-3.608-1.308-.974-.974-1.246-2.241-1.308-3.608C2.175 15.647 2.163 15.267 2.163 12s.012-3.584.07-4.85c.062-1.366.334-2.633 1.308-3.608C4.515 2.567 5.782 2.295 7.148 2.233 8.414 2.175 8.794 2.163 12 2.163zm0-2.163C8.741 0 8.332.012 7.052.07 5.771.128 4.659.334 3.678 1.315c-.98.98-1.187 2.092-1.245 3.373C2.012 5.668 2 6.077 2 12c0 5.923.012 6.332.07 7.612.058 1.281.265 2.393 1.245 3.373.98.98 2.092 1.187 3.373 1.245C8.332 23.988 8.741 24 12 24s3.668-.012 4.948-.07c1.281-.058 2.393-.265 3.373-1.245.98-.98 1.187-2.092 1.245-3.373.058-1.28.07-1.689.07-7.612 0-5.923-.012-6.332-.07-7.612-.058-1.281-.265-2.393-1.245-3.373-.98-.98-2.092-1.187-3.373-1.245C15.668.012 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zm0 10.162a3.999 3.999 0 1 1 0-7.998 3.999 3.999 0 0 1 0 7.998zm6.406-11.845a1.44 1.44 0 1 0 0 2.88 1.44 1.44 0 0 0 0-2.88z" />
|
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 1.366.062 2.633.334 3.608 1.308.974.974 1.246 2.241 1.308 3.608.058 1.266.069 1.646.069 4.85s-.012 3.584-.07 4.85c-.062 1.366-.334 2.633-1.308 3.608-.974.974-2.241 1.246-3.608 1.308-1.266.058-1.646.069-4.85.069s-3.584-.012-4.85-.07c-1.366-.062-2.633-.334-3.608-1.308-.974-.974-1.246-2.241-1.308-3.608C2.175 15.647 2.163 15.267 2.163 12s.012-3.584.07-4.85c.062-1.366.334-2.633 1.308-3.608C4.515 2.567 5.782 2.295 7.148 2.233 8.414 2.175 8.794 2.163 12 2.163zm0-2.163C8.741 0 8.332.012 7.052.07 5.771.128 4.659.334 3.678 1.315c-.98.98-1.187 2.092-1.245 3.373C2.012 5.668 2 6.077 2 12c0 5.923.012 6.332.07 7.612.058 1.281.265 2.393 1.245 3.373.98.98 2.092 1.187 3.373 1.245C8.332 23.988 8.741 24 12 24s3.668-.012 4.948-.07c1.281-.058 2.393-.265 3.373-1.245.98-.98 1.187-2.092 1.245-3.373.058-1.28.07-1.689.07-7.612 0-5.923-.012-6.332-.07-7.612-.058-1.281-.265-2.393-1.245-3.373-.98-.98-2.092-1.187-3.373-1.245C15.668.012 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zm0 10.162a3.999 3.999 0 1 1 0-7.998 3.999 3.999 0 0 1 0 7.998zm6.406-11.845a1.44 1.44 0 1 0 0 2.88 1.44 1.44 0 0 0 0-2.88z" />
|
||||||
</svg>
|
</svg>
|
||||||
</motion.a>
|
</m.a>
|
||||||
{/* YouTube */}
|
{/* YouTube */}
|
||||||
<motion.a
|
<m.a
|
||||||
href="https://www.youtube.com/@MozimoChocolates"
|
href="https://www.youtube.com/@MozimoChocolates"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
@ -289,9 +289,9 @@ export default function DesktopFooter() {
|
|||||||
>
|
>
|
||||||
<path d="M23.498 6.186a2.994 2.994 0 0 0-2.107-2.117C19.163 3.5 12 3.5 12 3.5s-7.163 0-9.391.569A2.994 2.994 0 0 0 .502 6.186C0 8.413 0 12 0 12s0 3.587.502 5.814a2.994 2.994 0 0 0 2.107 2.117C4.837 20.5 12 20.5 12 20.5s7.163 0 9.391-.569a2.994 2.994 0 0 0 2.107-2.117C24 15.587 24 12 24 12s0-3.587-.502-5.814zM9.545 15.568V8.432l6.545 3.568-6.545 3.568z" />
|
<path d="M23.498 6.186a2.994 2.994 0 0 0-2.107-2.117C19.163 3.5 12 3.5 12 3.5s-7.163 0-9.391.569A2.994 2.994 0 0 0 .502 6.186C0 8.413 0 12 0 12s0 3.587.502 5.814a2.994 2.994 0 0 0 2.107 2.117C4.837 20.5 12 20.5 12 20.5s7.163 0 9.391-.569a2.994 2.994 0 0 0 2.107-2.117C24 15.587 24 12 24 12s0-3.587-.502-5.814zM9.545 15.568V8.432l6.545 3.568-6.545 3.568z" />
|
||||||
</svg>
|
</svg>
|
||||||
</motion.a>
|
</m.a>
|
||||||
{/* LinkedIn */}
|
{/* LinkedIn */}
|
||||||
<motion.a
|
<m.a
|
||||||
href="https://www.linkedin.com/company/mozimochocolates/"
|
href="https://www.linkedin.com/company/mozimochocolates/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
@ -311,14 +311,14 @@ export default function DesktopFooter() {
|
|||||||
>
|
>
|
||||||
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.761 0 5-2.239 5-5v-14c0-2.761-2.239-5-5-5zm-11 19h-3v-10h3v10zm-1.5-11.268c-.966 0-1.75-.784-1.75-1.75s.784-1.75 1.75-1.75 1.75.784 1.75 1.75-.784 1.75-1.75 1.75zm15.5 11.268h-3v-5.604c0-1.337-.025-3.063-1.868-3.063-1.868 0-2.154 1.459-2.154 2.967v5.7h-3v-10h2.881v1.367h.041c.401-.761 1.381-1.563 2.841-1.563 3.039 0 3.6 2.001 3.6 4.601v5.595z" />
|
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.761 0 5-2.239 5-5v-14c0-2.761-2.239-5-5-5zm-11 19h-3v-10h3v10zm-1.5-11.268c-.966 0-1.75-.784-1.75-1.75s.784-1.75 1.75-1.75 1.75.784 1.75 1.75-.784 1.75-1.75 1.75zm15.5 11.268h-3v-5.604c0-1.337-.025-3.063-1.868-3.063-1.868 0-2.154 1.459-2.154 2.967v5.7h-3v-10h2.881v1.367h.041c.401-.761 1.381-1.563 2.841-1.563 3.039 0 3.6 2.001 3.6 4.601v5.595z" />
|
||||||
</svg>
|
</svg>
|
||||||
</motion.a>
|
</m.a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Bottom Bar */}
|
{/* Bottom Bar */}
|
||||||
<motion.div
|
<m.div
|
||||||
className="border-t border-[#e5e5e5] mt-6 md:mt-8 pt-6 md:pt-8 text-center text-sm font-renner relative z-10"
|
className="border-t border-[#e5e5e5] mt-6 md:mt-8 pt-6 md:pt-8 text-center text-sm font-renner relative z-10"
|
||||||
style={{
|
style={{
|
||||||
fontWeight: 300,
|
fontWeight: 300,
|
||||||
@ -335,7 +335,7 @@ export default function DesktopFooter() {
|
|||||||
<p className="text-xs md:text-sm">
|
<p className="text-xs md:text-sm">
|
||||||
© 2024 Mozimo. All rights reserved.
|
© 2024 Mozimo. All rights reserved.
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</footer>
|
</footer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { m, AnimatePresence, useScroll, useMotionValueEvent } from "framer-motion";
|
||||||
import { Image } from "@unpic/react";
|
import { Image } from "@unpic/react";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useLocation } from "@tanstack/react-router";
|
import { useLocation } from "@tanstack/react-router";
|
||||||
@ -8,15 +8,11 @@ export default function Header() {
|
|||||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||||
const pathname = useLocation({ select: (loc) => loc.pathname });
|
const pathname = useLocation({ select: (loc) => loc.pathname });
|
||||||
|
|
||||||
useEffect(() => {
|
const { scrollY } = useScroll();
|
||||||
const handleScroll = () => {
|
|
||||||
const scrollPosition = window.scrollY;
|
|
||||||
setIsScrolled(scrollPosition > 100);
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener("scroll", handleScroll);
|
useMotionValueEvent(scrollY, "change", (latest: number) => {
|
||||||
return () => window.removeEventListener("scroll", handleScroll);
|
setIsScrolled(latest > 100);
|
||||||
}, []);
|
});
|
||||||
|
|
||||||
// Close mobile menu when clicking outside
|
// Close mobile menu when clicking outside
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -59,7 +55,7 @@ export default function Header() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Mobile Header - Only visible on mobile */}
|
{/* Mobile Header - Only visible on mobile */}
|
||||||
<motion.header
|
<m.header
|
||||||
className="fixed top-0 z-[60] w-full md:hidden p-1 "
|
className="fixed top-0 z-[60] w-full md:hidden p-1 "
|
||||||
initial={false}
|
initial={false}
|
||||||
animate={{
|
animate={{
|
||||||
@ -78,7 +74,7 @@ export default function Header() {
|
|||||||
<nav className="relative bg-white border border-white/20 shadow-premium w-full h-full flex items-center px-4 rounded-[15px]">
|
<nav className="relative bg-white border border-white/20 shadow-premium w-full h-full flex items-center px-4 rounded-[15px]">
|
||||||
{/* Left: Hamburger Menu */}
|
{/* Left: Hamburger Menu */}
|
||||||
<div className="absolute left-4 top-1/2 -translate-y-1/2">
|
<div className="absolute left-4 top-1/2 -translate-y-1/2">
|
||||||
<motion.button
|
<m.button
|
||||||
className="hamburger-button p-2 text-gray-800 hover:text-[#8B4513] transition-all duration-300 relative min-w-[40px] min-h-[40px] flex items-center justify-center rounded-full hover:bg-white/20 backdrop-blur-sm"
|
className="hamburger-button p-2 text-gray-800 hover:text-[#8B4513] transition-all duration-300 relative min-w-[40px] min-h-[40px] flex items-center justify-center rounded-full hover:bg-white/20 backdrop-blur-sm"
|
||||||
whileHover={{ scale: 1.1 }}
|
whileHover={{ scale: 1.1 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
@ -86,20 +82,20 @@ export default function Header() {
|
|||||||
aria-label="Toggle mobile menu"
|
aria-label="Toggle mobile menu"
|
||||||
>
|
>
|
||||||
<div className="w-6 h-6 flex flex-col justify-center items-center">
|
<div className="w-6 h-6 flex flex-col justify-center items-center">
|
||||||
<motion.span
|
<m.span
|
||||||
className="w-6 h-0.5 bg-current block transition-all duration-300"
|
className="w-6 h-0.5 bg-current block transition-all duration-300"
|
||||||
animate={{
|
animate={{
|
||||||
rotate: isMobileMenuOpen ? 45 : 0,
|
rotate: isMobileMenuOpen ? 45 : 0,
|
||||||
y: isMobileMenuOpen ? 6 : 0,
|
y: isMobileMenuOpen ? 6 : 0,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<motion.span
|
<m.span
|
||||||
className="w-6 h-0.5 bg-current block mt-1 transition-all duration-300"
|
className="w-6 h-0.5 bg-current block mt-1 transition-all duration-300"
|
||||||
animate={{
|
animate={{
|
||||||
opacity: isMobileMenuOpen ? 0 : 1,
|
opacity: isMobileMenuOpen ? 0 : 1,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<motion.span
|
<m.span
|
||||||
className="w-6 h-0.5 bg-current block mt-1 transition-all duration-300"
|
className="w-6 h-0.5 bg-current block mt-1 transition-all duration-300"
|
||||||
animate={{
|
animate={{
|
||||||
rotate: isMobileMenuOpen ? -45 : 0,
|
rotate: isMobileMenuOpen ? -45 : 0,
|
||||||
@ -107,18 +103,18 @@ export default function Header() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</motion.button>
|
</m.button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Center: Logo */}
|
{/* Center: Logo */}
|
||||||
<div className="absolute left-1/2 transform -translate-x-1/2">
|
<div className="absolute left-1/2 transform -translate-x-1/2">
|
||||||
<motion.div
|
<m.div
|
||||||
className="flex items-center justify-center"
|
className="flex items-center justify-center"
|
||||||
initial={{ opacity: 0, y: -20 }}
|
initial={{ opacity: 0, y: -20 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.6 }}
|
transition={{ duration: 0.6 }}
|
||||||
>
|
>
|
||||||
<motion.div
|
<m.div
|
||||||
className="relative"
|
className="relative"
|
||||||
animate={{
|
animate={{
|
||||||
width: isScrolled ? 40 : 60, // shrink on scroll
|
width: isScrolled ? 40 : 60, // shrink on scroll
|
||||||
@ -137,13 +133,13 @@ export default function Header() {
|
|||||||
layout="fullWidth"
|
layout="fullWidth"
|
||||||
className="w-full h-full object-contain drop-shadow-lg"
|
className="w-full h-full object-contain drop-shadow-lg"
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right: Action Buttons */}
|
{/* Right: Action Buttons */}
|
||||||
<div className="absolute right-4 top-1/2 -translate-y-1/2 flex items-center gap-1">
|
<div className="absolute right-4 top-1/2 -translate-y-1/2 flex items-center gap-1">
|
||||||
<motion.button
|
<m.button
|
||||||
className="p-2"
|
className="p-2"
|
||||||
whileHover={{ scale: 1.05 }}
|
whileHover={{ scale: 1.05 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
@ -162,9 +158,9 @@ export default function Header() {
|
|||||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</motion.button>
|
</m.button>
|
||||||
|
|
||||||
<motion.button
|
<m.button
|
||||||
className="p-2"
|
className="p-2"
|
||||||
whileHover={{ scale: 1.05 }}
|
whileHover={{ scale: 1.05 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
@ -183,9 +179,9 @@ export default function Header() {
|
|||||||
d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"
|
d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</motion.button>
|
</m.button>
|
||||||
|
|
||||||
<motion.button
|
<m.button
|
||||||
className="p-2"
|
className="p-2"
|
||||||
whileHover={{ scale: 1.05 }}
|
whileHover={{ scale: 1.05 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
@ -204,13 +200,13 @@ export default function Header() {
|
|||||||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</motion.button>
|
</m.button>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</motion.header>
|
</m.header>
|
||||||
|
|
||||||
{/* Desktop Header - Only visible on desktop */}
|
{/* Desktop Header - Only visible on desktop */}
|
||||||
<motion.header
|
<m.header
|
||||||
className="fixed top-0 z-50 hidden md:block "
|
className="fixed top-0 z-50 hidden md:block "
|
||||||
initial={false}
|
initial={false}
|
||||||
animate={{
|
animate={{
|
||||||
@ -234,7 +230,7 @@ export default function Header() {
|
|||||||
<div className="flex justify-between items-center w-full px-20">
|
<div className="flex justify-between items-center w-full px-20">
|
||||||
{/* Left Navigation */}
|
{/* Left Navigation */}
|
||||||
<div className="flex items-center space-x-16">
|
<div className="flex items-center space-x-16">
|
||||||
<motion.a
|
<m.a
|
||||||
href={pathname === "/about" ? "/" : "/about"}
|
href={pathname === "/about" ? "/" : "/about"}
|
||||||
className="text-gray-800 hover:text-[#8B4513] transition-all duration-300 font-renner relative group"
|
className="text-gray-800 hover:text-[#8B4513] transition-all duration-300 font-renner relative group"
|
||||||
style={{
|
style={{
|
||||||
@ -248,8 +244,8 @@ export default function Header() {
|
|||||||
>
|
>
|
||||||
{pathname === "/about" ? "Home" : "About us"}
|
{pathname === "/about" ? "Home" : "About us"}
|
||||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-[#8B4513] to-[#DAA520] transition-all duration-300 group-hover:w-full"></span>
|
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-[#8B4513] to-[#DAA520] transition-all duration-300 group-hover:w-full"></span>
|
||||||
</motion.a>
|
</m.a>
|
||||||
<motion.a
|
<m.a
|
||||||
href="https://shop.mozimo.in/"
|
href="https://shop.mozimo.in/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
@ -265,11 +261,11 @@ export default function Header() {
|
|||||||
>
|
>
|
||||||
Shop
|
Shop
|
||||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-[#8B4513] to-[#DAA520] transition-all duration-300 group-hover:w-full"></span>
|
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-[#8B4513] to-[#DAA520] transition-all duration-300 group-hover:w-full"></span>
|
||||||
</motion.a>
|
</m.a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Center Logo */}
|
{/* Center Logo */}
|
||||||
<motion.div
|
<m.div
|
||||||
className="relative"
|
className="relative"
|
||||||
animate={{
|
animate={{
|
||||||
width: isScrolled ? 75 : 96, // shrink logo when scrolled
|
width: isScrolled ? 75 : 96, // shrink logo when scrolled
|
||||||
@ -289,12 +285,12 @@ export default function Header() {
|
|||||||
layout="fullWidth"
|
layout="fullWidth"
|
||||||
className="w-full h-full object-contain drop-shadow-lg"
|
className="w-full h-full object-contain drop-shadow-lg"
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Right Icons */}
|
{/* Right Icons */}
|
||||||
<div className="flex items-center space-x-8">
|
<div className="flex items-center space-x-8">
|
||||||
{/* More Dropdown */}
|
{/* More Dropdown */}
|
||||||
<motion.button
|
<m.button
|
||||||
className="flex items-center space-x-1 text-gray-800 hover:text-[#8B4513] transition-all duration-300 font-renner relative group"
|
className="flex items-center space-x-1 text-gray-800 hover:text-[#8B4513] transition-all duration-300 font-renner relative group"
|
||||||
style={{
|
style={{
|
||||||
fontWeight: 300,
|
fontWeight: 300,
|
||||||
@ -307,7 +303,7 @@ export default function Header() {
|
|||||||
aria-label="More options"
|
aria-label="More options"
|
||||||
>
|
>
|
||||||
<span>More</span>
|
<span>More</span>
|
||||||
<motion.svg
|
<m.svg
|
||||||
className="w-4 h-4"
|
className="w-4 h-4"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@ -322,10 +318,10 @@ export default function Header() {
|
|||||||
strokeWidth={2}
|
strokeWidth={2}
|
||||||
d="M19 9l-7 7-7-7"
|
d="M19 9l-7 7-7-7"
|
||||||
/>
|
/>
|
||||||
</motion.svg>
|
</m.svg>
|
||||||
</motion.button>
|
</m.button>
|
||||||
|
|
||||||
<motion.button
|
<m.button
|
||||||
className="p-3 text-gray-800 hover:text-[#8B4513] transition-all duration-300 relative min-w-[40px] min-h-[40px] flex items-center justify-center rounded-full hover:bg-white/20 backdrop-blur-sm"
|
className="p-3 text-gray-800 hover:text-[#8B4513] transition-all duration-300 relative min-w-[40px] min-h-[40px] flex items-center justify-center rounded-full hover:bg-white/20 backdrop-blur-sm"
|
||||||
whileHover={{ scale: 1.1, rotate: 5 }}
|
whileHover={{ scale: 1.1, rotate: 5 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
@ -344,8 +340,8 @@ export default function Header() {
|
|||||||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</motion.button>
|
</m.button>
|
||||||
<motion.button
|
<m.button
|
||||||
className="p-3 text-gray-800 hover:text-[#8B4513] transition-all duration-300 relative min-w-[40px] min-h-[40px] flex items-center justify-center rounded-full hover:bg-white/20 backdrop-blur-sm"
|
className="p-3 text-gray-800 hover:text-[#8B4513] transition-all duration-300 relative min-w-[40px] min-h-[40px] flex items-center justify-center rounded-full hover:bg-white/20 backdrop-blur-sm"
|
||||||
whileHover={{ scale: 1.1, rotate: -5 }}
|
whileHover={{ scale: 1.1, rotate: -5 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
@ -364,8 +360,8 @@ export default function Header() {
|
|||||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</motion.button>
|
</m.button>
|
||||||
<motion.button
|
<m.button
|
||||||
className="p-3 text-gray-800 hover:text-[#8B4513] transition-all duration-300 relative min-w-[40px] min-h-[40px] flex items-center justify-center rounded-full hover:bg-white/20 backdrop-blur-sm"
|
className="p-3 text-gray-800 hover:text-[#8B4513] transition-all duration-300 relative min-w-[40px] min-h-[40px] flex items-center justify-center rounded-full hover:bg-white/20 backdrop-blur-sm"
|
||||||
whileHover={{ scale: 1.1, y: -2 }}
|
whileHover={{ scale: 1.1, y: -2 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
@ -384,23 +380,23 @@ export default function Header() {
|
|||||||
d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"
|
d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</motion.button>
|
</m.button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</motion.header>
|
</m.header>
|
||||||
|
|
||||||
{/* Mobile Menu Overlay - Only visible on mobile */}
|
{/* Mobile Menu Overlay - Only visible on mobile */}
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{isMobileMenuOpen && (
|
{isMobileMenuOpen && (
|
||||||
<motion.div
|
<m.div
|
||||||
className="mobile-menu fixed inset-0 z-50 bg-black/50 backdrop-blur-sm md:hidden"
|
className="mobile-menu fixed inset-0 z-50 bg-black/50 backdrop-blur-sm md:hidden"
|
||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
exit={{ opacity: 0 }}
|
exit={{ opacity: 0 }}
|
||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
>
|
>
|
||||||
<motion.div
|
<m.div
|
||||||
className="absolute top-[72px] left-0 right-0 bg-white/95 backdrop-blur-md border-t border-white/20 shadow-premium"
|
className="absolute top-[72px] left-0 right-0 bg-white/95 backdrop-blur-md border-t border-white/20 shadow-premium"
|
||||||
initial={{ opacity: 0, y: -20 }}
|
initial={{ opacity: 0, y: -20 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
@ -410,7 +406,7 @@ export default function Header() {
|
|||||||
<div className="px-6 py-8 space-y-6">
|
<div className="px-6 py-8 space-y-6">
|
||||||
{/* Mobile Navigation Links */}
|
{/* Mobile Navigation Links */}
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<motion.a
|
<m.a
|
||||||
href={pathname === "/about" ? "/" : "/about"}
|
href={pathname === "/about" ? "/" : "/about"}
|
||||||
className="block text-lg font-renner text-gray-800 hover:text-[#8B4513] transition-all duration-300 py-3 border-b border-gray-100"
|
className="block text-lg font-renner text-gray-800 hover:text-[#8B4513] transition-all duration-300 py-3 border-b border-gray-100"
|
||||||
style={{
|
style={{
|
||||||
@ -424,8 +420,8 @@ export default function Header() {
|
|||||||
whileHover={{ x: 10 }}
|
whileHover={{ x: 10 }}
|
||||||
>
|
>
|
||||||
{pathname === "/about" ? "Home" : "About us"}
|
{pathname === "/about" ? "Home" : "About us"}
|
||||||
</motion.a>
|
</m.a>
|
||||||
<motion.a
|
<m.a
|
||||||
href="https://shop.mozimo.in/"
|
href="https://shop.mozimo.in/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
@ -441,8 +437,8 @@ export default function Header() {
|
|||||||
whileHover={{ x: 10 }}
|
whileHover={{ x: 10 }}
|
||||||
>
|
>
|
||||||
Shop
|
Shop
|
||||||
</motion.a>
|
</m.a>
|
||||||
<motion.a
|
<m.a
|
||||||
href="#categories"
|
href="#categories"
|
||||||
className="block text-lg font-renner text-gray-800 hover:text-[#8B4513] transition-all duration-300 py-3 border-b border-gray-100"
|
className="block text-lg font-renner text-gray-800 hover:text-[#8B4513] transition-all duration-300 py-3 border-b border-gray-100"
|
||||||
style={{
|
style={{
|
||||||
@ -456,11 +452,11 @@ export default function Header() {
|
|||||||
whileHover={{ x: 10 }}
|
whileHover={{ x: 10 }}
|
||||||
>
|
>
|
||||||
Categories
|
Categories
|
||||||
</motion.a>
|
</m.a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
)}
|
)}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { motion } from "framer-motion";
|
import { m } from "framer-motion";
|
||||||
import { Image } from "@unpic/react";
|
import { Image } from "@unpic/react";
|
||||||
|
|
||||||
export default function MobileFooter() {
|
export default function MobileFooter() {
|
||||||
@ -11,7 +11,7 @@ export default function MobileFooter() {
|
|||||||
|
|
||||||
<div className="px-4 py-8 flex flex-col gap-8 relative z-10">
|
<div className="px-4 py-8 flex flex-col gap-8 relative z-10">
|
||||||
{/* Logo at top */}
|
{/* Logo at top */}
|
||||||
<motion.div
|
<m.div
|
||||||
className="flex"
|
className="flex"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
@ -26,12 +26,12 @@ export default function MobileFooter() {
|
|||||||
height={80}
|
height={80}
|
||||||
layout="fixed"
|
layout="fixed"
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Two column layout */}
|
{/* Two column layout */}
|
||||||
<div className="grid grid-cols-2 gap-6">
|
<div className="grid grid-cols-2 gap-6">
|
||||||
{/* Left Column - Contact Info */}
|
{/* Left Column - Contact Info */}
|
||||||
<motion.div
|
<m.div
|
||||||
className="space-y-4"
|
className="space-y-4"
|
||||||
initial={{ opacity: 0, x: -10 }}
|
initial={{ opacity: 0, x: -10 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
@ -60,7 +60,7 @@ export default function MobileFooter() {
|
|||||||
fontFamily: "Renner*",
|
fontFamily: "Renner*",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<motion.div
|
<m.div
|
||||||
className="flex items-center space-x-2"
|
className="flex items-center space-x-2"
|
||||||
initial={{ opacity: 0, x: -10 }}
|
initial={{ opacity: 0, x: -10 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
@ -76,8 +76,8 @@ export default function MobileFooter() {
|
|||||||
<path d="M2 3a1 1 0 011-1h2.153a1 1 0 01.986.836l.74 4.435a1 1 0 01-.54 1.06l-1.548.773a11.037 11.037 0 006.105 6.105l.774-1.548a1 1 0 011.059-.54l4.435.74a1 1 0 01.836.986V17a1 1 0 01-1 1h-2C7.82 18 2 12.18 2 5V3z" />
|
<path d="M2 3a1 1 0 011-1h2.153a1 1 0 01.986.836l.74 4.435a1 1 0 01-.54 1.06l-1.548.773a11.037 11.037 0 006.105 6.105l.774-1.548a1 1 0 011.059-.54l4.435.74a1 1 0 01.836.986V17a1 1 0 01-1 1h-2C7.82 18 2 12.18 2 5V3z" />
|
||||||
</svg>
|
</svg>
|
||||||
<span className="text-xs md:text-sm">0172-4045414</span>
|
<span className="text-xs md:text-sm">0172-4045414</span>
|
||||||
</motion.div>
|
</m.div>
|
||||||
<motion.div
|
<m.div
|
||||||
className="flex items-start space-x-2"
|
className="flex items-start space-x-2"
|
||||||
initial={{ opacity: 0, x: -10 }}
|
initial={{ opacity: 0, x: -10 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
@ -99,7 +99,7 @@ export default function MobileFooter() {
|
|||||||
<span className="text-xs md:text-sm">
|
<span className="text-xs md:text-sm">
|
||||||
SCO 8, Inner Market, 9-D, Sector 9, Chandigarh, 160009
|
SCO 8, Inner Market, 9-D, Sector 9, Chandigarh, 160009
|
||||||
</span>
|
</span>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Find Us On */}
|
{/* Find Us On */}
|
||||||
@ -118,7 +118,7 @@ export default function MobileFooter() {
|
|||||||
</h3>
|
</h3>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
{/* Social icons with original animations */}
|
{/* Social icons with original animations */}
|
||||||
<motion.a
|
<m.a
|
||||||
href="https://www.facebook.com/share/16vPmvcQV7/?mibextid=wwXIfr"
|
href="https://www.facebook.com/share/16vPmvcQV7/?mibextid=wwXIfr"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
@ -138,8 +138,8 @@ export default function MobileFooter() {
|
|||||||
>
|
>
|
||||||
<path d="M22.675 0h-21.35C.595 0 0 .592 0 1.326v21.348C0 23.408.595 24 1.325 24h11.495v-9.294H9.692v-3.622h3.128V8.413c0-3.1 1.893-4.788 4.659-4.788 1.325 0 2.463.099 2.797.143v3.24l-1.918.001c-1.504 0-1.797.715-1.797 1.763v2.313h3.587l-.467 3.622h-3.12V24h6.116C23.406 24 24 23.408 24 22.674V1.326C24 .592 23.406 0 22.675 0" />
|
<path d="M22.675 0h-21.35C.595 0 0 .592 0 1.326v21.348C0 23.408.595 24 1.325 24h11.495v-9.294H9.692v-3.622h3.128V8.413c0-3.1 1.893-4.788 4.659-4.788 1.325 0 2.463.099 2.797.143v3.24l-1.918.001c-1.504 0-1.797.715-1.797 1.763v2.313h3.587l-.467 3.622h-3.12V24h6.116C23.406 24 24 23.408 24 22.674V1.326C24 .592 23.406 0 22.675 0" />
|
||||||
</svg>
|
</svg>
|
||||||
</motion.a>
|
</m.a>
|
||||||
<motion.a
|
<m.a
|
||||||
href="https://www.instagram.com/mozimo.choc?igsh=bTVzbGo0enV3b3Jn"
|
href="https://www.instagram.com/mozimo.choc?igsh=bTVzbGo0enV3b3Jn"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
@ -159,8 +159,8 @@ export default function MobileFooter() {
|
|||||||
>
|
>
|
||||||
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 1.366.062 2.633.334 3.608 1.308.974.974 1.246 2.241 1.308 3.608.058 1.266.069 1.646.069 4.85s-.012 3.584-.07 4.85c-.062 1.366-.334 2.633-1.308 3.608-.974.974-2.241 1.246-3.608 1.308-1.266.058-1.646.069-4.85.069s-3.584-.012-4.85-.07c-1.366-.062-2.633-.334-3.608-1.308-.974-.974-1.246-2.241-1.308-3.608C2.175 15.647 2.163 15.267 2.163 12s.012-3.584.07-4.85c.062-1.366.334-2.633 1.308-3.608C4.515 2.567 5.782 2.295 7.148 2.233 8.414 2.175 8.794 2.163 12 2.163zm0-2.163C8.741 0 8.332.012 7.052.07 5.771.128 4.659.334 3.678 1.315c-.98.98-1.187 2.092-1.245 3.373C2.012 5.668 2 6.077 2 12c0 5.923.012 6.332.07 7.612.058 1.281.265 2.393 1.245 3.373.98.98 2.092 1.187 3.373 1.245C8.332 23.988 8.741 24 12 24s3.668-.012 4.948-.07c1.281-.058 2.393-.265 3.373-1.245.98-.98 1.187-2.092 1.245-3.373.058-1.28.07-1.689.07-7.612 0-5.923-.012-6.332-.07-7.612-.058-1.281-.265-2.393-1.245-3.373-.98-.98-2.092-1.187-3.373-1.245C15.668.012 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zm0 10.162a3.999 3.999 0 1 1 0-7.998 3.999 3.999 0 0 1 0 7.998zm6.406-11.845a1.44 1.44 0 1 0 0 2.88 1.44 1.44 0 0 0 0-2.88z" />
|
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 1.366.062 2.633.334 3.608 1.308.974.974 1.246 2.241 1.308 3.608.058 1.266.069 1.646.069 4.85s-.012 3.584-.07 4.85c-.062 1.366-.334 2.633-1.308 3.608-.974.974-2.241 1.246-3.608 1.308-1.266.058-1.646.069-4.85.069s-3.584-.012-4.85-.07c-1.366-.062-2.633-.334-3.608-1.308-.974-.974-1.246-2.241-1.308-3.608C2.175 15.647 2.163 15.267 2.163 12s.012-3.584.07-4.85c.062-1.366.334-2.633 1.308-3.608C4.515 2.567 5.782 2.295 7.148 2.233 8.414 2.175 8.794 2.163 12 2.163zm0-2.163C8.741 0 8.332.012 7.052.07 5.771.128 4.659.334 3.678 1.315c-.98.98-1.187 2.092-1.245 3.373C2.012 5.668 2 6.077 2 12c0 5.923.012 6.332.07 7.612.058 1.281.265 2.393 1.245 3.373.98.98 2.092 1.187 3.373 1.245C8.332 23.988 8.741 24 12 24s3.668-.012 4.948-.07c1.281-.058 2.393-.265 3.373-1.245.98-.98 1.187-2.092 1.245-3.373.058-1.28.07-1.689.07-7.612 0-5.923-.012-6.332-.07-7.612-.058-1.281-.265-2.393-1.245-3.373-.98-.98-2.092-1.187-3.373-1.245C15.668.012 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zm0 10.162a3.999 3.999 0 1 1 0-7.998 3.999 3.999 0 0 1 0 7.998zm6.406-11.845a1.44 1.44 0 1 0 0 2.88 1.44 1.44 0 0 0 0-2.88z" />
|
||||||
</svg>
|
</svg>
|
||||||
</motion.a>
|
</m.a>
|
||||||
<motion.a
|
<m.a
|
||||||
href="https://www.youtube.com/@MozimoChocolates"
|
href="https://www.youtube.com/@MozimoChocolates"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
@ -180,8 +180,8 @@ export default function MobileFooter() {
|
|||||||
>
|
>
|
||||||
<path d="M23.498 6.186a2.994 2.994 0 0 0-2.107-2.117C19.163 3.5 12 3.5 12 3.5s-7.163 0-9.391.569A2.994 2.994 0 0 0 .502 6.186C0 8.413 0 12 0 12s0 3.587.502 5.814a2.994 2.994 0 0 0 2.107 2.117C4.837 20.5 12 20.5 12 20.5s7.163 0 9.391-.569a2.994 2.994 0 0 0 2.107-2.117C24 15.587 24 12 24 12s0-3.587-.502-5.814zM9.545 15.568V8.432l6.545 3.568-6.545 3.568z" />
|
<path d="M23.498 6.186a2.994 2.994 0 0 0-2.107-2.117C19.163 3.5 12 3.5 12 3.5s-7.163 0-9.391.569A2.994 2.994 0 0 0 .502 6.186C0 8.413 0 12 0 12s0 3.587.502 5.814a2.994 2.994 0 0 0 2.107 2.117C4.837 20.5 12 20.5 12 20.5s7.163 0 9.391-.569a2.994 2.994 0 0 0 2.107-2.117C24 15.587 24 12 24 12s0-3.587-.502-5.814zM9.545 15.568V8.432l6.545 3.568-6.545 3.568z" />
|
||||||
</svg>
|
</svg>
|
||||||
</motion.a>
|
</m.a>
|
||||||
<motion.a
|
<m.a
|
||||||
href="https://www.linkedin.com/company/mozimochocolates/"
|
href="https://www.linkedin.com/company/mozimochocolates/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
@ -201,14 +201,14 @@ export default function MobileFooter() {
|
|||||||
>
|
>
|
||||||
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.761 0 5-2.239 5-5v-14c0-2.761-2.239-5-5-5zm-11 19h-3v-10h3v10zm-1.5-11.268c-.966 0-1.75-.784-1.75-1.75s.784-1.75 1.75-1.75 1.75.784 1.75 1.75-.784 1.75-1.75 1.75zm15.5 11.268h-3v-5.604c0-1.337-.025-3.063-1.868-3.063-1.868 0-2.154 1.459-2.154 2.967v5.7h-3v-10h2.881v1.367h.041c.401-.761 1.381-1.563 2.841-1.563 3.039 0 3.6 2.001 3.6 4.601v5.595z" />
|
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.761 0 5-2.239 5-5v-14c0-2.761-2.239-5-5-5zm-11 19h-3v-10h3v10zm-1.5-11.268c-.966 0-1.75-.784-1.75-1.75s.784-1.75 1.75-1.75 1.75.784 1.75 1.75-.784 1.75-1.75 1.75zm15.5 11.268h-3v-5.604c0-1.337-.025-3.063-1.868-3.063-1.868 0-2.154 1.459-2.154 2.967v5.7h-3v-10h2.881v1.367h.041c.401-.761 1.381-1.563 2.841-1.563 3.039 0 3.6 2.001 3.6 4.601v5.595z" />
|
||||||
</svg>
|
</svg>
|
||||||
</motion.a>
|
</m.a>
|
||||||
{/* Other social icons... */}
|
{/* Other social icons... */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Right Column - Know more and other links */}
|
{/* Right Column - Know more and other links */}
|
||||||
<motion.div
|
<m.div
|
||||||
className="space-y-4"
|
className="space-y-4"
|
||||||
initial={{ opacity: 0, x: 10 }}
|
initial={{ opacity: 0, x: 10 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
@ -247,7 +247,7 @@ export default function MobileFooter() {
|
|||||||
"Locate our store",
|
"Locate our store",
|
||||||
"Bulk Ordering",
|
"Bulk Ordering",
|
||||||
].map((link, index) => (
|
].map((link, index) => (
|
||||||
<motion.li
|
<m.li
|
||||||
key={link}
|
key={link}
|
||||||
initial={{ opacity: 0, x: -10 }}
|
initial={{ opacity: 0, x: -10 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
@ -261,15 +261,15 @@ export default function MobileFooter() {
|
|||||||
{link}
|
{link}
|
||||||
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-[#8B4513] to-[#DAA520] transition-all duration-300 group-hover:w-full"></span>
|
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-[#8B4513] to-[#DAA520] transition-all duration-300 group-hover:w-full"></span>
|
||||||
</a>
|
</a>
|
||||||
</motion.li>
|
</m.li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Copyright - original styling preserved */}
|
{/* Copyright - original styling preserved */}
|
||||||
<motion.div
|
<m.div
|
||||||
className="border-t border-[#e5e5e5] mt-6 md:mt-8 pt-6 md:pt-8 text-center text-sm font-renner relative z-10"
|
className="border-t border-[#e5e5e5] mt-6 md:mt-8 pt-6 md:pt-8 text-center text-sm font-renner relative z-10"
|
||||||
style={{
|
style={{
|
||||||
fontWeight: 300,
|
fontWeight: 300,
|
||||||
@ -286,7 +286,7 @@ export default function MobileFooter() {
|
|||||||
<p className="text-xs md:text-sm">
|
<p className="text-xs md:text-sm">
|
||||||
© 2024 Mozimo. All rights reserved.
|
© 2024 Mozimo. All rights reserved.
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { useState, useCallback, useMemo, useEffect } from "react";
|
import { useState, useCallback, useMemo, useEffect } from "react";
|
||||||
import { LazyMotion, domAnimation, m } from "framer-motion";
|
import { m } from "framer-motion";
|
||||||
import Section from "@/components/Section";
|
import Section from "@/components/Section";
|
||||||
import { Image } from "@unpic/react";
|
import { Image } from "@unpic/react";
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ import { Image } from "@unpic/react";
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Section background="white" id="categories">
|
<Section background="white" id="categories">
|
||||||
<LazyMotion features={domAnimation}>
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-0 items-stretch min-h-[400px] md:min-h-[500px]">
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-0 items-stretch min-h-[400px] md:min-h-[500px]">
|
||||||
{/* Left */}
|
{/* Left */}
|
||||||
<div className="flex flex-col justify-center h-full bg-white px-4 md:px-8 py-6 md:py-12 order-2 lg:order-1">
|
<div className="flex flex-col justify-center h-full bg-white px-4 md:px-8 py-6 md:py-12 order-2 lg:order-1">
|
||||||
@ -123,7 +123,7 @@ import { Image } from "@unpic/react";
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</LazyMotion>
|
|
||||||
</Section>
|
</Section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { motion } from 'framer-motion';
|
import { m } from 'framer-motion';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
interface SectionProps {
|
interface SectionProps {
|
||||||
@ -35,7 +35,7 @@ export default function Section({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section id={id} className={classes}>
|
<section id={id} className={classes}>
|
||||||
<motion.div
|
<m.div
|
||||||
initial={{ opacity: 0, y: 60 }}
|
initial={{ opacity: 0, y: 60 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
transition={{
|
transition={{
|
||||||
@ -50,7 +50,7 @@ export default function Section({
|
|||||||
<div className="absolute top-0 left-1/2 transform -translate-x-1/2 w-16 md:w-24 h-1 bg-gradient-to-r from-transparent via-[#8B4513]/30 to-transparent opacity-0 hover:opacity-100 transition-opacity duration-500" />
|
<div className="absolute top-0 left-1/2 transform -translate-x-1/2 w-16 md:w-24 h-1 bg-gradient-to-r from-transparent via-[#8B4513]/30 to-transparent opacity-0 hover:opacity-100 transition-opacity duration-500" />
|
||||||
|
|
||||||
{children}
|
{children}
|
||||||
</motion.div>
|
</m.div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { motion } from "framer-motion";
|
import { m } from "framer-motion";
|
||||||
import { Image } from "@unpic/react";
|
import { Image } from "@unpic/react";
|
||||||
import Section from "./Section";
|
import Section from "./Section";
|
||||||
import { useInstagram } from "@/hooks/useInstagram";
|
import { useInstagram } from "@/hooks/useInstagram";
|
||||||
@ -60,7 +60,7 @@ export default function SocialMedia() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Section background="cream" padding="md">
|
<Section background="cream" padding="md">
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
@ -79,7 +79,7 @@ export default function SocialMedia() {
|
|||||||
>
|
>
|
||||||
Follow us on Instagram
|
Follow us on Instagram
|
||||||
</h2>
|
</h2>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
ref={scrollRef}
|
ref={scrollRef}
|
||||||
@ -88,7 +88,7 @@ export default function SocialMedia() {
|
|||||||
{loading ? (
|
{loading ? (
|
||||||
<>
|
<>
|
||||||
{[1, 2, 3].map((i) => (
|
{[1, 2, 3].map((i) => (
|
||||||
<motion.div
|
<m.div
|
||||||
key={i}
|
key={i}
|
||||||
className="bg-white rounded-lg shadow-premium h-64 md:h-96 skeleton snap-start w-[calc(80vw-1rem)] flex-shrink-0 sm:w-auto"
|
className="bg-white rounded-lg shadow-premium h-64 md:h-96 skeleton snap-start w-[calc(80vw-1rem)] flex-shrink-0 sm:w-auto"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
@ -101,7 +101,7 @@ export default function SocialMedia() {
|
|||||||
) : error ? (
|
) : error ? (
|
||||||
isTokenExpired ? (
|
isTokenExpired ? (
|
||||||
<div className="col-span-full text-center py-12 sm:col-span-2 lg:col-span-3">
|
<div className="col-span-full text-center py-12 sm:col-span-2 lg:col-span-3">
|
||||||
<motion.div
|
<m.div
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.6 }}
|
transition={{ duration: 0.6 }}
|
||||||
@ -121,12 +121,12 @@ export default function SocialMedia() {
|
|||||||
<div className="text-sm text-gray-500">
|
<div className="text-sm text-gray-500">
|
||||||
In the meantime, follow us @mozimo_chocolate
|
In the meantime, follow us @mozimo_chocolate
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{/* Left Block - Chocolate Spread Jar */}
|
{/* Left Block - Chocolate Spread Jar */}
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
@ -135,7 +135,7 @@ export default function SocialMedia() {
|
|||||||
whileHover={{ scale: 1.02 }}
|
whileHover={{ scale: 1.02 }}
|
||||||
>
|
>
|
||||||
<div className="relative h-64 md:h-96 bg-gradient-to-br from-amber-50 to-orange-50 flex items-center justify-center">
|
<div className="relative h-64 md:h-96 bg-gradient-to-br from-amber-50 to-orange-50 flex items-center justify-center">
|
||||||
<motion.div
|
<m.div
|
||||||
className="text-center"
|
className="text-center"
|
||||||
whileHover={{ scale: 1.05 }}
|
whileHover={{ scale: 1.05 }}
|
||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
@ -151,12 +151,12 @@ export default function SocialMedia() {
|
|||||||
SINGLE ORIGIN HAZELNUT SPREAD 45%
|
SINGLE ORIGIN HAZELNUT SPREAD 45%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Middle Block - Magazine Article */}
|
{/* Middle Block - Magazine Article */}
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
@ -191,10 +191,10 @@ export default function SocialMedia() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
|
|
||||||
{/* Right Block - World Chocolate Day */}
|
{/* Right Block - World Chocolate Day */}
|
||||||
<motion.div
|
<m.div
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
viewport={{ once: true, margin: "-50px" }}
|
viewport={{ once: true, margin: "-50px" }}
|
||||||
@ -218,12 +218,12 @@ export default function SocialMedia() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</m.div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
posts?.slice(0, 3).map((post, index) => (
|
posts?.slice(0, 3).map((post, index) => (
|
||||||
<motion.div
|
<m.div
|
||||||
key={post.id}
|
key={post.id}
|
||||||
initial="initial"
|
initial="initial"
|
||||||
whileInView="animate"
|
whileInView="animate"
|
||||||
@ -273,7 +273,7 @@ export default function SocialMedia() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</motion.div>
|
</m.div>
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
@ -13,15 +13,10 @@
|
|||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"plugins": [
|
|
||||||
{
|
|
||||||
"name": "next"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
"include": ["**/*.ts", "**/*.tsx"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user