mirror of
https://github.com/Nezumi-2711/multitenant-ecommerce.git
synced 2026-09-22 13:38:34 +00:00
Merge pull request #1 from Nezumi-2711/feat/implement-layout
Feature/ Implement the layout of the application
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
const AboutPage = () => {
|
||||||
|
return (
|
||||||
|
<div>AboutPage</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AboutPage
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
const ContactPage = () => {
|
||||||
|
return (
|
||||||
|
<div>Contact Page</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ContactPage
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
const FeaturesPage = () => {
|
||||||
|
return (
|
||||||
|
<div>FeaturesPage</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FeaturesPage
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
const Footer = () => {
|
||||||
|
return (
|
||||||
|
<footer className="flex border-t justify-between font-medium p-6">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<p>funroad, Inc.</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Footer
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
import Navbar from './navbar';
|
||||||
|
import Footer from './footer';
|
||||||
|
|
||||||
|
interface LayoutProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Layout = ({ children }: LayoutProps) => {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col min-h-screen">
|
||||||
|
<Navbar />
|
||||||
|
|
||||||
|
<div className="flex-1 bg-[#F4F4F0]">{children}</div>
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Layout;
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||||
|
import {
|
||||||
|
Sheet,
|
||||||
|
SheetContent,
|
||||||
|
SheetHeader,
|
||||||
|
SheetTitle,
|
||||||
|
} from '@/components/ui/sheet';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
interface NavbarItem {
|
||||||
|
href: string;
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
items: NavbarItem[];
|
||||||
|
open: boolean;
|
||||||
|
onOpenChange: (open: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NavbarSidebar = ({ items, open, onOpenChange }: Props) => {
|
||||||
|
return (
|
||||||
|
<Sheet open={open} onOpenChange={onOpenChange}>
|
||||||
|
<SheetContent side="left" className="p-0 transition-none">
|
||||||
|
<SheetHeader className="p-4 border-b">
|
||||||
|
<SheetTitle>Menu</SheetTitle>
|
||||||
|
</SheetHeader>
|
||||||
|
|
||||||
|
<ScrollArea className="flex flex-col overflow-y-auto h-full pb-2">
|
||||||
|
{items.map((item) => (
|
||||||
|
<Link
|
||||||
|
key={item.href}
|
||||||
|
href={item.href}
|
||||||
|
className="w-full text-left p-4 hover:bg-black hover:text-white flex items-center text-base font-medium"
|
||||||
|
onClick={() => onOpenChange(false)}
|
||||||
|
>
|
||||||
|
{item.children}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<div className="border-t">
|
||||||
|
<Link
|
||||||
|
href="/sign-in"
|
||||||
|
className="w-full text-left p-4 hover:bg-black hover:text-white flex items-center text-base font-medium"
|
||||||
|
onClick={() => onOpenChange(false)}
|
||||||
|
>
|
||||||
|
Log in
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
href="/sign-up"
|
||||||
|
className="w-full text-left p-4 hover:bg-black hover:text-white flex items-center text-base font-medium"
|
||||||
|
onClick={() => onOpenChange(false)}
|
||||||
|
>
|
||||||
|
Start Selling
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
</SheetContent>
|
||||||
|
</Sheet>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NavbarSidebar;
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { ReactNode, useState } from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { Poppins } from 'next/font/google';
|
||||||
|
import { MenuIcon } from 'lucide-react';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
|
||||||
|
import NavbarSidebar from './navbar-sidebar';
|
||||||
|
|
||||||
|
const poppins = Poppins({
|
||||||
|
subsets: ['latin'],
|
||||||
|
weight: ['700'],
|
||||||
|
});
|
||||||
|
|
||||||
|
interface NavbarItemProps {
|
||||||
|
href: string;
|
||||||
|
children: ReactNode;
|
||||||
|
isActive?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const navbarItems = [
|
||||||
|
{
|
||||||
|
href: '/',
|
||||||
|
children: 'Home',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
href: '/about',
|
||||||
|
children: 'About',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
href: '/features',
|
||||||
|
children: 'Features',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
href: '/pricing',
|
||||||
|
children: 'Pricing',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
href: '/contact',
|
||||||
|
children: 'Contact',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const NavbarItem = ({ href, children, isActive }: NavbarItemProps) => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
asChild
|
||||||
|
variant="outline"
|
||||||
|
className={cn(
|
||||||
|
'bg-transparent hover:bg-transparent rounded-full hover:border-primary border-transparent px-3.5 text-lg',
|
||||||
|
isActive && 'bg-black text-white hover:bg-black hover:text-white'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Link href={href}>{children}</Link>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Navbar = () => {
|
||||||
|
const pathname = usePathname();
|
||||||
|
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav className="h-20 flex border-b justify-between font-medium bg-white">
|
||||||
|
<Link href="/" className="pl-6 flex items-center">
|
||||||
|
<span className={cn('text-5xl font-semibold', poppins.className)}>
|
||||||
|
funroad
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<NavbarSidebar
|
||||||
|
items={navbarItems}
|
||||||
|
open={isSidebarOpen}
|
||||||
|
onOpenChange={setIsSidebarOpen}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="items-center gap-4 hidden lg:flex">
|
||||||
|
{navbarItems.map((item) => (
|
||||||
|
<NavbarItem
|
||||||
|
key={item.href}
|
||||||
|
href={item.href}
|
||||||
|
isActive={pathname === item.href}
|
||||||
|
>
|
||||||
|
{item.children}
|
||||||
|
</NavbarItem>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="hidden lg:flex">
|
||||||
|
<Button
|
||||||
|
asChild
|
||||||
|
variant="secondary"
|
||||||
|
className="border-l border-t-0 border-b-0 border-r-0 px-12 h-full rounded-none bg-white hover:bg-pink-400 transition-colors text-lg"
|
||||||
|
>
|
||||||
|
<Link href="/sign-in">Log in</Link>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
asChild
|
||||||
|
variant="secondary"
|
||||||
|
className="border-l border-t-0 border-b-0 border-r-0 px-12 h-full rounded-none bg-black text-white hover:bg-pink-400 hover:text-black transition-colors text-lg"
|
||||||
|
>
|
||||||
|
<Link href="/sign-up">Start Selling</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='flex lg:hidden items-center justify-center'>
|
||||||
|
<Button variant="ghost" className="size-12 border-transparent bg-white" onClick={() => setIsSidebarOpen(true)}>
|
||||||
|
<MenuIcon />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Navbar;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Home page
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
const PricingPage = () => {
|
||||||
|
return (
|
||||||
|
<div>PricingPage</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PricingPage
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { Button } from "@/components/ui/button";
|
|
||||||
|
|
||||||
export default function Home() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Button variant="elevated">Hello World</Button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -15,6 +15,7 @@ function Checkbox({
|
|||||||
data-slot="checkbox"
|
data-slot="checkbox"
|
||||||
className={cn(
|
className={cn(
|
||||||
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
"bg-white",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ function Progress({
|
|||||||
data-slot="progress"
|
data-slot="progress"
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative h-3 w-full overflow-hidden rounded-full",
|
"relative h-3 w-full overflow-hidden rounded-full",
|
||||||
"border bg-transparent",
|
"border bg-white",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
|||||||
<textarea
|
<textarea
|
||||||
data-slot="textarea"
|
data-slot="textarea"
|
||||||
className={cn(
|
className={cn(
|
||||||
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border px-3 py-2 text-base transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
"md:text-base",
|
"md:text-base bg-white",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
Reference in New Issue
Block a user