add: bottom nav bar
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
"use client";
|
||||
|
||||
import { ReactQueryProvider } from '@/components/providers/ReactQueryProvider'
|
||||
|
||||
|
||||
@@ -117,7 +117,6 @@ function AuthIndex({ }: Props) {
|
||||
};
|
||||
|
||||
const onSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
console.log(step);
|
||||
e.preventDefault();
|
||||
try {
|
||||
setIsPending(true);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
--color-disabled-text: #8C90A3;
|
||||
--radius-normal: 10px;
|
||||
--text-sm2: 13px;
|
||||
--text-xs2: 10px;
|
||||
--radius-container: 24px;
|
||||
}
|
||||
|
||||
|
||||
+7
-5
@@ -1,20 +1,22 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
title: 'Dashboard',
|
||||
description: 'Webapp dashboard'
|
||||
}
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
|
||||
return (
|
||||
|
||||
<html lang="en">
|
||||
<body
|
||||
className={`antialiased`}
|
||||
className={`antialiased bg-background h-full`}
|
||||
>
|
||||
{children}
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import BottomNavBar from "@/components/navigation/BottomNavBar";
|
||||
import { ReactQueryProvider } from "@/components/providers/ReactQueryProvider";
|
||||
|
||||
export const metadata = {
|
||||
title: 'Menu',
|
||||
}
|
||||
|
||||
export default function MenuLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
|
||||
return (
|
||||
<ReactQueryProvider>
|
||||
<main className="h-full pb-0">
|
||||
{children}
|
||||
</main>
|
||||
<BottomNavBar />
|
||||
</ReactQueryProvider>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
'use client';
|
||||
|
||||
export default function MenuIndex() {
|
||||
|
||||
return (
|
||||
<>
|
||||
Menu
|
||||
</>
|
||||
);
|
||||
}
|
||||
+4
-111
@@ -1,118 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { useAuthStore } from "@/zustand/authStore";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Home() {
|
||||
|
||||
const logout = useAuthStore((state) => state.logout);
|
||||
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
||||
|
||||
return (
|
||||
<div className="grid font-sans grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20">
|
||||
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
|
||||
{!isAuthenticated && <Link href={"/auth"}>Login</Link>}
|
||||
{isAuthenticated &&
|
||||
<div>
|
||||
{/* <Link href={"/profile"}>Profile</Link>
|
||||
<br /> */}
|
||||
<Link href={""} onClick={logout}>Logout</Link>
|
||||
</div>}
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={180}
|
||||
height={38}
|
||||
priority
|
||||
/>
|
||||
<ol className="list-inside list-decimal text-sm/6 text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
|
||||
<li className="mb-2 tracking-[-.01em]">
|
||||
Get started by editing{" "}
|
||||
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-[family-name:var(--font-geist-mono)] font-semibold">
|
||||
src/app/page.tsx
|
||||
</code>
|
||||
.
|
||||
</li>
|
||||
<li className="tracking-[-.01em]">
|
||||
Save and see your changes instantly.
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div className="flex gap-4 items-center flex-col sm:flex-row">
|
||||
<a
|
||||
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={20}
|
||||
height={20}
|
||||
/>
|
||||
Deploy now
|
||||
</a>
|
||||
<a
|
||||
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Read our docs
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
<footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/file.svg"
|
||||
alt="File icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Learn
|
||||
</a>
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/window.svg"
|
||||
alt="Window icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Examples
|
||||
</a>
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/globe.svg"
|
||||
alt="Globe icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Go to nextjs.org →
|
||||
</a>
|
||||
</footer>
|
||||
<div>
|
||||
<Link href={'/auth'}>Auth</Link><br/>
|
||||
<Link href={'/menu'}>Menu</Link><br/>
|
||||
<Link href={'/'}>Index</Link><br/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import React from "react";
|
||||
|
||||
type Props = React.SVGProps<SVGSVGElement>;
|
||||
|
||||
const BagIcon = (props: Props) => (
|
||||
<svg
|
||||
width={24}
|
||||
height={24}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M7.5 7.67001V6.70001C7.5 4.45001 9.31 2.24001 11.56 2.03001C14.24 1.77001 16.5 3.88001 16.5 6.51001V7.89001"
|
||||
stroke="#7F7F7F"
|
||||
strokeWidth={1.5}
|
||||
strokeMiterlimit={10}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M8.99983 22H14.9998C19.0198 22 19.7398 20.39 19.9498 18.43L20.6998 12.43C20.9698 9.99 20.2698 8 15.9998 8H7.99983C3.72983 8 3.02983 9.99 3.29983 12.43L4.04983 18.43C4.25983 20.39 4.97983 22 8.99983 22Z"
|
||||
stroke="#7F7F7F"
|
||||
strokeWidth={1.5}
|
||||
strokeMiterlimit={10}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default BagIcon;
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from "react";
|
||||
|
||||
type Props = React.SVGProps<SVGSVGElement>;
|
||||
|
||||
const HeartIcon = (props: Props) => (
|
||||
<svg
|
||||
width={24}
|
||||
height={24}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M12.62 20.8101C12.28 20.9301 11.72 20.9301 11.38 20.8101C8.48 19.8201 2 15.6901 2 8.6901C2 5.6001 4.49 3.1001 7.56 3.1001C9.38 3.1001 10.99 3.9801 12 5.3401C13.01 3.9801 14.63 3.1001 16.44 3.1001C19.51 3.1001 22 5.6001 22 8.6901C22 15.6901 15.52 19.8201 12.62 20.8101Z"
|
||||
stroke="#8C90A3"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default HeartIcon;
|
||||
@@ -0,0 +1,45 @@
|
||||
import React from "react";
|
||||
|
||||
type Props = React.SVGProps<SVGSVGElement>;
|
||||
|
||||
const HomeHashtagIcon = (props: Props) => (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M9.02 2.83992L3.63 7.03992C2.73 7.73992 2 9.22992 2 10.3599V17.7699C2 20.0899 3.89 21.9899 6.21 21.9899H17.79C20.11 21.9899 22 20.0899 22 17.7799V10.4999C22 9.28992 21.19 7.73992 20.2 7.04992L14.02 2.71992C12.62 1.73992 10.37 1.78992 9.02 2.83992Z"
|
||||
stroke="white"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M10.5 18H13.5C15.15 18 16.5 16.65 16.5 15V12C16.5 10.35 15.15 9 13.5 9H10.5C8.85 9 7.5 10.35 7.5 12V15C7.5 16.65 8.85 18 10.5 18Z"
|
||||
stroke="white"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M12 9V18"
|
||||
stroke="white"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M7.5 13.5H16.5"
|
||||
stroke="white"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default HomeHashtagIcon;
|
||||
@@ -0,0 +1,45 @@
|
||||
import React from "react";
|
||||
|
||||
type Props = React.SVGProps<SVGSVGElement>;
|
||||
|
||||
const NotifiBoardIcon = (props: Props) => (
|
||||
<svg
|
||||
width={24}
|
||||
height={24}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M19 8C20.6569 8 22 6.65685 22 5C22 3.34315 20.6569 2 19 2C17.3431 2 16 3.34315 16 5C16 6.65685 17.3431 8 19 8Z"
|
||||
stroke="#8C90A3"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M7 13H12"
|
||||
stroke="#8C90A3"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M7 17H16"
|
||||
stroke="#8C90A3"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M14 2H9C4 2 2 4 2 9V15C2 20 4 22 9 22H15C20 22 22 20 22 15V10"
|
||||
stroke="#8C90A3"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default NotifiBoardIcon;
|
||||
@@ -0,0 +1,45 @@
|
||||
import React from "react";
|
||||
|
||||
type Props = React.SVGProps<SVGSVGElement>;
|
||||
|
||||
const PagerIcon = (props: Props) => (
|
||||
<svg
|
||||
width={24}
|
||||
height={24}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M18.9702 22H4.97021C1.97021 22 1.97021 20.65 1.97021 19V18C1.97021 17.45 2.42021 17 2.97021 17H20.9702C21.5202 17 21.9702 17.45 21.9702 18V19C21.9702 20.65 21.9702 22 18.9702 22Z"
|
||||
stroke="#8C90A3"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M20.72 13V17H3.27002V13C3.27002 9.16 5.98002 5.95 9.59002 5.18C10.13 5.06 10.69 5 11.27 5H12.72C13.3 5 13.87 5.06 14.41 5.18C18.02 5.96 20.72 9.16 20.72 13Z"
|
||||
stroke="#8C90A3"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M14.5 4.5C14.5 4.74 14.47 4.96 14.41 5.18C13.87 5.06 13.3 5 12.72 5H11.27C10.69 5 10.13 5.06 9.59 5.18C9.53 4.96 9.5 4.74 9.5 4.5C9.5 3.12 10.62 2 12 2C13.38 2 14.5 3.12 14.5 4.5Z"
|
||||
stroke="#8C90A3"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M15 11H9"
|
||||
stroke="#8C90A3"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default PagerIcon;
|
||||
@@ -25,8 +25,8 @@ const LoadingOverlay = ({ visible = true, bgOpacity = 30, delay = 0, children =
|
||||
className={`absolute inset-0 flex items-center justify-center
|
||||
backdrop-blur-sm bg-background/${bgOpacity}
|
||||
opacity-0 transition-opacity duration-300 ease-in-out delay-${delay}
|
||||
data-[loaded=false]:-z-100
|
||||
data-[visible=true]:z-100
|
||||
data-[loaded=false]:-z-50
|
||||
data-[visible=true]:z-50
|
||||
data-[visible=true]:opacity-100`}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import React from 'react'
|
||||
import BottomNavLink from './BottomNavLink'
|
||||
import BottomNavHighlightLink from './BottomNavLinkBig'
|
||||
import HomeHashtagIcon from '../icons/HomeHashtagIcon'
|
||||
import PagerIcon from '../icons/PagerIcon'
|
||||
import NotifiBoardIcon from '../icons/NotifBoardIcon'
|
||||
import BagIcon from '../icons/BagIcon'
|
||||
import HeartIcon from '../icons/HeartIcon'
|
||||
|
||||
type Props = object
|
||||
|
||||
function BottomNavBar({ }: Props) {
|
||||
return (
|
||||
<div className="absolute bottom-0 left-0 w-full bg-transparent">
|
||||
<div className="max-w-md mx-auto w-full aspect-[436/104] relative z-40">
|
||||
<svg
|
||||
viewBox="0 0 436 104"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="w-full h-full block"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
>
|
||||
<g filter="url(#filter0_d_9095_18036)">
|
||||
<path
|
||||
d="M218 16C229.034 16 238.711 22.0313 244.148 31.0943C245.844 33.9222 248.724 36 252.022 36H406C414.837 36 422 43.1634 422 52V80C422 88.8366 414.837 96 406 96H30C21.1634 96 14 88.8366 14 80V52C14 43.1634 21.1634 36 30 36H183.979C187.277 36 190.157 33.9222 191.853 31.0943C197.29 22.0315 206.966 16.0001 218 16Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
|
||||
{/* 🔽 Your HTML content inside SVG */}
|
||||
<foreignObject x="0" y="10" width="100%" height="80">
|
||||
<div
|
||||
className="absolute z-20 w-full h-full px-2 grid grid-cols-5 gap-x-2 text-[10px] items-end"
|
||||
>
|
||||
<BottomNavLink href={'/auth'} icon={<HeartIcon />} value="پسند ها" />
|
||||
<BottomNavLink href={''} icon={<NotifiBoardIcon />} value="اعلان ها" />
|
||||
<BottomNavHighlightLink href={''} icon={<HomeHashtagIcon />} value="منو" />
|
||||
<BottomNavLink href={''} icon={<PagerIcon />} value="پیجر" />
|
||||
<BottomNavLink href={''} icon={<BagIcon />} value="سبد خرید" />
|
||||
</div>
|
||||
</foreignObject>
|
||||
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_d_9095_18036"
|
||||
x="0"
|
||||
y="0"
|
||||
width="100%"
|
||||
height="100%"
|
||||
filterUnits="userSpaceOnUse"
|
||||
colorInterpolationFilters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset dy="-2" />
|
||||
<feGaussianBlur stdDeviation="7" />
|
||||
<feComposite in2="hardAlpha" operator="out" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="BackgroundImageFix"
|
||||
result="effect1_dropShadow_9095_18036"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="effect1_dropShadow_9095_18036"
|
||||
result="shape"
|
||||
/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BottomNavBar
|
||||
@@ -0,0 +1,21 @@
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
import type { LinkProps } from 'next/link'
|
||||
|
||||
type Props = {
|
||||
icon: React.ReactElement
|
||||
value: string
|
||||
} & LinkProps & React.AnchorHTMLAttributes<HTMLAnchorElement>
|
||||
|
||||
function BottomNavLink({ icon, value, ...restProps }: Props) {
|
||||
return (
|
||||
<Link {...restProps} className={`flex flex-col justify-arround items-center gap-[5px] ${restProps.className ?? ''}`}>
|
||||
{icon}
|
||||
<span className='text-xs2 text-disabled-text'>
|
||||
{value}
|
||||
</span>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export default BottomNavLink
|
||||
@@ -0,0 +1,23 @@
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
import type { LinkProps } from 'next/link'
|
||||
|
||||
type Props = {
|
||||
icon: React.ReactElement
|
||||
value: string
|
||||
} & LinkProps & React.AnchorHTMLAttributes<HTMLAnchorElement>
|
||||
|
||||
function BottomNavHighlightLink({ icon, value, ...restProps }: Props) {
|
||||
return (
|
||||
<Link {...restProps} className={`flex flex-col relative justify-arround items-center gap-[5px] ${restProps.className ?? ''}`}>
|
||||
<div className='bg-primary p-3 rounded-full'>
|
||||
{icon}
|
||||
</div>
|
||||
<span className='text-xs2 text-disabled-text'>
|
||||
{value}
|
||||
</span>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export default BottomNavHighlightLink
|
||||
@@ -28,8 +28,6 @@ const processQueue = (error: unknown, token: string | null = null) => {
|
||||
// Attach access token to requests
|
||||
api.interceptors.request.use((config) => {
|
||||
const state = useAuthStore.getState();
|
||||
console.log('AuthStore state:', state);
|
||||
|
||||
const token = state.user?.accessToken;
|
||||
|
||||
if (token) {
|
||||
|
||||
Reference in New Issue
Block a user