feat: New design and optimization

This commit is contained in:
2025-10-27 13:23:05 +05:45
parent 63777cb3c1
commit db9315ad22
44 changed files with 2877 additions and 336 deletions

View File

@@ -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>
</>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>
</>
);
}