Compare commits
No commits in common. "24c3f71a5b744a589635335fa28cf9d950fcafb1" and "86daacd45250f5a05df32259084015837dcdb2dd" have entirely different histories.
24c3f71a5b
...
86daacd452
58
.drone.yml
58
.drone.yml
|
|
@ -1,58 +0,0 @@
|
|||
kind: pipeline
|
||||
name: Build Image
|
||||
|
||||
clone:
|
||||
depth: 1
|
||||
|
||||
steps:
|
||||
- name: Lint Check
|
||||
image: node:22-alpine
|
||||
commands:
|
||||
# Enable Corepack and prepare Yarn 4
|
||||
- corepack enable
|
||||
- corepack prepare yarn@4.9.2 --activate
|
||||
|
||||
# Install dependencies with Yarn 4
|
||||
- yarn install --immutable
|
||||
- yarn lint
|
||||
|
||||
- name: Build Docker Image
|
||||
image: plugins/docker
|
||||
settings:
|
||||
build_args: 'API_BASE_URL=https://TheKalawati.com/api'
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
repo: git.TheKalawati.com/midastix/TheKalawati
|
||||
registry: git.TheKalawati.com
|
||||
when:
|
||||
branch:
|
||||
- main
|
||||
event:
|
||||
- push
|
||||
|
||||
- name: Deploy image
|
||||
image: appleboy/drone-ssh
|
||||
settings:
|
||||
host: midastix.com
|
||||
username: TheKalawati
|
||||
key:
|
||||
from_secret: server_ssh_pkey
|
||||
port: 22
|
||||
command_timeout: 3m
|
||||
script:
|
||||
- echo "Deploying image"
|
||||
- sudo /opt/deployable/Navigo_website/docker/deploy.sh
|
||||
- echo "Completed Deployment"
|
||||
when:
|
||||
branch:
|
||||
- main
|
||||
event:
|
||||
- push
|
||||
# trigger:
|
||||
# branch:
|
||||
# - main
|
||||
# - feature/env_api_url
|
||||
# event:
|
||||
# - push
|
||||
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
nodeLinker: node-modules
|
||||
47
Dockerfile
47
Dockerfile
|
|
@ -1,47 +0,0 @@
|
|||
# ------------------------
|
||||
# Build stage
|
||||
# ------------------------
|
||||
FROM node:22-bullseye AS builder
|
||||
|
||||
ARG API_BASE_URL="https://navigolabs.com/api"
|
||||
|
||||
# Enable Corepack and Yarn 4
|
||||
RUN corepack enable && corepack prepare yarn@4.9.2 --activate
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy Yarn 4 files
|
||||
COPY package.json yarn.lock .yarnrc.yml ./
|
||||
COPY .yarn .yarn
|
||||
|
||||
# Install dependencies (immutable to match lockfile)
|
||||
RUN yarn install --immutable
|
||||
|
||||
# Copy all source files
|
||||
COPY . .
|
||||
|
||||
# Pass API URL to Vite
|
||||
ENV VITE_API_BASE_URL=$API_BASE_URL
|
||||
|
||||
# Build the app
|
||||
RUN yarn build
|
||||
|
||||
|
||||
# ------------------------
|
||||
# Production stage
|
||||
# ------------------------
|
||||
FROM node:22-alpine AS production
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy built files from builder stage
|
||||
COPY --from=builder /app/dist ./dist
|
||||
|
||||
# Install a lightweight static server
|
||||
RUN npm install -g serve@14
|
||||
|
||||
# Expose port (optional but recommended)
|
||||
EXPOSE 3000
|
||||
|
||||
# Start the static server
|
||||
CMD ["serve", "-s", "dist", "-l", "3000"]
|
||||
|
|
@ -10,13 +10,8 @@
|
|||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
"@mui/icons-material": "^7.3.2",
|
||||
"@mui/material": "^7.3.2",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-intersection-observer": "^9.16.0"
|
||||
"react-dom": "^19.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.33.0",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#root {
|
||||
width: 100vw;
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
/* padding: 2rem; */
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
|
@ -11,11 +11,9 @@
|
|||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
}
|
||||
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
|
||||
.logo.react:hover {
|
||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
||||
}
|
||||
|
|
@ -24,7 +22,6 @@
|
|||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
|
|
@ -42,4 +39,4 @@
|
|||
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
33
src/App.tsx
33
src/App.tsx
|
|
@ -1,18 +1,35 @@
|
|||
import { useState } from 'react'
|
||||
// import reactLogo from './assets/react.svg'
|
||||
// import viteLogo from '/vite.svg'
|
||||
import reactLogo from './assets/react.svg'
|
||||
import viteLogo from '/vite.svg'
|
||||
import './App.css'
|
||||
// import VintageComingSoon from './comingsoon/comingsoon'
|
||||
import VintageComingSoonPage from './comingsoon/comingsoon'
|
||||
|
||||
function App() {
|
||||
const [count, setCount] = useState(0)
|
||||
|
||||
return (
|
||||
|
||||
<VintageComingSoonPage />
|
||||
|
||||
);
|
||||
<>
|
||||
<div>
|
||||
<a href="https://vite.dev" target="_blank">
|
||||
<img src={viteLogo} className="logo" alt="Vite logo" />
|
||||
</a>
|
||||
<a href="https://react.dev" target="_blank">
|
||||
<img src={reactLogo} className="logo react" alt="React logo" />
|
||||
</a>
|
||||
</div>
|
||||
<h1>Vite + React</h1>
|
||||
<div className="card">
|
||||
<button onClick={() => setCount((count) => count + 1)}>
|
||||
count is {count}
|
||||
</button>
|
||||
<p>
|
||||
Edit <code>src/App.tsx</code> and save to test HMR
|
||||
</p>
|
||||
</div>
|
||||
<p className="read-the-docs">
|
||||
Click on the Vite and React logos to learn more
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
|
|
|
|||
|
|
@ -1,891 +0,0 @@
|
|||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { Box, Typography, Button, Container, IconButton, Grid } from '@mui/material';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import InstagramIcon from '@mui/icons-material/Instagram';
|
||||
import FacebookIcon from '@mui/icons-material/Facebook';
|
||||
import TwitterIcon from '@mui/icons-material/Twitter';
|
||||
import EmailIcon from '@mui/icons-material/Email';
|
||||
import { keyframes } from '@emotion/react';
|
||||
import { styled } from '@mui/system';
|
||||
|
||||
// Color palette inspired by Indian heritage
|
||||
const colors = {
|
||||
paper: '#F5F5EF', // Aged paper
|
||||
ink: '#1A2526', // Deep charcoal
|
||||
accent: '#D4A017', // Saffron gold
|
||||
secondary: '#7B4F3A', // Terracotta
|
||||
highlight: '#FFF4CC', // Light sandalwood
|
||||
border: '#B89A6E', // Antique brass
|
||||
dark: '#3A1F0F', // Rich teak
|
||||
};
|
||||
|
||||
// Animations
|
||||
const fadeIn = keyframes`
|
||||
from { opacity: 0; transform: translateY(20px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
`;
|
||||
|
||||
const scaleIn = keyframes`
|
||||
from { transform: scale(0.8); opacity: 0; }
|
||||
to { transform: scale(1); opacity: 1; }
|
||||
`;
|
||||
|
||||
const rotateIn = keyframes`
|
||||
from { transform: rotate(5deg) scale(0.9); opacity: 0; }
|
||||
to { transform: rotate(0deg) scale(1); opacity: 1; }
|
||||
`;
|
||||
|
||||
const drawUnderline = keyframes`
|
||||
0% { width: 0; }
|
||||
100% { width: 100%; }
|
||||
`;
|
||||
|
||||
const vintagePulse = keyframes`
|
||||
0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(212, 160, 23, 0.4); }
|
||||
70% { transform: scale(1.02); box-shadow: 0 0 0 10px rgba(212, 160, 23, 0); }
|
||||
100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(212, 160, 23, 0); }
|
||||
`;
|
||||
|
||||
const float = keyframes`
|
||||
0% { transform: translateY(0px); }
|
||||
50% { transform: translateY(-10px); }
|
||||
100% { transform: translateY(0px); }
|
||||
`;
|
||||
|
||||
const scrollReveal = keyframes`
|
||||
from { opacity: 0; transform: translateY(50px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
`;
|
||||
|
||||
// Styled components
|
||||
const VintageBox = styled(Box)({
|
||||
position: 'relative',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: `url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z' fill='%233A1F0F' fill-opacity='0.05' fill-rule='evenodd'/%3E%3C/svg%3E")`,
|
||||
opacity: 0.15,
|
||||
zIndex: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const VintageButton = styled(Button)({
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
border: `1px solid ${colors.border}`,
|
||||
color: colors.ink,
|
||||
backgroundColor: colors.paper,
|
||||
fontWeight: 400,
|
||||
letterSpacing: '1px',
|
||||
textTransform: 'uppercase',
|
||||
padding: '12px 24px',
|
||||
borderRadius: '0',
|
||||
transition: 'all 0.3s ease',
|
||||
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
|
||||
'&:hover': {
|
||||
backgroundColor: colors.highlight,
|
||||
color: colors.dark,
|
||||
borderColor: colors.accent,
|
||||
transform: 'translateY(-2px)',
|
||||
boxShadow: '0 4px 8px rgba(0,0,0,0.2)',
|
||||
},
|
||||
'&::after': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '1px',
|
||||
backgroundColor: colors.accent,
|
||||
transform: 'scaleX(0)',
|
||||
transformOrigin: 'right',
|
||||
transition: 'transform 0.3s ease',
|
||||
},
|
||||
'&:hover::after': {
|
||||
transform: 'scaleX(1)',
|
||||
transformOrigin: 'left',
|
||||
},
|
||||
});
|
||||
|
||||
const VintagePulseButton = styled(VintageButton)({
|
||||
animation: `${vintagePulse} 2s infinite`,
|
||||
'&:hover': {
|
||||
animation: 'none',
|
||||
},
|
||||
});
|
||||
|
||||
const VintageUnderline = styled(Box)({
|
||||
position: 'relative',
|
||||
display: 'inline-block',
|
||||
'&::after': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
bottom: '-5px',
|
||||
left: 0,
|
||||
width: '0',
|
||||
height: '2px',
|
||||
backgroundColor: colors.accent,
|
||||
animation: `${drawUnderline} 1.5s forwards`,
|
||||
animationDelay: '0.5s',
|
||||
},
|
||||
});
|
||||
|
||||
const VintageImageFrame = styled(Box)({
|
||||
border: `12px solid ${colors.paper}`,
|
||||
boxShadow: `8px 8px 0 ${colors.secondary}80, 0 4px 8px rgba(0,0,0,0.1)`,
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: '-15px',
|
||||
left: '-15px',
|
||||
right: '-15px',
|
||||
bottom: '-15px',
|
||||
border: `1px solid ${colors.border}`,
|
||||
zIndex: -1,
|
||||
opacity: 0.7,
|
||||
},
|
||||
});
|
||||
|
||||
const AnimatedSection = styled(Box)({
|
||||
opacity: 0,
|
||||
transform: 'translateY(50px)',
|
||||
animation: `${scrollReveal} 1s forwards`,
|
||||
});
|
||||
|
||||
// Kalawati story sections with updated Pexels images
|
||||
const storyChapters = [
|
||||
{
|
||||
year: '2019',
|
||||
title: 'Where Curiosity Met Craft',
|
||||
content:
|
||||
'Fresh out of fashion school, I found myself drawn to looms, dye pits, and village homes. I organized workshops to listen, learn, and share space with artisans, forging a bond between design, community, and culture.',
|
||||
image: 'https://images.pexels.com/photos/28382914/pexels-photo-28382914.jpeg?auto=compress&cs=tinysrgb&w=500',
|
||||
},
|
||||
{
|
||||
year: '2020',
|
||||
title: 'A Name Was Born',
|
||||
content:
|
||||
'During the pandemic, I launched a campaign to highlight artisans hit by lockdowns. The Kalawati was born—named after women who hold culture in their palms and creativity in their hearts.',
|
||||
image: 'https://images.pexels.com/photos/31308739/pexels-photo-31308739.jpeg?auto=compress&cs=tinysrgb&w=500',
|
||||
},
|
||||
{
|
||||
year: '2021',
|
||||
title: 'Strengthening the Circle',
|
||||
content:
|
||||
'I spent the year mapping artisan strengths, connecting traditional skills to modern demand, and building trust for a long-term vision of community and craft.',
|
||||
image: 'https://images.pexels.com/photos/3772504/pexels-photo-3772504.jpeg?auto=compress&cs=tinysrgb&w=500',
|
||||
},
|
||||
{
|
||||
year: '2022',
|
||||
title: 'Systems That Serve People',
|
||||
content:
|
||||
'Through the JSW Foundation Fellowship, I built systems blending business and empathy—brand building for rural women, value chain development, and sustainable income pathways.',
|
||||
image: 'https://images.pexels.com/photos/163064/pexels-photo-163064.jpeg?auto=compress&cs=tinysrgb&w=500',
|
||||
},
|
||||
{
|
||||
year: '2023',
|
||||
title: 'Quiet Creation',
|
||||
content:
|
||||
'Working with artisan clusters, we prototyped collections with handloom, embroidery, and natural dyes—crafting stories you could wear.',
|
||||
image: 'https://images.pexels.com/photos/145939/pexels-photo-145939.jpeg?auto=compress&cs=tinysrgb&w=500',
|
||||
},
|
||||
{
|
||||
year: '2024',
|
||||
title: 'Kalawati Arrives',
|
||||
content:
|
||||
'The Kalawati opens its doors as a brand and movement, offering ethically made handcrafted apparel and decor. Join us to co-create, support heritage, and connect to roots.',
|
||||
image: 'https://images.pexels.com/photos/774859/pexels-photo-774859.jpeg?auto=compress&cs=tinysrgb&w=500',
|
||||
},
|
||||
];
|
||||
|
||||
// Process steps with updated Pexels images
|
||||
const processSteps = [
|
||||
{
|
||||
title: 'Design Inspiration',
|
||||
description: 'Drawing from traditional Indian motifs and contemporary aesthetics',
|
||||
image: 'https://images.pexels.com/photos/28382914/pexels-photo-28382914.jpeg?auto=compress&cs=tinysrgb&w=500',
|
||||
},
|
||||
{
|
||||
title: 'Material Selection',
|
||||
description: 'Choosing the finest natural fibers and dyes',
|
||||
image: 'https://images.pexels.com/photos/145939/pexels-photo-145939.jpeg?auto=compress&cs=tinysrgb&w=500',
|
||||
},
|
||||
{
|
||||
title: 'Artisan Crafting',
|
||||
description: 'Skilled hands weaving stories into fabric',
|
||||
image: 'https://images.pexels.com/photos/163064/pexels-photo-163064.jpeg?auto=compress&cs=tinysrgb&w=500',
|
||||
},
|
||||
{
|
||||
title: 'Quality Assurance',
|
||||
description: 'Meticulous inspection ensuring perfection',
|
||||
image: 'https://images.pexels.com/photos/3772504/pexels-photo-3772504.jpeg?auto=compress&cs=tinysrgb&w=500',
|
||||
},
|
||||
];
|
||||
|
||||
export const VintageComingSoonPage: React.FC = () => {
|
||||
const [days, setDays] = useState(10);
|
||||
const [hours, setHours] = useState(0);
|
||||
const [minutes, setMinutes] = useState(0);
|
||||
const [seconds, setSeconds] = useState(0);
|
||||
const [email, setEmail] = useState('');
|
||||
const [subscribed, setSubscribed] = useState(false);
|
||||
const [currentChapter, setCurrentChapter] = useState(0);
|
||||
const [scrollPosition, setScrollPosition] = useState(0);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Intersection Observer for scroll animations
|
||||
const [heroRef, heroInView] = useInView({ threshold: 0.1, triggerOnce: true });
|
||||
const [storyRef, storyInView] = useInView({ threshold: 0.1, triggerOnce: true });
|
||||
const [processRef, processInView] = useInView({ threshold: 0.1, triggerOnce: true });
|
||||
const [footerRef, footerInView] = useInView({ threshold: 0.1, triggerOnce: true });
|
||||
|
||||
// Countdown timer
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
const now = new Date();
|
||||
const launchDate = new Date();
|
||||
launchDate.setDate(now.getDate() + 10);
|
||||
launchDate.setHours(0, 0, 0, 0);
|
||||
|
||||
const diff = launchDate.getTime() - now.getTime();
|
||||
|
||||
setDays(Math.floor(diff / (1000 * 60 * 60 * 24)));
|
||||
setHours(Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)));
|
||||
setMinutes(Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)));
|
||||
setSeconds(Math.floor((diff % (1000 * 60)) / 1000));
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(timer);
|
||||
}, []);
|
||||
|
||||
// Rotate story chapters for main image
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setCurrentChapter((prev) => (prev + 1) % storyChapters.length);
|
||||
}, 8000);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
// Scroll position for parallax effects
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
const position = window.pageYOffset;
|
||||
setScrollPosition(position);
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', handleScroll, { passive: true });
|
||||
return () => {
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleSubscribe = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault();
|
||||
console.log('Subscribed with email:', email);
|
||||
setSubscribed(true);
|
||||
setEmail('');
|
||||
setTimeout(() => setSubscribed(false), 3000);
|
||||
};
|
||||
|
||||
return (
|
||||
<VintageBox sx={{ minHeight: '100vh', background: colors.paper, color: colors.ink, overflow: 'hidden', position: 'relative' }}>
|
||||
{/* Paper texture overlay */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundImage:
|
||||
'url("data:image/svg+xml,%3Csvg width=\'600\' height=\'600\' viewBox=\'0 0 600 600\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cfilter id=\'noiseFilter\'%3E%3CfeTurbulence type=\'fractalNoise\' baseFrequency=\'0.65\' numOctaves=\'3\' stitchTiles=\'stitch\'/%3E%3C/filter%3E%3Crect width=\'100%25\' height=\'100%25\' filter=\'url(%23noiseFilter)\' opacity=\'0.1\'/%3E%3C/svg%3E")',
|
||||
opacity: 0.3,
|
||||
zIndex: 0,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Parallax background elements */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'fixed',
|
||||
top: `${scrollPosition * 0.1}px`,
|
||||
right: '5%',
|
||||
width: '200px',
|
||||
height: '200px',
|
||||
backgroundImage: 'url(https://images.pexels.com/photos/28382914/pexels-photo-28382914.jpeg?auto=compress&cs=tinysrgb&w=500)',
|
||||
backgroundSize: 'cover',
|
||||
opacity: 0.1,
|
||||
zIndex: 0,
|
||||
transform: `rotate(${scrollPosition * 0.02}deg)`,
|
||||
transition: 'transform 0.3s ease-out',
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'fixed',
|
||||
top: `${400 + scrollPosition * 0.05}px`,
|
||||
left: '5%',
|
||||
width: '150px',
|
||||
height: '150px',
|
||||
backgroundImage: 'url(https://images.pexels.com/photos/145939/pexels-photo-145939.jpeg?auto=compress&cs=tinysrgb&w=500)',
|
||||
backgroundSize: 'cover',
|
||||
opacity: 0.1,
|
||||
zIndex: 0,
|
||||
transform: `rotate(${-scrollPosition * 0.03}deg)`,
|
||||
transition: 'transform 0.3s ease-out',
|
||||
}}
|
||||
/>
|
||||
|
||||
<Container maxWidth="lg" sx={{ position: 'relative', zIndex: 1, py: 6 }} ref={containerRef}>
|
||||
{/* Header */}
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderBottom: `1px solid ${colors.border}`, py: 4, mb: 4 }}>
|
||||
<AnimatedSection ref={heroRef} style={{ animationDelay: heroInView ? '0.1s' : '0s' }}>
|
||||
<Typography
|
||||
variant="h3"
|
||||
sx={{
|
||||
fontWeight: 300,
|
||||
color: colors.ink,
|
||||
letterSpacing: '3px',
|
||||
fontFamily: '"Playfair Display", serif',
|
||||
textTransform: 'uppercase',
|
||||
}}
|
||||
>
|
||||
<VintageUnderline>The Kalawati</VintageUnderline>
|
||||
</Typography>
|
||||
</AnimatedSection>
|
||||
<AnimatedSection ref={heroRef} style={{ animationDelay: heroInView ? '0.2s' : '0s' }}>
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
<IconButton
|
||||
href="https://instagram.com"
|
||||
target="_blank"
|
||||
sx={{ color: colors.secondary, '&:hover': { color: colors.accent, transform: 'scale(1.1)' }, transition: 'all 0.3s ease' }}
|
||||
>
|
||||
<InstagramIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
href="https://facebook.com"
|
||||
target="_blank"
|
||||
sx={{ color: colors.secondary, '&:hover': { color: colors.accent, transform: 'scale(1.1)' }, transition: 'all 0.3s ease' }}
|
||||
>
|
||||
<FacebookIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
href="https://twitter.com"
|
||||
target="_blank"
|
||||
sx={{ color: colors.secondary, '&:hover': { color: colors.accent, transform: 'scale(1.1)' }, transition: 'all 0.3s ease' }}
|
||||
>
|
||||
<TwitterIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</AnimatedSection>
|
||||
</Box>
|
||||
|
||||
{/* Hero Section with Rotating Image */}
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: { xs: 'column', md: 'row-reverse' },
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
py: 8,
|
||||
minHeight: '80vh',
|
||||
}}
|
||||
>
|
||||
<AnimatedSection
|
||||
ref={heroRef}
|
||||
style={{
|
||||
animationDelay: heroInView ? '0.3s' : '0s',
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<VintageImageFrame
|
||||
sx={{
|
||||
height: { xs: '400px', md: '550px' },
|
||||
background: colors.dark,
|
||||
backgroundImage: `url(${storyChapters[currentChapter].image})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
filter: 'sepia(0.2) contrast(1.05)',
|
||||
animation: `${scaleIn} 1.5s ease, ${float} 6s ease-in-out infinite`,
|
||||
transition: 'background-image 1.5s ease-in-out',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
background: `linear-gradient(to top, ${colors.dark}CC, transparent)`,
|
||||
color: colors.paper,
|
||||
p: 5,
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6" sx={{ fontWeight: 300, mb: 1, letterSpacing: '2px', fontFamily: '"Playfair Display", serif' }}>
|
||||
{storyChapters[currentChapter].year}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="h5"
|
||||
sx={{ fontWeight: 400, mb: 2, textTransform: 'uppercase', letterSpacing: '2px', fontFamily: '"Playfair Display", serif' }}
|
||||
>
|
||||
{storyChapters[currentChapter].title}
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{ opacity: 0.9, fontStyle: 'italic', fontFamily: '"Cormorant Garamond", serif', lineHeight: 1.6 }}>
|
||||
{storyChapters[currentChapter].content}
|
||||
</Typography>
|
||||
</Box>
|
||||
</VintageImageFrame>
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection
|
||||
ref={heroRef}
|
||||
style={{
|
||||
animationDelay: heroInView ? '0.4s' : '0s',
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="h1"
|
||||
sx={{
|
||||
fontWeight: 300,
|
||||
mb: 4,
|
||||
fontSize: { xs: '3rem', md: '4rem' },
|
||||
lineHeight: 1.2,
|
||||
color: colors.ink,
|
||||
fontFamily: '"Playfair Display", serif',
|
||||
}}
|
||||
>
|
||||
<span style={{ fontWeight: 400, color: colors.dark }}>A Journey</span> Woven with Stories, People & Purpose
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="h5"
|
||||
sx={{
|
||||
mb: 6,
|
||||
color: colors.secondary,
|
||||
fontWeight: 300,
|
||||
fontStyle: 'italic',
|
||||
fontFamily: '"Cormorant Garamond", serif',
|
||||
pl: 4,
|
||||
position: 'relative',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
height: '100%',
|
||||
width: '2px',
|
||||
background: colors.accent,
|
||||
},
|
||||
}}
|
||||
>
|
||||
Preserving Indian crafts, empowering artisans, and creating timeless pieces for the modern world.
|
||||
</Typography>
|
||||
|
||||
{/* Countdown Timer */}
|
||||
<Box sx={{ mb: 6 }}>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{
|
||||
mb: 4,
|
||||
fontWeight: 300,
|
||||
color: colors.secondary,
|
||||
letterSpacing: '2px',
|
||||
fontFamily: '"Cormorant Garamond", serif',
|
||||
textTransform: 'uppercase',
|
||||
}}
|
||||
>
|
||||
Collection Unveiling
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', gap: 3, flexWrap: 'wrap', justifyContent: { xs: 'center', md: 'flex-start' } }}>
|
||||
{[{ value: days, label: 'Days' }, { value: hours, label: 'Hours' }, { value: minutes, label: 'Minutes' }, { value: seconds, label: 'Seconds' }].map(
|
||||
(item, index) => (
|
||||
<Box
|
||||
key={item.label}
|
||||
sx={{
|
||||
background: colors.paper,
|
||||
borderRadius: '0',
|
||||
p: 3,
|
||||
minWidth: '90px',
|
||||
border: `1px solid ${colors.border}`,
|
||||
textAlign: 'center',
|
||||
boxShadow: '0 2px 4px rgba(0,0,0,0.05)',
|
||||
transition: 'all 0.3s ease',
|
||||
'&:hover': { transform: 'translateY(-2px)', boxShadow: '0 4px 8px rgba(0,0,0,0.1)' },
|
||||
animation: `${scaleIn} 1s ease`,
|
||||
animationDelay: `${index * 0.1}s`,
|
||||
}}
|
||||
>
|
||||
<Typography variant="h4" sx={{ fontWeight: 300, color: colors.ink, fontFamily: '"Playfair Display", serif' }}>
|
||||
{item.value}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{
|
||||
color: colors.secondary,
|
||||
letterSpacing: '1px',
|
||||
textTransform: 'uppercase',
|
||||
fontSize: '0.8rem',
|
||||
fontFamily: '"Cormorant Garamond", serif',
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
</Typography>
|
||||
</Box>
|
||||
)
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Email Subscription */}
|
||||
<Box>
|
||||
<Box sx={{ display: 'flex', gap: 3, mb: 3, flexDirection: { xs: 'column', sm: 'row' } }}>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder="Your email address"
|
||||
required
|
||||
style={{
|
||||
flex: 1,
|
||||
padding: '16px 24px',
|
||||
borderRadius: '0',
|
||||
border: `1px solid ${colors.border}`,
|
||||
fontSize: '16px',
|
||||
outline: 'none',
|
||||
background: colors.paper,
|
||||
color: colors.ink,
|
||||
fontFamily: '"Cormorant Garamond", serif',
|
||||
transition: 'all 0.3s ease',
|
||||
}}
|
||||
/>
|
||||
<VintagePulseButton
|
||||
onClick={handleSubscribe}
|
||||
variant="contained"
|
||||
sx={{
|
||||
px: 5,
|
||||
py: 2,
|
||||
fontWeight: 300,
|
||||
fontFamily: '"Cormorant Garamond", serif',
|
||||
letterSpacing: '2px',
|
||||
color: colors.ink,
|
||||
'&:hover': { background: colors.highlight },
|
||||
}}
|
||||
>
|
||||
Notify Me
|
||||
</VintagePulseButton>
|
||||
</Box>
|
||||
{subscribed && (
|
||||
<Typography
|
||||
sx={{
|
||||
color: colors.accent,
|
||||
fontWeight: 300,
|
||||
fontSize: '1rem',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 1,
|
||||
fontFamily: '"Cormorant Garamond", serif',
|
||||
animation: `${fadeIn} 0.5s ease`,
|
||||
}}
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.5 4L6 12L2.5 8.5" stroke={colors.accent} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
Thank you! We'll keep you informed.
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</AnimatedSection>
|
||||
</Box>
|
||||
|
||||
{/* Story Timeline */}
|
||||
<Box
|
||||
ref={storyRef}
|
||||
sx={{
|
||||
my: 10,
|
||||
py: 10,
|
||||
position: 'relative',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: '50%',
|
||||
transform: 'translateX(-50%)',
|
||||
width: '1px',
|
||||
height: '100%',
|
||||
background: colors.border,
|
||||
zIndex: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Container maxWidth="lg">
|
||||
<AnimatedSection style={{ animationDelay: storyInView ? '0.1s' : '0s' }}>
|
||||
<Typography
|
||||
variant="h3"
|
||||
sx={{
|
||||
mb: 8,
|
||||
fontWeight: 300,
|
||||
textAlign: 'center',
|
||||
color: colors.ink,
|
||||
fontFamily: '"Playfair Display", serif',
|
||||
position: 'relative',
|
||||
'&::after': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
bottom: '-15px',
|
||||
left: '50%',
|
||||
transform: 'translateX(-50%)',
|
||||
width: '150px',
|
||||
height: '1px',
|
||||
background: colors.accent,
|
||||
},
|
||||
}}
|
||||
>
|
||||
Our Story Woven in Time
|
||||
</Typography>
|
||||
</AnimatedSection>
|
||||
|
||||
<Grid container spacing={4}>
|
||||
{storyChapters.map((chapter, index) => (
|
||||
<Grid key={chapter.year}>
|
||||
<AnimatedSection
|
||||
style={{
|
||||
animationDelay: storyInView ? `${index * 0.2}s` : '0s',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: { xs: 'column', md: index % 2 === 0 ? 'row' : 'row-reverse' },
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
p: 4,
|
||||
borderRadius: '4px',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.05)',
|
||||
background: `${colors.paper}ee`,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
flex: 1,
|
||||
textAlign: { xs: 'center', md: index % 2 === 0 ? 'right' : 'left' },
|
||||
px: { xs: 2, md: 4 },
|
||||
}}
|
||||
>
|
||||
<Typography variant="h5" sx={{ fontWeight: 400, color: colors.dark, mb: 2, fontFamily: '"Playfair Display", serif' }}>
|
||||
{chapter.year}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="h4"
|
||||
sx={{
|
||||
fontWeight: 300,
|
||||
color: colors.ink,
|
||||
mb: 3,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: '1.5px',
|
||||
fontFamily: '"Playfair Display", serif',
|
||||
}}
|
||||
>
|
||||
{chapter.title}
|
||||
</Typography>
|
||||
<Typography variant="body1" sx={{ color: colors.secondary, fontFamily: '"Cormorant Garamond", serif', lineHeight: 1.8, fontSize: '1.1rem' }}>
|
||||
{chapter.content}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
flex: 1,
|
||||
position: 'relative',
|
||||
minHeight: '250px',
|
||||
width: '100%',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: { xs: '50%', md: index % 2 === 0 ? '100%' : 'auto' },
|
||||
right: { xs: 'auto', md: index % 2 === 0 ? 'auto' : '100%' },
|
||||
transform: 'translate(-50%, -50%)',
|
||||
width: '24px',
|
||||
height: '24px',
|
||||
borderRadius: '50%',
|
||||
background: colors.accent,
|
||||
border: `4px solid ${colors.paper}`,
|
||||
zIndex: 1,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<VintageImageFrame
|
||||
sx={{
|
||||
height: '250px',
|
||||
width: '100%',
|
||||
backgroundImage: `url(${chapter.image})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
filter: 'sepia(0.2) contrast(1.05)',
|
||||
animation: `${rotateIn} 1.2s ease`,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</AnimatedSection>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Container>
|
||||
</Box>
|
||||
|
||||
{/* Process Section */}
|
||||
<Box ref={processRef} sx={{ my: 10, py: 10, background: colors.highlight, position: 'relative', overflow: 'hidden' }}>
|
||||
<Container maxWidth="lg">
|
||||
<AnimatedSection style={{ animationDelay: processInView ? '0.1s' : '0s' }}>
|
||||
<Typography
|
||||
variant="h3"
|
||||
sx={{
|
||||
mb: 8,
|
||||
fontWeight: 300,
|
||||
textAlign: 'center',
|
||||
color: colors.dark,
|
||||
fontFamily: '"Playfair Display", serif',
|
||||
position: 'relative',
|
||||
'&::after': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
bottom: '-15px',
|
||||
left: '50%',
|
||||
transform: 'translateX(-50%)',
|
||||
width: '150px',
|
||||
height: '1px',
|
||||
background: colors.accent,
|
||||
},
|
||||
}}
|
||||
>
|
||||
The Art of Creation
|
||||
</Typography>
|
||||
</AnimatedSection>
|
||||
|
||||
<Grid container spacing={4} justifyContent="center">
|
||||
{processSteps.map((step, index) => (
|
||||
<Grid key={index}>
|
||||
<AnimatedSection
|
||||
style={{
|
||||
animationDelay: processInView ? `${index * 0.2}s` : '0s',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
textAlign: 'center',
|
||||
p: 3,
|
||||
borderRadius: '4px',
|
||||
background: colors.paper,
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
|
||||
transition: 'transform 0.3s ease',
|
||||
'&:hover': {
|
||||
transform: 'translateY(-5px)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<VintageImageFrame
|
||||
sx={{
|
||||
height: '200px',
|
||||
width: '100%',
|
||||
backgroundImage: `url(${step.image})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
mb: 3,
|
||||
filter: 'sepia(0.2) contrast(1.05)',
|
||||
animation: `${scaleIn} 1s ease`,
|
||||
}}
|
||||
/>
|
||||
<Typography variant="h6" sx={{ fontWeight: 400, color: colors.ink, mb: 2, fontFamily: '"Playfair Display", serif' }}>
|
||||
{step.title}
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{ color: colors.secondary, fontFamily: '"Cormorant Garamond", serif', lineHeight: 1.6 }}>
|
||||
{step.description}
|
||||
</Typography>
|
||||
</Box>
|
||||
</AnimatedSection>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Container>
|
||||
</Box>
|
||||
|
||||
{/* Footer */}
|
||||
<Box ref={footerRef} sx={{ py: 6, textAlign: 'center', borderTop: `1px solid ${colors.border}` }}>
|
||||
<AnimatedSection style={{ animationDelay: footerInView ? '0.1s' : '0s' }}>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{
|
||||
mb: 3,
|
||||
fontWeight: 300,
|
||||
color: colors.ink,
|
||||
letterSpacing: '4px',
|
||||
fontFamily: '"Playfair Display", serif',
|
||||
textTransform: 'uppercase',
|
||||
}}
|
||||
>
|
||||
The Kalawati
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{
|
||||
color: colors.secondary,
|
||||
mb: 4,
|
||||
maxWidth: '600px',
|
||||
margin: '0 auto',
|
||||
fontSize: '1rem',
|
||||
fontFamily: '"Cormorant Garamond", serif',
|
||||
lineHeight: 1.6,
|
||||
}}
|
||||
>
|
||||
Join our journey to weave stories, empower artisans, and celebrate Indian heritage. Be the first to experience our handcrafted collections.
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', gap: 3, mb: 4 }}>
|
||||
<IconButton
|
||||
href="https://instagram.com"
|
||||
target="_blank"
|
||||
sx={{ color: colors.secondary, '&:hover': { color: colors.accent, transform: 'scale(1.1)' }, transition: 'all 0.3s ease' }}
|
||||
>
|
||||
<InstagramIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
href="https://facebook.com"
|
||||
target="_blank"
|
||||
sx={{ color: colors.secondary, '&:hover': { color: colors.accent, transform: 'scale(1.1)' }, transition: 'all 0.3s ease' }}
|
||||
>
|
||||
<FacebookIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
href="https://twitter.com"
|
||||
target="_blank"
|
||||
sx={{ color: colors.secondary, '&:hover': { color: colors.accent, transform: 'scale(1.1)' }, transition: 'all 0.3s ease' }}
|
||||
>
|
||||
<TwitterIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
href="mailto:contact@thekalawati.com"
|
||||
sx={{ color: colors.secondary, '&:hover': { color: colors.accent, transform: 'scale(1.1)' }, transition: 'all 0.3s ease' }}
|
||||
>
|
||||
<EmailIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{ color: colors.secondary, opacity: 0.7, fontSize: '0.8rem', fontFamily: '"Cormorant Garamond", serif' }}
|
||||
>
|
||||
© {new Date().getFullYear()} The Kalawati. All rights reserved.
|
||||
</Typography>
|
||||
</AnimatedSection>
|
||||
</Box>
|
||||
</Container>
|
||||
</VintageBox>
|
||||
);
|
||||
};
|
||||
|
||||
export default VintageComingSoonPage;
|
||||
|
|
@ -1,19 +1,9 @@
|
|||
/* simple defaults (no Tailwind) */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
html, body, #root { height: 100%; }
|
||||
body {
|
||||
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
|
||||
background: #f7fafc;
|
||||
color: #0f172a;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,7 @@
|
|||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"DOM.Iterable",
|
||||
"ESNext"
|
||||
],
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": false,
|
||||
|
|
@ -20,7 +16,5 @@
|
|||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
"include": ["src"]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue