feat: New design and optimization
This commit is contained in:
@@ -8,7 +8,7 @@ export default function AppLogo() {
|
||||
</div>
|
||||
<div className="ml-1 grid flex-1 text-left text-sm">
|
||||
<span className="mb-0.5 truncate leading-tight font-semibold">
|
||||
Laravel Starter Kit
|
||||
Soorya Carpet
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { NavFooter } from '@/components/nav-footer';
|
||||
import { NavMain } from '@/components/nav-main';
|
||||
import { NavUser } from '@/components/nav-user';
|
||||
import {
|
||||
@@ -15,7 +14,12 @@ import dashboardcarousel from '@/routes/dashboard/carousel';
|
||||
import testimonial from '@/routes/testimonial';
|
||||
import { type NavItem } from '@/types';
|
||||
import { Link } from '@inertiajs/react';
|
||||
import { BookOpen, Folder, GalleryHorizontal, LayoutGrid } from 'lucide-react';
|
||||
import {
|
||||
GalleryHorizontal,
|
||||
LayoutGrid,
|
||||
Package,
|
||||
TableOfContents,
|
||||
} from 'lucide-react';
|
||||
import AppLogo from './app-logo';
|
||||
|
||||
const mainNavItems: NavItem[] = [
|
||||
@@ -29,23 +33,20 @@ const mainNavItems: NavItem[] = [
|
||||
href: dashboardcarousel.index(),
|
||||
icon: GalleryHorizontal,
|
||||
},
|
||||
{
|
||||
title: 'Products',
|
||||
href: dashboard.product.index(),
|
||||
icon: Package,
|
||||
},
|
||||
{
|
||||
title: 'Testimonial',
|
||||
href: testimonial.index(),
|
||||
icon: GalleryHorizontal,
|
||||
},
|
||||
];
|
||||
|
||||
const footerNavItems: NavItem[] = [
|
||||
{
|
||||
title: 'Repository',
|
||||
href: 'https://github.com/laravel/react-starter-kit',
|
||||
icon: Folder,
|
||||
},
|
||||
{
|
||||
title: 'Documentation',
|
||||
href: 'https://laravel.com/docs/starter-kits#react',
|
||||
icon: BookOpen,
|
||||
title: 'FAQs',
|
||||
href: dashboard.faq.show(),
|
||||
icon: TableOfContents,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -69,7 +70,6 @@ export function AppSidebar() {
|
||||
</SidebarContent>
|
||||
|
||||
<SidebarFooter>
|
||||
<NavFooter items={footerNavItems} className="mt-auto" />
|
||||
<NavUser />
|
||||
</SidebarFooter>
|
||||
</Sidebar>
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { about, artOfWeaving, contact, faq, home, product } from '@/routes';
|
||||
import { about, artOfWeaving, contact, faq, home } from '@/routes';
|
||||
import index from '@/routes/index/index';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import ns from '@asset/img/about/ns.gif';
|
||||
import oko from '@asset/img/about/oko.gif';
|
||||
import logo from '@asset/img/logo/soorya.png';
|
||||
import { SiFacebook, SiInstagram } from '@icons-pack/react-simple-icons';
|
||||
import { Link } from '@inertiajs/react';
|
||||
import { MoveRight } from 'lucide-react';
|
||||
|
||||
export default function Footer() {
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<footer className="bg-primary">
|
||||
<div className="mx-auto grid max-w-screen-2xl grid-cols-4 gap-8 px-12 py-8 max-md:grid-cols-1 max-md:grid-rows-4 max-md:px-6">
|
||||
<div className="flex flex-col gap-4">
|
||||
<img src={logo} alt="Soorya Carpet Logo" className="w-32" />
|
||||
<div className="flex flex-col gap-4 text-sm text-white">
|
||||
<p>
|
||||
A beautiful home deserves beautiful carpets Since
|
||||
1974, crafting the finest handmade Nepalese carpets
|
||||
</p>
|
||||
<p>{t('footer.desc.title')}</p>
|
||||
<ul>
|
||||
<li>Soorya Carpet Industries</li>
|
||||
<li>Address: Thapathali, Kathmandu</li>
|
||||
<li>Phone: [+977-1] 4780923, 4783003</li>
|
||||
<li>Email: sooryacarpets@gmail.com</li>
|
||||
<li>{t('footer.desc.company')}</li>
|
||||
<li>{t('footer.desc.address')}</li>
|
||||
<li>{t('footer.desc.phone')}</li>
|
||||
<li>{t('footer.desc.email')}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -31,17 +33,17 @@ export default function Footer() {
|
||||
<ul className="flex flex-col gap-1 text-sm">
|
||||
<li>
|
||||
<Link href={home()} className="text-neutral-300">
|
||||
Home
|
||||
{t('footer.links.home')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={contact()} className="text-neutral-300">
|
||||
Contact US
|
||||
{t('footer.links.contact')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={about()} className="text-neutral-300">
|
||||
About Us
|
||||
{t('footer.links.about-us')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
@@ -49,27 +51,30 @@ export default function Footer() {
|
||||
href={artOfWeaving()}
|
||||
className="text-neutral-300"
|
||||
>
|
||||
Art of Weaving
|
||||
{t('footer.links.art')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={product()} className="text-neutral-300">
|
||||
Products
|
||||
<Link
|
||||
href={index.product()}
|
||||
className="text-neutral-300"
|
||||
>
|
||||
{t('footer.links.products')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={home()} className="text-neutral-300">
|
||||
Bespoke Design
|
||||
{t('footer.links.bespoke')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={home()} className="text-neutral-300">
|
||||
Design Gallery / E-Catalog
|
||||
{t('footer.links.gallery')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={faq()} className="text-neutral-300">
|
||||
FAQ
|
||||
{t('footer.links.faq')}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -78,46 +83,57 @@ export default function Footer() {
|
||||
<p className="text-lg font-medium text-white">
|
||||
Certifications & Trust Badges
|
||||
</p>
|
||||
<div className="grid grid-cols-3 gap-1">
|
||||
<img
|
||||
src={ns}
|
||||
alt="NS Standard"
|
||||
className="aspect-square object-cover object-center"
|
||||
/>
|
||||
<img
|
||||
src={oko}
|
||||
alt="oko Standard"
|
||||
className="object-cover object-center"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex flex-col gap-6">
|
||||
<form className="flex flex-col gap-2">
|
||||
<Label className="text-lg font-medium text-white">
|
||||
Newsletter/Updates
|
||||
{t('footer.news.title')}
|
||||
</Label>
|
||||
<div className="flex items-center gap-2 max-sm:flex-col">
|
||||
<Input
|
||||
id="newsletter"
|
||||
placeholder="Email Address"
|
||||
placeholder={t('footer.news.input')}
|
||||
className="bg-white"
|
||||
/>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className="bg-transparent text-white max-sm:w-full"
|
||||
>
|
||||
Subscribe <MoveRight />
|
||||
{t('footer.news.button')} <MoveRight />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="text-base font-medium text-white">
|
||||
Legal
|
||||
{t('footer.news.legal.title')}
|
||||
</p>
|
||||
<ul className="flex flex-col gap-1 text-sm text-neutral-300">
|
||||
<li>
|
||||
<Link href="privacy-policy">
|
||||
Privacy Policy
|
||||
{t('footer.news.legal.privacy')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="terms-and-condition">
|
||||
Terms & Conditions Return
|
||||
{t('footer.news.legal.terms')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={faq()}>
|
||||
Policy (from FAQ)Privacy Policy (from
|
||||
FAQ)
|
||||
{t('footer.news.legal.policy')}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
// import { dashboard, login, register } from '@/routes';
|
||||
// import { SharedData } from '@/types';
|
||||
// import { Link, usePage } from '@inertiajs/react';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
@@ -8,18 +16,55 @@ import {
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@/components/ui/sheet';
|
||||
import { about, artOfWeaving, contact, faq, home, product } from '@/routes';
|
||||
import { about, artOfWeaving, bespoke, contact, faq, home } from '@/routes';
|
||||
import index from '@/routes/index/index';
|
||||
import { useLocale, useTranslations } from '@/utils/i18n';
|
||||
import logo from '@asset/img/logo/soorya.png';
|
||||
import { Link } from '@inertiajs/react';
|
||||
import { Link, router } from '@inertiajs/react';
|
||||
import { Mail, MapPin, Menu, Phone } from 'lucide-react';
|
||||
|
||||
export default function Navbar() {
|
||||
// const [lang, setLang] = useState('en');
|
||||
// const { translations } = usePage().props;
|
||||
// const { post } = useForm({
|
||||
// locale: lang,
|
||||
// });
|
||||
|
||||
// console.log('lang', lang);
|
||||
|
||||
// const changeLanguage = (e) => {
|
||||
// console.log(e);
|
||||
// setLang(e);
|
||||
// post(locale.change().url);
|
||||
// };
|
||||
// const { auth } = usePage<SharedData>().props;
|
||||
|
||||
const { t } = useTranslations();
|
||||
const locale = useLocale();
|
||||
|
||||
// const { locale, translations } = usePage().props;
|
||||
|
||||
const changeLanguage = (newLocale: string) => {
|
||||
router.post(
|
||||
'/locale',
|
||||
{ locale: newLocale },
|
||||
{
|
||||
preserveScroll: true,
|
||||
preserveState: true,
|
||||
onSuccess: () => {
|
||||
// The page will automatically update because Inertia
|
||||
// will make a new request and get the updated translations
|
||||
console.log('Language changed to:', newLocale);
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className="mx-auto w-full text-sm not-has-[nav]:hidden">
|
||||
<div className="bg-primary py-1.5 text-white/60 max-md:hidden">
|
||||
<div className="mx-auto max-w-screen-2xl px-12 max-md:px-2">
|
||||
<div className="mx-auto flex max-w-screen-2xl items-center justify-between px-12 max-md:px-2">
|
||||
<ul className="flex items-center gap-4">
|
||||
<li>
|
||||
<a
|
||||
@@ -49,6 +94,19 @@ export default function Navbar() {
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<Select value={locale} onValueChange={changeLanguage}>
|
||||
<SelectTrigger className="h-0 w-32 border-0 focus-visible:ring-0">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{/* <SelectLabel>Fruits</SelectLabel> */}
|
||||
<SelectItem value="en">English</SelectItem>
|
||||
<SelectItem value="cn">中国人</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx-auto w-full max-w-screen-2xl px-12 py-2 text-base not-has-[nav]:hidden max-md:px-4">
|
||||
@@ -62,24 +120,26 @@ export default function Navbar() {
|
||||
</Link>
|
||||
<ul className="flex items-center gap-6 max-md:hidden">
|
||||
<li>
|
||||
<Link href={about()}>About Us</Link>
|
||||
<Link href={about()}>{t('nav.about-us')}</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={artOfWeaving()}>
|
||||
Art of Weaving
|
||||
{t('nav.art')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={product()}>Our Products</Link>
|
||||
<Link href={index.product()}>
|
||||
{t('nav.products')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={about()}>Bespoke Design</Link>
|
||||
<Link href={bespoke()}>{t('nav.bespoke')}</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={faq()}>FAQs</Link>
|
||||
<Link href={faq()}>{t('nav.faq')}</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={contact()}>Contact Us</Link>
|
||||
<Link href={contact()}>{t('nav.contact')}</Link>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -94,28 +154,32 @@ export default function Navbar() {
|
||||
</SheetDescription>
|
||||
<ul className="mt-20 flex flex-col items-center justify-center gap-6">
|
||||
<li>
|
||||
<Link href={about()}>About Us</Link>
|
||||
<Link href={about()}>
|
||||
{t('nav.about-us')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={artOfWeaving()}>
|
||||
Art of Weaving
|
||||
{t('nav.art')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={product()}>
|
||||
Our Products
|
||||
<Link href={index.product()}>
|
||||
{t('nav.products')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={about()}>
|
||||
Bespoke Design
|
||||
<Link href={bespoke()}>
|
||||
{t('nav.bespoke')}
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={faq()}>FAQs</Link>
|
||||
<Link href={faq()}>{t('nav.faq')}</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={contact()}>Contact Us</Link>
|
||||
<Link href={contact()}>
|
||||
{t('nav.contact')}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</SheetContent>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import index from '@/routes/index/index';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import { Link } from '@inertiajs/react';
|
||||
import { MoveRightIcon } from 'lucide-react';
|
||||
import 'swiper/css';
|
||||
@@ -10,6 +12,7 @@ export default function SwiperCarousel({
|
||||
}: {
|
||||
item: [{ image_url: string; alt: string }];
|
||||
}) {
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@@ -39,20 +42,22 @@ export default function SwiperCarousel({
|
||||
</Swiper>
|
||||
<div className="absolute bottom-7 left-12 z-50 flex w-md flex-col gap-6 rounded-lg bg-[#FFF5F1]/80 px-12 py-6 font-serif">
|
||||
<div className="flex flex-col gap-1">
|
||||
<h1 className="text-4xl font-medium">
|
||||
Feel More Like Home
|
||||
<h1 className="text-3xl font-medium max-sm:text-lg">
|
||||
{t('pages.home.banner.title')}
|
||||
{/* A Beautiful Home
|
||||
Deserves A Beautiful Carpet */}
|
||||
</h1>
|
||||
<p className="text-xl leading-tight">
|
||||
Carpets that are made with care from ground up
|
||||
<p className="text-xl leading-tight max-sm:text-sm">
|
||||
{t('pages.home.banner.subTitle')}
|
||||
</p>
|
||||
</div>
|
||||
<Link href="">
|
||||
<Link href={index.product().url}>
|
||||
<Button
|
||||
variant={'secondary'}
|
||||
size={'lg'}
|
||||
className="cursor-pointer border border-primary bg-transparent text-lg ring-primary"
|
||||
>
|
||||
Discover More <MoveRightIcon />
|
||||
{t('pages.home.banner.button')} <MoveRightIcon />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,300 @@
|
||||
export default function Testimonial() {
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import FilePondPluginImageExifOrientation from 'filepond-plugin-image-exif-orientation';
|
||||
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
|
||||
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
|
||||
import 'filepond/dist/filepond.min.css';
|
||||
import { Star } from 'lucide-react';
|
||||
import { FilePond, registerPlugin } from 'react-filepond';
|
||||
|
||||
import 'swiper/css';
|
||||
import 'swiper/css/navigation';
|
||||
import 'swiper/css/pagination';
|
||||
import { Swiper, SwiperSlide } from 'swiper/react';
|
||||
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import { useForm } from '@inertiajs/react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { Pagination } from 'swiper/modules';
|
||||
|
||||
// const testimonial = [
|
||||
// {
|
||||
// name: 'Priya Sharada',
|
||||
// company: 'Sharada Group',
|
||||
// review: 'What impressed me the most was the attention to detail and the evident care put into making the rug, It has become a center piece in my living room, gathering compliments from everyone who sees it. If you are considering handmade rugs, I highly recommend Kaleen.',
|
||||
// img: testimonial1,
|
||||
// },
|
||||
// {
|
||||
// name: 'Kedar Bhakta Mathema',
|
||||
// company:
|
||||
// 'Former VC of Tribhuwan University, Nepal, Former Nepalese Ambassador to Japan',
|
||||
// review: 'I am delighted to recommend Kaleen Carpet in Kathmandu to anyone seeking skilled carpet weavers. What impressed me most about Kaleen was their willingness to make several changes to the design at my request without any hesitation. I find Kaleen to be highly professional and trustworthy in all their dealings.',
|
||||
// img: testimonial3,
|
||||
// },
|
||||
// {
|
||||
// name: 'Ani Rudra Silwal and Srijana Silwal',
|
||||
// company: 'USA',
|
||||
// review: "Thank you for making these carpets for us! We couldn't be more pleased with them. The entire process - from the custom design to shipping - was seamless and very professional. We look forward to having these beautiful Nepali handmade carpets in our home for many years to come!",
|
||||
// img: testimonial1,
|
||||
// },
|
||||
// {
|
||||
// name: 'Manila Pradhan and Bhaskar Joshi',
|
||||
// company: 'USA',
|
||||
// review: 'We absolutely love the carpet. Thank you so much for the excellent design and execution.',
|
||||
// img: testimonial2,
|
||||
// },
|
||||
// ];
|
||||
export default function Testimonial({
|
||||
testimonial,
|
||||
}: {
|
||||
testimonial: [
|
||||
{
|
||||
name: string;
|
||||
location: string;
|
||||
image: string;
|
||||
description: string;
|
||||
},
|
||||
];
|
||||
}) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [file, setFile] = useState<any | null>(null);
|
||||
const [open, setOpen] = useState(false);
|
||||
const { data, setData, post, processing, errors } = useForm({
|
||||
name: '',
|
||||
location: '',
|
||||
description: '',
|
||||
image: null as File | null,
|
||||
});
|
||||
registerPlugin(
|
||||
FilePondPluginImageExifOrientation,
|
||||
FilePondPluginImagePreview,
|
||||
);
|
||||
useEffect(() => {
|
||||
if (file) {
|
||||
setData('image', file.file);
|
||||
}
|
||||
}, [file, setData]);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
post('/testimonial', {
|
||||
// forceFormData: true,
|
||||
onSuccess: () => {
|
||||
toast.success('Testimonial successfully uploaded!');
|
||||
setOpen(false);
|
||||
setFile(null);
|
||||
setData({
|
||||
name: '',
|
||||
location: '',
|
||||
description: '',
|
||||
image: null,
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<h4>Testimonials</h4>
|
||||
<div></div>
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col items-center gap-12 px-16 py-12 max-sm:px-8">
|
||||
<h4 className="text-center font-serif text-4xl font-medium">
|
||||
{t('pages.home.sections.testimonial.title')}
|
||||
</h4>
|
||||
{/* <div className="grid grid-cols-4 gap-8 max-lg:grid-cols-2 max-md:grid-cols-2 max-sm:grid-cols-1">
|
||||
{testimonial.map((review) => (
|
||||
<div className="flex flex-col items-center gap-4 rounded-lg border border-gray-300 px-6 py-6 text-center">
|
||||
<div className="flex flex-col gap-1">
|
||||
<img
|
||||
src={review.image}
|
||||
alt={review.name}
|
||||
className="mb-4 aspect-video rounded-md object-cover object-center"
|
||||
/>
|
||||
<p className="text-lg font-bold">
|
||||
{review.name}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
{review.location}
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-sm text-gray-800">
|
||||
{review.description}
|
||||
</p>
|
||||
|
||||
<div className="flex items-center">
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div> */}
|
||||
<div
|
||||
className="relative max-w-7xl overflow-clip max-sm:max-w-sm"
|
||||
id="testimonial"
|
||||
>
|
||||
<Swiper
|
||||
spaceBetween={16}
|
||||
slidesPerView={4}
|
||||
breakpoints={{
|
||||
432: {
|
||||
slidesPerView: 2,
|
||||
spaceBetween: 8,
|
||||
},
|
||||
768: {
|
||||
slidesPerView: 3,
|
||||
spaceBetween: 8,
|
||||
},
|
||||
1024: {
|
||||
slidesPerView: 4,
|
||||
spaceBetween: 16,
|
||||
},
|
||||
}}
|
||||
loop={true}
|
||||
autoplay={{
|
||||
delay: 1500,
|
||||
}}
|
||||
className="w-full"
|
||||
pagination={true}
|
||||
// navigation={true}
|
||||
modules={[Pagination]}
|
||||
>
|
||||
{testimonial.map((review) => (
|
||||
<SwiperSlide className="relative overflow-clip">
|
||||
<div className="flex flex-col items-center gap-4 rounded-lg border border-gray-300 px-6 py-6 text-center">
|
||||
<div className="flex flex-col gap-1">
|
||||
<img
|
||||
src={review.image}
|
||||
alt={review.name}
|
||||
className="mb-4 aspect-video rounded-md object-cover object-center"
|
||||
/>
|
||||
<p className="text-lg font-bold">
|
||||
{review.name}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
{review.location}
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-sm text-gray-800">
|
||||
{review.description}
|
||||
</p>
|
||||
|
||||
<div className="flex items-center">
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
<Star size={16} color="#EDC001" />
|
||||
</div>
|
||||
</div>
|
||||
</SwiperSlide>
|
||||
))}
|
||||
</Swiper>
|
||||
</div>
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button className="cursor-pointer">
|
||||
{t('pages.home.sections.testimonial.button')}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="!max-w-3xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Give your testimonial</DialogTitle>
|
||||
<DialogDescription></DialogDescription>
|
||||
<form
|
||||
className="grid gap-4"
|
||||
onSubmit={handleSubmit}
|
||||
method="POST"
|
||||
>
|
||||
<div className="grid gap-3">
|
||||
<Label htmlFor="name">Name</Label>
|
||||
<Input
|
||||
id="name"
|
||||
name="name"
|
||||
placeholder="Enter your name"
|
||||
value={data.name}
|
||||
onChange={(e) =>
|
||||
setData('name', e.target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-3">
|
||||
<Label htmlFor="company">Location</Label>
|
||||
<Input
|
||||
id="company"
|
||||
name="location"
|
||||
placeholder="Enter you location (e.g. Private Company / Country Name)"
|
||||
value={data.location}
|
||||
onChange={(e) =>
|
||||
setData('location', e.target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-3">
|
||||
<Label htmlFor="review">Description</Label>
|
||||
<Textarea
|
||||
id="review"
|
||||
name="review"
|
||||
cols={20}
|
||||
placeholder="Write your review..."
|
||||
value={data.description}
|
||||
onChange={(e) =>
|
||||
setData(
|
||||
'description',
|
||||
e.target.value,
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3">
|
||||
<Label>Image</Label>
|
||||
<FilePond
|
||||
files={file ? [file] : []}
|
||||
onupdatefiles={(fileItems) => {
|
||||
setFile(fileItems[0] || null);
|
||||
}}
|
||||
allowMultiple={false}
|
||||
maxFiles={1}
|
||||
name="image"
|
||||
instantUpload={false}
|
||||
storeAsFile={true}
|
||||
labelIdle='Drag & Drop your image or <span class="filepond--label-action">Browse</span>'
|
||||
/>
|
||||
{errors.image && (
|
||||
<span className="text-red-600">
|
||||
{errors.image}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={processing}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
{processing
|
||||
? 'Submitting...'
|
||||
: 'Submit Now'}
|
||||
</Button>
|
||||
</form>
|
||||
</DialogHeader>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import ourStory from '@asset/img/about/A1PG1ALsIBL._AC_UF894,1000_QL80_.jpg';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import kaleen from '@asset/img/about/kaleen.jpg';
|
||||
import ns from '@asset/img/about/ns.gif';
|
||||
import oko from '@asset/img/about/oko.gif';
|
||||
import ourStory from '@asset/img/products/sci trad 8.jpg';
|
||||
import { Head } from '@inertiajs/react';
|
||||
|
||||
import { HeartHandshake, Lightbulb, Target } from 'lucide-react';
|
||||
export default function About() {
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<Head title="About Us">
|
||||
@@ -20,49 +22,19 @@ export default function About() {
|
||||
<div className="grid h-1/2 grid-cols-2 gap-20 overflow-clip max-md:grid-cols-1 max-md:gap-12">
|
||||
<div className="flex flex-col gap-2">
|
||||
<h1 className="font-serif text-5xl leading-tight font-medium tracking-tight max-sm:text-4xl">
|
||||
Our Story: Crafting Legacies Since 1974
|
||||
{t('pages.about.sections.first.title')}
|
||||
</h1>
|
||||
<div className="flex flex-col gap-4 text-sm max-sm:text-base">
|
||||
<p>
|
||||
The story of Soorya Carpet Industries begins
|
||||
in the early 1970s, when Mr. Laxman Shrestha
|
||||
and Mrs. Renuka Shrestha left their village
|
||||
in Dolakha and moved to Kathmandu with the
|
||||
ambition of building something meaningful.
|
||||
What started as a small rug-weaving
|
||||
initiative in a single room eventually grew
|
||||
into one of Nepal’s largest carpet
|
||||
manufacturing enterprises. Through
|
||||
perseverance and vision, they provided
|
||||
livelihoods to more than 1,000 skilled and
|
||||
unskilled workers and made a significant
|
||||
contribution to the country’s GDP. For over
|
||||
two decades, Soorya Carpet Industries earned
|
||||
international recognition, particularly in
|
||||
Germany, for exporting high-quality,
|
||||
hand-knotted carpets.
|
||||
{t('pages.about.sections.first.desc.first')}
|
||||
</p>
|
||||
<p>
|
||||
By the late 1990s, however, Nepal’s carpet
|
||||
industry suffered severe setbacks owing to
|
||||
economic, social, and political challenges.
|
||||
Global scrutiny following child labour
|
||||
controversies in the wider industry, coupled
|
||||
with the instability caused by the Maoist
|
||||
insurgency, crippled the sector. Like many
|
||||
others, Soorya Carpet Industries was forced
|
||||
to scale down and eventually suspend
|
||||
production.
|
||||
{t(
|
||||
'pages.about.sections.first.desc.second',
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
The industry never quite returned to its
|
||||
early-1990s mass-scale export peak, yet it
|
||||
found ways to reinvent itself and stay
|
||||
relevant. Recognizing this shift, Soorya
|
||||
Carpet Industries transitioned from
|
||||
large-scale production to a boutique model,
|
||||
focusing on the niche luxury segment with
|
||||
custom-made, limited-edition rugs.
|
||||
{t('pages.about.sections.first.desc.third')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -80,35 +52,23 @@ export default function About() {
|
||||
/>
|
||||
<div className="flex flex-col gap-2">
|
||||
<h2 className="font-serif text-5xl leading-tight font-medium tracking-tight max-sm:text-4xl">
|
||||
The Kaleen Rebrand Story: A New Chapter
|
||||
{t('pages.about.sections.second.title')}
|
||||
</h2>
|
||||
<div className="flex flex-col gap-4 text-sm max-sm:text-base">
|
||||
<p>
|
||||
Guided by the aspiration to create premium,
|
||||
ethical and artistic carpets, this journey
|
||||
led to the launch of Kaleen—our exclusive
|
||||
designer carpet brand.
|
||||
{t(
|
||||
'pages.about.sections.second.desc.first',
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
Kaleen celebrates craftsmanship, artistry,
|
||||
and ethics. We create bespoke,
|
||||
limited-edition rugs that range from
|
||||
time-honoured traditional designs to bold,
|
||||
innovative forms, all crafted to complement
|
||||
modern interiors and aesthetics. Our
|
||||
collections are inspired by beautiful
|
||||
landscapes of Nepal and the five elements of
|
||||
life: Fire, Water, Earth, Air, and Metal.
|
||||
{t(
|
||||
'pages.about.sections.second.desc.second',
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
Handmade carpets have long been central to
|
||||
interior design—a tradition that remains
|
||||
timeless. At Kaleen, we are proud to carry
|
||||
this heritage forward with integrity and
|
||||
creativity. Our ambition is to build a
|
||||
strong brand identity, uphold ethical
|
||||
credibility, and expand into discerning
|
||||
global markets.
|
||||
{t(
|
||||
'pages.about.sections.second.desc.third',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -117,47 +77,53 @@ export default function About() {
|
||||
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-12 py-12 max-md:px-6">
|
||||
<h3 className="text-center font-serif text-5xl leading-tight font-medium tracking-tight max-sm:text-4xl">
|
||||
Our Guiding Principles
|
||||
{t('pages.about.sections.third.title')}
|
||||
</h3>
|
||||
<div className="flex gap-8 max-md:flex-col">
|
||||
<div className="flex flex-col items-center gap-4 rounded-xl bg-accent px-8 py-8 text-center max-sm:px-4">
|
||||
<Lightbulb size={48} color="#5A1A1A" />
|
||||
<p className="font-serif text-3xl font-semibold">
|
||||
Our vision
|
||||
{t(
|
||||
'pages.about.sections.third.cards.first.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="text-center">
|
||||
To be the global leader in luxury handcrafted
|
||||
carpets, renowned for unparalleled quality,
|
||||
innovative design, and sustainable practices.
|
||||
<p className="text-justify text-lg tracking-tight">
|
||||
{t(
|
||||
'pages.about.sections.third.cards.first.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>{' '}
|
||||
<div className="flex flex-col items-center gap-4 rounded-xl bg-accent px-8 py-8 text-center">
|
||||
<Target size={48} color="#5A1A1A" />
|
||||
<p className="font-serif text-3xl font-semibold">
|
||||
Our Mission
|
||||
{t(
|
||||
'pages.about.sections.third.cards.second.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="text-center">
|
||||
To meticulously craft exquisite carpets that
|
||||
enrich lives and spaces, preserving artisanal
|
||||
heritage while inspiring contemporary design.
|
||||
<p className="text-justify text-lg tracking-tight">
|
||||
{t(
|
||||
'pages.about.sections.third.cards.second.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>{' '}
|
||||
<div className="flex flex-col items-center gap-4 rounded-xl bg-accent px-8 py-8 text-center">
|
||||
<HeartHandshake size={48} color="#5A1A1A" />
|
||||
<p className="font-serif text-3xl font-semibold">
|
||||
Our Promise
|
||||
{t(
|
||||
'pages.about.sections.third.cards.third.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="text-center">
|
||||
We promise exceptional artistry, ethical
|
||||
sourcing, and personalized service, ensuring
|
||||
every Kaleen carpet is a timeless masterpiece.
|
||||
<p className="text-justify text-lg tracking-tight">
|
||||
{t(
|
||||
'pages.about.sections.third.cards.third.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-12 py-12">
|
||||
<h4 className="text-center font-serif text-5xl leading-tight font-medium tracking-tight max-sm:text-4xl">
|
||||
Our Commitment to Quality & Ethics
|
||||
{t('pages.about.sections.fourth.title')}
|
||||
</h4>
|
||||
<div className="flex items-center justify-center gap-8">
|
||||
<img src={ns} alt="NS Standard" />
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import artOfWeaving from '@asset/img/art/IMG_4715.jpg';
|
||||
import skill from '@asset/img/material/silk balls.jpg';
|
||||
import skillYarn from '@asset/img/material/silk yarn.jpg';
|
||||
import woolBall from '@asset/img/material/wool balls.jpg';
|
||||
import woolYarn from '@asset/img/material/wool yarn.jpg';
|
||||
import artOfWeaving from '@asset/img/production/IMG_2719.jpg';
|
||||
import { Head } from '@inertiajs/react';
|
||||
import { Flower, Hand, Package, Palette, Shirt } from 'lucide-react';
|
||||
|
||||
@@ -15,11 +15,11 @@ export default function Art() {
|
||||
<Head title="Art of Weaving" />
|
||||
<section>
|
||||
<div className="relative">
|
||||
<div className="absolute h-full w-full bg-white/70"></div>
|
||||
<div className="absolute h-full w-full bg-white/60"></div>
|
||||
<img
|
||||
src={artOfWeaving}
|
||||
alt="Art of Weaving"
|
||||
className="aspect-[16/4] object-cover object-top"
|
||||
className="aspect-[16/4] object-cover object-center"
|
||||
/>
|
||||
<h1 className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 font-serif text-7xl font-medium tracking-tight">
|
||||
The Art of Weaving
|
||||
|
||||
128
resources/js/pages/bespoke.tsx
Normal file
128
resources/js/pages/bespoke.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import bespokeHeader from '@asset/img/products/color swatches.jpg';
|
||||
import { Head } from '@inertiajs/react';
|
||||
import { ClipboardList, Paintbrush, Palette, Truck } from 'lucide-react';
|
||||
|
||||
export default function Bespoke({
|
||||
product,
|
||||
}: {
|
||||
product: [{ id: number; title: string; type: string; image_url: string }];
|
||||
}) {
|
||||
console.log(product);
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<Layout>
|
||||
<Head title="Bespoke Design" />
|
||||
<section className="">
|
||||
<div className="relative">
|
||||
<div className="absolute h-full w-full bg-white/30"></div>
|
||||
<img
|
||||
src={bespokeHeader}
|
||||
alt="Bespoke Design"
|
||||
className="aspect-[16/4] object-cover object-center max-sm:aspect-[16/9]"
|
||||
/>
|
||||
<div className="absolute top-1/2 left-1/2 flex -translate-x-1/2 -translate-y-1/2 flex-col gap-2">
|
||||
<h1 className="text-center font-serif text-5xl font-medium tracking-tight max-md:text-4xl max-sm:text-2xl">
|
||||
{t('pages.bespoke.sections.banner.title')}
|
||||
</h1>
|
||||
<p className="text-center text-lg text-gray-800 max-sm:text-sm">
|
||||
{t('pages.bespoke.sections.banner.subTitle')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-12 px-12 py-18 max-sm:px-8">
|
||||
<h2 className="text-center font-serif text-4xl font-medium max-md:text-2xl">
|
||||
{t('pages.bespoke.sections.first.title')}
|
||||
</h2>
|
||||
<div className="grid grid-cols-4 gap-4 max-md:grid-cols-2 max-sm:grid-cols-1">
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<ClipboardList size={40} color="#5A1A1A" />
|
||||
<p className="text-center font-serif text-xl font-medium">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.first.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="px-4 text-center text-sm">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.first.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<Palette size={40} color="#5A1A1A" />
|
||||
<p className="text-center font-serif text-xl font-medium">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.second.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="px-4 text-center text-sm">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.second.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<Paintbrush size={40} color="#5A1A1A" />
|
||||
<p className="text-center font-serif text-xl font-medium">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.third.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="px-4 text-center text-sm">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.third.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<Truck size={40} color="#5A1A1A" />
|
||||
<p className="text-center font-serif text-xl font-medium">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.fourth.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="px-4 text-center text-sm">
|
||||
{t(
|
||||
'pages.bespoke.sections.first.card.fourth.desc',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-12 px-12 py-18 max-sm:px-8">
|
||||
<h3 className="text-center font-serif text-4xl font-medium max-md:text-2xl">
|
||||
Bespoke Product
|
||||
</h3>
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
{product.map((item) => (
|
||||
<img
|
||||
src={item.image_url}
|
||||
alt={item.title}
|
||||
className="aspect-[4/5] rounded-lg object-cover object-center"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col items-center gap-8 px-12 py-18 max-sm:px-8">
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<h4 className="text-center font-serif text-4xl font-medium max-md:text-2xl">
|
||||
{t('pages.bespoke.sections.second.title')}
|
||||
</h4>
|
||||
<p className="text-center max-md:text-sm">
|
||||
{t('pages.bespoke.sections.second.desc')} <br />{' '}
|
||||
{t('pages.bespoke.sections.second.desc2')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Button className="cursor-pointer">
|
||||
{t('pages.bespoke.sections.second.button')}
|
||||
</Button>
|
||||
</section>
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -10,10 +10,12 @@ import {
|
||||
} from '@/components/ui/select';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import { Form, Head } from '@inertiajs/react';
|
||||
import { Mail, MapPin, Phone } from 'lucide-react';
|
||||
|
||||
export default function Contact() {
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<Layout>
|
||||
@@ -21,64 +23,79 @@ export default function Contact() {
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-12 px-12 py-12 max-md:px-8">
|
||||
<div className="flex flex-col gap-4">
|
||||
<h1 className="text-center font-serif text-5xl font-medium tracking-tight max-md:text-3xl">
|
||||
Connect with Kaleen Carpets
|
||||
{t('pages.contact.sections.first.title')}
|
||||
</h1>
|
||||
<p className="text-center text-sm">
|
||||
We are here to assist you with any inquiries,
|
||||
bespoke design requests, or partnership
|
||||
opportunities. <br /> Reach out to our team through
|
||||
our offices or the contact form below.
|
||||
{t('pages.contact.sections.first.subTitle')} <br />{' '}
|
||||
{t('pages.contact.sections.first.subTitle2')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-8">
|
||||
<h2 className="text-center font-serif text-3xl font-medium tracking-tight">
|
||||
Our Global Offices
|
||||
{t('pages.contact.sections.second.title')}
|
||||
</h2>
|
||||
<div className="flex items-start justify-center gap-24 max-md:flex-col max-md:gap-12">
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="font-serif text-xl font-medium tracking-tight">
|
||||
Soorya Carpet Industries
|
||||
{t(
|
||||
'pages.contact.sections.second.soorya.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
Our global presence to serve you better.
|
||||
{t(
|
||||
'pages.contact.sections.second.soorya.subTitle',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ul className="flex flex-col gap-2">
|
||||
<li className="flex items-center gap-2 text-sm">
|
||||
<MapPin size={16} /> G.P.O Box 1765 2
|
||||
Swet Binayak Marg Thapathali -11,
|
||||
Kathmandu, Nepal
|
||||
<MapPin size={16} />{' '}
|
||||
{t(
|
||||
'pages.contact.sections.second.soorya.address',
|
||||
)}
|
||||
</li>{' '}
|
||||
<li className="flex items-center gap-2 text-sm">
|
||||
<Phone size={16} /> [+977-1] 4780923,
|
||||
4783003
|
||||
<Phone size={16} />{' '}
|
||||
{t(
|
||||
'pages.contact.sections.second.soorya.phone',
|
||||
)}
|
||||
</li>{' '}
|
||||
<li className="flex items-center gap-2 text-sm">
|
||||
<Mail size={16} />{' '}
|
||||
sooryacarpets@gmail.com
|
||||
{t(
|
||||
'pages.contact.sections.second.soorya.email',
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="font-serif text-xl font-medium tracking-tight">
|
||||
Kaleen Studio
|
||||
{t(
|
||||
'pages.contact.sections.second.kaleen.title',
|
||||
)}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
Our global presence to serve you better.
|
||||
{t(
|
||||
'pages.contact.sections.second.kaleen.subTitle',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ul className="flex flex-col gap-2">
|
||||
<li className="flex items-center gap-2 text-sm">
|
||||
<MapPin size={16} /> Kadel Chautari
|
||||
Prasuti Griha Marg Ward No. 11,
|
||||
Babarmahal Kathmandu, Nepal
|
||||
<MapPin size={16} />{' '}
|
||||
{t(
|
||||
'pages.contact.sections.second.kaleen.address',
|
||||
)}
|
||||
</li>{' '}
|
||||
<li className="flex items-center gap-2 text-sm">
|
||||
<Phone size={16} /> 9802341880
|
||||
<Phone size={16} />{' '}
|
||||
{t(
|
||||
'pages.contact.sections.second.kaleen.phone',
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
<a
|
||||
@@ -90,7 +107,9 @@ export default function Contact() {
|
||||
className="w-full cursor-pointer border border-primary text-primary ring-primary"
|
||||
variant={'outline'}
|
||||
>
|
||||
Visit Studio
|
||||
{t(
|
||||
'pages.contact.sections.second.kaleen.button',
|
||||
)}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
@@ -100,36 +119,55 @@ export default function Contact() {
|
||||
<div className="mx-auto flex w-full max-w-3xl flex-col gap-8 py-12">
|
||||
<div className="flex flex-col gap-1">
|
||||
<h3 className="font-serif text-3xl font-medium">
|
||||
Send us a Message
|
||||
{t('pages.contact.sections.third.title')}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-500">
|
||||
Fill out the form below and we'll get back to
|
||||
you as soon as possible.
|
||||
{t('pages.contact.sections.third.subTitle')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Form action={'/'} className="flex flex-col gap-2">
|
||||
<div>
|
||||
<Label htmlFor="name">Name</Label>
|
||||
<Label htmlFor="name">
|
||||
{t(
|
||||
'pages.contact.sections.third.form.name.label',
|
||||
)}
|
||||
</Label>
|
||||
<Input
|
||||
placeholder="Full Name"
|
||||
placeholder={t(
|
||||
'pages.contact.sections.third.form.name.input',
|
||||
)}
|
||||
id="name"
|
||||
name="name"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Label htmlFor="email">
|
||||
{t(
|
||||
'pages.contact.sections.third.form.email.label',
|
||||
)}
|
||||
</Label>
|
||||
<Input
|
||||
placeholder="your.email@example.com"
|
||||
placeholder={t(
|
||||
'pages.contact.sections.third.form.email.input',
|
||||
)}
|
||||
id="email"
|
||||
name="email"
|
||||
/>
|
||||
</div>{' '}
|
||||
<div>
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Label htmlFor="email">
|
||||
{t(
|
||||
'pages.contact.sections.third.form.inquiry.label',
|
||||
)}
|
||||
</Label>
|
||||
<Select>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Select an inquiry type" />
|
||||
<SelectValue
|
||||
placeholder={t(
|
||||
'pages.contact.sections.third.form.inquiry.input',
|
||||
)}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="problem">
|
||||
@@ -142,31 +180,38 @@ export default function Contact() {
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="message">Message</Label>
|
||||
<Label htmlFor="message">
|
||||
{t(
|
||||
'pages.contact.sections.third.form.message.label',
|
||||
)}
|
||||
</Label>
|
||||
<Textarea
|
||||
id="message"
|
||||
placeholder="Tell us how can we help you"
|
||||
placeholder={t(
|
||||
'pages.contact.sections.third.form.message.input',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Button type="submit" className="my-4">
|
||||
Send Message
|
||||
{t('pages.contact.sections.third.form.button')}
|
||||
</Button>
|
||||
</Form>
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-8">
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<h4 className="text-center font-serif text-3xl font-medium tracking-tight">
|
||||
Direct Engagement
|
||||
{t('pages.contact.sections.fourth.title')}
|
||||
</h4>
|
||||
<p className="text-center text-sm text-gray-500">
|
||||
Prefer to speak with us directly or send a quick
|
||||
email? <br /> Our team is ready to assist.
|
||||
{t('pages.contact.sections.fourth.desc')} <br />{' '}
|
||||
{t('pages.contact.sections.fourth.desc2')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<a href="tel:9802341880">
|
||||
<Button className="cursor-pointer">
|
||||
<Phone /> Call Us Now
|
||||
<Phone />{' '}
|
||||
{t('pages.contact.sections.fourth.callBtn')}
|
||||
</Button>
|
||||
</a>
|
||||
<a href="mailto:info@soory.com">
|
||||
@@ -174,7 +219,10 @@ export default function Contact() {
|
||||
variant={'outline'}
|
||||
className="cursor-pointer border border-primary text-primary ring-primary"
|
||||
>
|
||||
<Mail /> Email Our Team
|
||||
<Mail />{' '}
|
||||
{t(
|
||||
'pages.contact.sections.fourth.emailBtn',
|
||||
)}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -7,13 +7,14 @@ import FilePondPluginImageExifOrientation from 'filepond-plugin-image-exif-orien
|
||||
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
|
||||
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
|
||||
import 'filepond/dist/filepond.min.css';
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FilePond, registerPlugin } from 'react-filepond';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
registerPlugin(FilePondPluginImageExifOrientation, FilePondPluginImagePreview);
|
||||
|
||||
export default function CarouselAdd() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [file, setFile] = useState<any | null>(null);
|
||||
|
||||
const { data, setData, post, processing, errors, wasSuccessful } = useForm({
|
||||
@@ -21,12 +22,14 @@ export default function CarouselAdd() {
|
||||
image_url: null as File | null,
|
||||
});
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
useEffect(() => {
|
||||
if (file) {
|
||||
setData('image_url', file.file);
|
||||
}
|
||||
}, [file, setData]);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
post('/carousel', {
|
||||
forceFormData: true,
|
||||
@@ -72,7 +75,7 @@ export default function CarouselAdd() {
|
||||
}}
|
||||
allowMultiple={false}
|
||||
maxFiles={1}
|
||||
name="image_url" // Change this to match your backend expectation
|
||||
name="image_url"
|
||||
instantUpload={false}
|
||||
storeAsFile={true}
|
||||
labelIdle='Drag & Drop your image or <span class="filepond--label-action">Browse</span>'
|
||||
@@ -84,7 +87,11 @@ export default function CarouselAdd() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Button type="submit" disabled={processing}>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={processing}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
{processing ? 'Uploading...' : 'Submit'}
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
@@ -31,7 +31,9 @@ export default function Carousel({
|
||||
Carousel
|
||||
</h1>
|
||||
<Link href={dashboardcarousel.add()}>
|
||||
<Button>Add Image</Button>
|
||||
<Button className="cursor-pointer">
|
||||
Add Image
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<Table>
|
||||
|
||||
162
resources/js/pages/dashboard/products/add.tsx
Normal file
162
resources/js/pages/dashboard/products/add.tsx
Normal file
@@ -0,0 +1,162 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import AppLayout from '@/layouts/app-layout';
|
||||
import dashboard from '@/routes/dashboard';
|
||||
import { Head, useForm } from '@inertiajs/react';
|
||||
import FilePondPluginImageExifOrientation from 'filepond-plugin-image-exif-orientation';
|
||||
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
|
||||
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
|
||||
import 'filepond/dist/filepond.min.css';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FilePond, registerPlugin } from 'react-filepond';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
registerPlugin(FilePondPluginImageExifOrientation, FilePondPluginImagePreview);
|
||||
|
||||
export default function CarouselAdd() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [file, setFile] = useState<any | null>(null);
|
||||
// const [type, setType] = useState<string>('traditional');
|
||||
|
||||
const { data, setData, post, processing, errors, wasSuccessful } = useForm({
|
||||
title: '',
|
||||
type: 'traditional',
|
||||
image_url: null as File | null,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (file) {
|
||||
setData('image_url', file.file);
|
||||
}
|
||||
}, [file, setData]);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
post(dashboard.product.add().url, {
|
||||
forceFormData: true,
|
||||
});
|
||||
|
||||
if (wasSuccessful) {
|
||||
toast.success('Product added successfully');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<AppLayout>
|
||||
<Head title="Add Product Image" />
|
||||
<section className="flex flex-col gap-8 px-8 py-8">
|
||||
<h1 className="text-lg font-semibold tracking-tight">
|
||||
Add Product Image
|
||||
</h1>
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
method="POST"
|
||||
encType="multipart/formdata"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<Label htmlFor="title">Title</Label>
|
||||
<Input
|
||||
type="text"
|
||||
id="title"
|
||||
value={data.title}
|
||||
onChange={(e) =>
|
||||
setData('title', e.target.value)
|
||||
}
|
||||
className="rounded border p-2"
|
||||
/>
|
||||
{errors.title && (
|
||||
<span className="text-red-600">
|
||||
{errors.title}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<Label htmlFor="title">Type</Label>
|
||||
<Select
|
||||
value={data.type}
|
||||
onValueChange={(e) => {
|
||||
console.log(e);
|
||||
setData('type', e);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a type" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="traditional">
|
||||
Traditional
|
||||
</SelectItem>
|
||||
<SelectItem value="modern">
|
||||
Modern
|
||||
</SelectItem>
|
||||
<SelectItem value="bespoke">
|
||||
Bespoke
|
||||
</SelectItem>
|
||||
<SelectItem value="abstract">
|
||||
Abstract
|
||||
</SelectItem>
|
||||
<SelectItem value="art">
|
||||
Art in carpet
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{/* <Input
|
||||
type="text"
|
||||
id="title"
|
||||
value={data.alt}
|
||||
onChange={(e) => setData('alt', e.target.value)}
|
||||
className="rounded border p-2"
|
||||
/>
|
||||
{errors.alt && (
|
||||
<span className="text-red-600">{errors.alt}</span>
|
||||
)} */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<Label>Image</Label>
|
||||
<FilePond
|
||||
files={file ? [file] : []}
|
||||
onupdatefiles={(fileItems) => {
|
||||
setFile(fileItems[0] || null);
|
||||
}}
|
||||
allowMultiple={false}
|
||||
maxFiles={1}
|
||||
name="image_url"
|
||||
instantUpload={false}
|
||||
storeAsFile={true}
|
||||
labelIdle='Drag & Drop your image or <span class="filepond--label-action">Browse</span>'
|
||||
/>
|
||||
{errors.image_url && (
|
||||
<span className="text-red-600">
|
||||
{errors.image_url}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={processing}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
{processing ? 'Uploading...' : 'Submit'}
|
||||
</Button>
|
||||
</form>
|
||||
</section>
|
||||
</AppLayout>
|
||||
);
|
||||
}
|
||||
0
resources/js/pages/dashboard/products/edit.tsx
Normal file
0
resources/js/pages/dashboard/products/edit.tsx
Normal file
82
resources/js/pages/dashboard/products/index.tsx
Normal file
82
resources/js/pages/dashboard/products/index.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import AppLayout from '@/layouts/app-layout';
|
||||
import dashboard from '@/routes/dashboard';
|
||||
import { Head, Link } from '@inertiajs/react';
|
||||
import { Pencil, Trash2 } from 'lucide-react';
|
||||
|
||||
export default function Product({
|
||||
product,
|
||||
}: {
|
||||
product: [{ title: string; type: string; image_url: string }];
|
||||
}) {
|
||||
return (
|
||||
<AppLayout
|
||||
breadcrumbs={[
|
||||
{ title: 'Products', href: dashboard.product.index().url },
|
||||
]}
|
||||
>
|
||||
<Head title="Products" />
|
||||
|
||||
<section className="flex flex-col gap-8 px-8 py-8">
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-xl font-semibold tracking-tight">
|
||||
Products
|
||||
</h1>
|
||||
<Link href={dashboard.product.add()}>
|
||||
<Button className="cursor-pointer">Add Image</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[80px]">S.N.</TableHead>
|
||||
<TableHead className="w-48">Image</TableHead>
|
||||
<TableHead>Title</TableHead>
|
||||
<TableHead className="w-24">Type</TableHead>
|
||||
<TableHead className="text-right">Action</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{product.map((item, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell className="font-medium">
|
||||
{index + 1}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<img
|
||||
src={item.image_url}
|
||||
alt={item.title}
|
||||
className="aspect-video w-24 rounded-md object-cover object-center"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>{item.title}</TableCell>
|
||||
<TableCell>{item.type}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<Link href="">
|
||||
<Pencil size={18} />
|
||||
</Link>
|
||||
<Link href="">
|
||||
<Trash2
|
||||
size={18}
|
||||
color={'#D2042D'}
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</section>
|
||||
</AppLayout>
|
||||
);
|
||||
}
|
||||
@@ -1,16 +1,82 @@
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import AppLayout from '@/layouts/app-layout';
|
||||
import testimonial from '@/routes/testimonial';
|
||||
import { Head } from '@inertiajs/react';
|
||||
import { index } from '@/routes/testimonial';
|
||||
import { Head, Link } from '@inertiajs/react';
|
||||
import { Pencil, Trash2 } from 'lucide-react';
|
||||
|
||||
export default function Testimonial() {
|
||||
export default function Testimonial({
|
||||
testimonial,
|
||||
}: {
|
||||
testimonial: [
|
||||
{ name: string; description: string; location: string; image: string },
|
||||
];
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<AppLayout
|
||||
breadcrumbs={[
|
||||
{ title: 'testimonial', href: testimonial.index().url },
|
||||
]}
|
||||
breadcrumbs={[{ title: 'Testimonial', href: index().url }]}
|
||||
>
|
||||
<Head title={'Testimonials'}></Head>
|
||||
<section className="flex flex-col gap-8 px-8 py-8">
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-xl font-semibold tracking-tight">
|
||||
Testimonial
|
||||
</h1>
|
||||
</div>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[80px]">S.N.</TableHead>
|
||||
<TableHead className="w-48">Image</TableHead>
|
||||
<TableHead>Name</TableHead>
|
||||
<TableHead>Location</TableHead>
|
||||
<TableHead>Description</TableHead>
|
||||
<TableHead className="text-right">
|
||||
Action
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{testimonial.map((item, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell className="font-medium">
|
||||
{index + 1}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<img
|
||||
src={item.image}
|
||||
alt={item.name}
|
||||
className="aspect-video w-24 rounded-md object-cover object-center"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>{item.name}</TableCell>
|
||||
<TableCell>{item.location}</TableCell>
|
||||
<TableCell>{item.description}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<Link href="">
|
||||
<Pencil size={18} />
|
||||
</Link>
|
||||
<Link href="">
|
||||
<Trash2
|
||||
size={18}
|
||||
color={'#D2042D'}
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</section>
|
||||
</AppLayout>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -7,6 +7,10 @@ import {
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import { contact } from '@/routes';
|
||||
import img1 from '@asset/img/Bespoke/bes 5.jpg';
|
||||
import img4 from '@asset/img/Bespoke/Ree 6.jpg';
|
||||
import img3 from '@asset/img/Bespoke/Shrek.jpg';
|
||||
import img2 from '@asset/img/Bespoke/Swarovsky embedded wall hang.jpg';
|
||||
import { Head, Link } from '@inertiajs/react';
|
||||
|
||||
export default function Faq() {
|
||||
@@ -14,8 +18,8 @@ export default function Faq() {
|
||||
<>
|
||||
<Layout>
|
||||
<Head title="FAQs" />
|
||||
<section className="mx-auto flex max-w-screen-2xl gap-32 px-12 py-8">
|
||||
<div className="flex flex-col gap-4">
|
||||
<section className="mx-auto grid max-w-screen-2xl grid-cols-12 gap-32 px-12 py-8 max-sm:grid-cols-1 max-sm:gap-8 max-sm:px-8">
|
||||
<div className="col-span-4 flex flex-col items-start gap-4">
|
||||
<div>
|
||||
<h1 className="font-serif text-4xl font-medium tracking-tight">
|
||||
Frequently Asked Questions
|
||||
@@ -30,50 +34,51 @@ export default function Faq() {
|
||||
Contact Now
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<div className="mt-8 grid grid-cols-2 gap-2 max-sm:mt-2 max-sm:hidden">
|
||||
<div className="flex flex-col gap-2">
|
||||
<img
|
||||
src={img1}
|
||||
alt="Image 1"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
<img
|
||||
src={img4}
|
||||
alt="Image 4"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-8 flex flex-col gap-2">
|
||||
<img
|
||||
src={img2}
|
||||
alt="Image 2"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
<img
|
||||
src={img3}
|
||||
alt="Image 3"
|
||||
className="rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<div className="col-span-8 w-full">
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
className="w-full"
|
||||
defaultValue="item-1"
|
||||
>
|
||||
<AccordionItem value="item-1">
|
||||
<AccordionTrigger className="w-full">
|
||||
Is it accessible?
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It adheres to the WAI-ARIA design
|
||||
pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>{' '}
|
||||
<AccordionItem value="item-2">
|
||||
<AccordionTrigger className="w-full">
|
||||
Is it accessible?
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It adheres to the WAI-ARIA design
|
||||
pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>{' '}
|
||||
<AccordionItem value="item-3">
|
||||
<AccordionTrigger className="w-full">
|
||||
Is it accessible?
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It adheres to the WAI-ARIA design
|
||||
pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>{' '}
|
||||
<AccordionItem value="item-4">
|
||||
<AccordionTrigger className="w-full">
|
||||
Is it accessible?
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It adheres to the WAI-ARIA design
|
||||
pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
{faq.map((item) => (
|
||||
<AccordionItem value={`${item.id}`}>
|
||||
<AccordionTrigger className="w-full">
|
||||
{item?.question}
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="px-2 text-gray-600">
|
||||
{item?.answer}
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,29 +1,113 @@
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import { Head } from '@inertiajs/react';
|
||||
|
||||
export default function Product() {
|
||||
export default function Product({
|
||||
product,
|
||||
}: {
|
||||
product: [{ title: string; type: string; image_url: string }];
|
||||
}) {
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<Layout>
|
||||
<Head title="Our Products" />
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-12 py-8">
|
||||
<h1 className="font-serif text-5xl font-medium tracking-tight">
|
||||
Our Exquisite Collections
|
||||
{t('pages.product.sections.first.title')}
|
||||
</h1>
|
||||
<Tabs defaultValue="account" className="w-[400px]">
|
||||
<TabsList>
|
||||
<TabsTrigger value="account">Account</TabsTrigger>
|
||||
<TabsTrigger value="password">Password</TabsTrigger>
|
||||
<Tabs
|
||||
defaultValue="traditional"
|
||||
className="flex flex-col gap-8"
|
||||
>
|
||||
<TabsList className="flex items-center gap-4 bg-transparent">
|
||||
<TabsTrigger
|
||||
value="traditional"
|
||||
className="!h-auto cursor-pointer px-4 py-2 data-[state=active]:bg-primary data-[state=active]:text-white"
|
||||
>
|
||||
{t('pages.product.sections.first.tab1')}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="modern"
|
||||
className="!h-auto cursor-pointer px-4 py-2 data-[state=active]:bg-primary data-[state=active]:text-white"
|
||||
>
|
||||
{t('pages.product.sections.first.tab2')}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="abstract"
|
||||
className="!h-auto cursor-pointer px-4 py-2 data-[state=active]:bg-primary data-[state=active]:text-white"
|
||||
>
|
||||
{t('pages.product.sections.first.tab3')}
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="account">
|
||||
Make changes to your account here.
|
||||
<TabsContent value="traditional">
|
||||
<div className="grid grid-cols-4 gap-6 max-md:grid-cols-3 max-sm:grid-cols-2 max-sm:gap-4">
|
||||
{product.map((e, index) =>
|
||||
e.type === 'traditional' ? (
|
||||
<img
|
||||
key={index}
|
||||
src={e.image_url}
|
||||
alt={e.title}
|
||||
className="aspect-video rounded-md object-cover object-center"
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="password">
|
||||
Change your password here.
|
||||
<TabsContent value="modern">
|
||||
<div className="grid grid-cols-4 gap-6 max-md:grid-cols-3 max-sm:grid-cols-2 max-sm:gap-4">
|
||||
{product.map((e, index) =>
|
||||
e.type === 'modern' ? (
|
||||
<img
|
||||
key={index}
|
||||
src={e.image_url}
|
||||
alt={e.title}
|
||||
className="aspect-video rounded-md object-cover object-center"
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="abstract">
|
||||
<div className="grid grid-cols-4 gap-6 max-md:grid-cols-3 max-sm:grid-cols-2 max-sm:gap-4">
|
||||
{product.map((e, index) =>
|
||||
e.type === 'abstract' ? (
|
||||
<img
|
||||
key={index}
|
||||
src={e.image_url}
|
||||
alt={e.title}
|
||||
className="aspect-video rounded-md object-cover object-center"
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
</div>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</section>
|
||||
|
||||
<section className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-12 py-8 max-md:px-8">
|
||||
<div className="flex flex-col gap-2">
|
||||
<h2 className="font-serif text-3xl font-medium tracking-tight">
|
||||
{t('pages.product.sections.second.title')}
|
||||
</h2>
|
||||
<p className="text-gray-500">
|
||||
{t('pages.product.sections.second.desc')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 gap-6 max-md:grid-cols-3 max-sm:grid-cols-2 max-sm:gap-4">
|
||||
{product.map((e, index) =>
|
||||
e.type === 'art' ? (
|
||||
<img
|
||||
key={index}
|
||||
src={e.image_url}
|
||||
alt={e.title}
|
||||
className="aspect-video rounded-md object-cover object-center"
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Swiper, Testimonial } from '@/components/pages/Home';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Layout from '@/layouts/client/layout';
|
||||
import { about } from '@/routes';
|
||||
import { about, artOfWeaving } from '@/routes';
|
||||
import { useTranslations } from '@/utils/i18n';
|
||||
import artofWeaving from '@asset/img/carpet/IMG_1301.jpg';
|
||||
import kaleenCarpet from '@asset/img/carpet/IMG_3401.jpg';
|
||||
import sooryaCarpet from '@asset/img/carpet/sci trad 31.jpg';
|
||||
@@ -11,8 +12,19 @@ import { MoveRight } from 'lucide-react';
|
||||
export default function Welcome({
|
||||
data,
|
||||
}: {
|
||||
data: { carousel: [{ image_url: string; alt: string }] };
|
||||
data: {
|
||||
carousel: [{ image_url: string; alt: string }];
|
||||
testimonial: [
|
||||
{
|
||||
name: string;
|
||||
location: string;
|
||||
image: string;
|
||||
description: string;
|
||||
},
|
||||
];
|
||||
};
|
||||
}) {
|
||||
const { t } = useTranslations();
|
||||
return (
|
||||
<>
|
||||
<Head title="Premium Hand Knotted Carpets in Nepal">
|
||||
@@ -38,13 +50,10 @@ export default function Welcome({
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
<h2 className="font-serif text-3xl font-medium">
|
||||
Soorya Carpet
|
||||
{t('pages.home.sections.first.title')}
|
||||
</h2>
|
||||
<p className="text-gray-500">
|
||||
Discover the journey of Kaleen Carpets, a
|
||||
testament to enduring craftsmanship,
|
||||
innovative design, and a commitment to
|
||||
enriching lives through beautiful artistry.
|
||||
{t('pages.home.sections.first.desc')}
|
||||
</p>
|
||||
</div>
|
||||
<Link href={about()}>
|
||||
@@ -52,7 +61,8 @@ export default function Welcome({
|
||||
variant={'outline'}
|
||||
className="w-fit cursor-pointer border border-primary bg-transparent font-serif ring-primary"
|
||||
>
|
||||
Learn More <MoveRight />
|
||||
{t('pages.home.sections.first.button')}{' '}
|
||||
<MoveRight />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -61,21 +71,21 @@ export default function Welcome({
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
<h3 className="font-serif text-3xl font-medium">
|
||||
The Kaleen Rebrand
|
||||
{t('pages.home.sections.second.title')}
|
||||
</h3>
|
||||
<p className="text-gray-500">
|
||||
In 2015, Kaleen embarked on a transformative
|
||||
journey, evolving from a traditional
|
||||
manufacturer to a dynamic, luxury lifestyle
|
||||
brand.
|
||||
{t('pages.home.sections.second.desc')}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className="w-fit border border-primary bg-transparent font-serif ring-primary"
|
||||
>
|
||||
Learn More <MoveRight />
|
||||
</Button>
|
||||
<Link href={about()}>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className="w-fit cursor-pointer border border-primary bg-transparent font-serif ring-primary"
|
||||
>
|
||||
{t('pages.home.sections.second.button')}
|
||||
<MoveRight />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<img
|
||||
src={kaleenCarpet}
|
||||
@@ -92,24 +102,24 @@ export default function Welcome({
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
<h2 className="font-serif text-3xl font-medium">
|
||||
Art of Weaving
|
||||
{t('pages.home.sections.third.title')}
|
||||
</h2>
|
||||
<p className="text-gray-500">
|
||||
Since time immemorial, the art of carpet
|
||||
making has captured millions of carpet
|
||||
connoisseurs from around the world and still
|
||||
continues to do so.
|
||||
{t('pages.home.sections.third.desc')}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className="w-fit border border-primary bg-transparent font-serif ring-primary"
|
||||
>
|
||||
Learn More <MoveRight />
|
||||
</Button>
|
||||
<Link href={artOfWeaving()}>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className="w-fit cursor-pointer border border-primary bg-transparent font-serif ring-primary"
|
||||
>
|
||||
{t('pages.home.sections.third.button')}{' '}
|
||||
<MoveRight />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
<Testimonial />
|
||||
<Testimonial testimonial={data?.testimonial} />
|
||||
</div>
|
||||
</Layout>
|
||||
</>
|
||||
|
||||
90
resources/js/utils/i18n.ts
Normal file
90
resources/js/utils/i18n.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { usePage } from '@inertiajs/react';
|
||||
|
||||
// Type definitions for our translations
|
||||
interface Translations {
|
||||
nav: {
|
||||
'about-us': string;
|
||||
art: string;
|
||||
products: string;
|
||||
bespoke: string;
|
||||
faq: string;
|
||||
contact: string;
|
||||
};
|
||||
footer: {
|
||||
desc: {
|
||||
title: string;
|
||||
company: string;
|
||||
address: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
};
|
||||
// Add other translation sections as needed
|
||||
};
|
||||
}
|
||||
|
||||
interface PageProps {
|
||||
locale: string;
|
||||
translations: Translations;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translation function
|
||||
*/
|
||||
export function t(
|
||||
translations: any,
|
||||
key: string,
|
||||
replacements: Record<string, string> = {},
|
||||
): string {
|
||||
if (!translations) {
|
||||
console.warn('No translations provided');
|
||||
return key;
|
||||
}
|
||||
|
||||
const keys = key.split('.');
|
||||
let value: any = translations;
|
||||
|
||||
for (const k of keys) {
|
||||
if (value && typeof value === 'object' && k in value) {
|
||||
value = value[k];
|
||||
} else {
|
||||
console.warn(`Translation key not found: ${key}`);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
return key;
|
||||
}
|
||||
|
||||
let text = value;
|
||||
Object.entries(replacements).forEach(([k, v]) => {
|
||||
text = text.replace(new RegExp(`:${k}`, 'g'), v);
|
||||
});
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* React hook for translations
|
||||
*/
|
||||
export function useTranslations() {
|
||||
const { translations } = usePage<PageProps>().props;
|
||||
|
||||
const translate = (
|
||||
key: string,
|
||||
replacements: Record<string, string> = {},
|
||||
) => {
|
||||
return t(translations, key, replacements);
|
||||
};
|
||||
|
||||
return { t: translate, translations };
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to get current locale
|
||||
*/
|
||||
export function useLocale() {
|
||||
const { locale } = usePage<PageProps>().props;
|
||||
return locale;
|
||||
}
|
||||
Reference in New Issue
Block a user