feat: tab navigation
This commit is contained in:
27
web/src/components/Home/Sidebar/index.tsx
Normal file
27
web/src/components/Home/Sidebar/index.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import type { FC } from "react";
|
||||||
|
import { barItems } from "../tabs";
|
||||||
|
|
||||||
|
export interface ISidebarProps {
|
||||||
|
activeTab: string;
|
||||||
|
onChangeTab: (tab: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Sidebar: FC<ISidebarProps> = ({ activeTab, onChangeTab }) => {
|
||||||
|
return (
|
||||||
|
<div className="hidden sm:flex flex-col gap-2 items-stretch min-w-80 w-80 p-5 pt-18 min-h-screen select-none bg-white/65 dark:bg-black/65 shadow-lg shadow-gray-300 dark:shadow-gray-700">
|
||||||
|
{barItems.map((item) => (
|
||||||
|
<div
|
||||||
|
key={item.tab}
|
||||||
|
onClick={() => onChangeTab(item.tab)}
|
||||||
|
className={`dark:text-gray-200 transition-colors text-md cursor-pointer p-4 rounded-lg flex flex-row items-center gap-3${
|
||||||
|
item.tab === activeTab ? " bg-gray-200 dark:bg-gray-900" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{item.icon} {item.title}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Sidebar;
|
25
web/src/components/Home/Tabs/Home.tsx
Normal file
25
web/src/components/Home/Tabs/Home.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { type FC } from "react";
|
||||||
|
|
||||||
|
const Home: FC = () => {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center gap-2 p-7">
|
||||||
|
<div className="w-24 h-24 sm:w-36 sm:h-36 overflow-hidden rounded-full flex items-center justify-center bg-gray-300">
|
||||||
|
{/* <User size={64} /> */}
|
||||||
|
<img
|
||||||
|
className="w-full h-full"
|
||||||
|
src="http://192.168.178.69:9000/guard-storage/profile_eff00028-2d9e-458d-8944-677855edc147_1748099702417601900.jpg"
|
||||||
|
alt="profile pic"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<h1 className="dark:text-gray-200 text-gray-800 text-2xl select-none">
|
||||||
|
Welcome, Amir Adal
|
||||||
|
</h1>
|
||||||
|
<p className="text-gray-600 dark:text-gray-500 select-none text-center text-sm/normal sm:text-lg">
|
||||||
|
Manage your info, private and security to make Home Guard work better
|
||||||
|
for you.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Home;
|
66
web/src/components/Home/Tabs/PersonalInfo.tsx
Normal file
66
web/src/components/Home/Tabs/PersonalInfo.tsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { ChevronRight } from "lucide-react";
|
||||||
|
import { type FC } from "react";
|
||||||
|
|
||||||
|
const PersonalInfo: FC = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1 className="dark:text-gray-200 text-gray-800 text-2xl">
|
||||||
|
Your profile info in Home services
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p className="text-gray-500 text-sm mt-2 sm:text-lg">
|
||||||
|
Personal info and options to manage it. You can make some of this info,
|
||||||
|
like your contact details, visible to others so they can reach you
|
||||||
|
easily. You can also see a summary of your profiles.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="border dark:border-gray-800 border-gray-300 p-4 rounded mt-4">
|
||||||
|
<h3 className="dark:text-gray-300 text-gray-800">Basic info</h3>
|
||||||
|
<p className="text-gray-500 text-sm mt-2 mb-4">
|
||||||
|
Some info may be visible to other services and tools using Home Guard.{" "}
|
||||||
|
<a href="#" className="text-blue-500">
|
||||||
|
Learn more
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Profile Picture */}
|
||||||
|
<div className="flex flex-row items-center justify-between px-2 p-4 border-b gap-2 dark:border-b-gray-800 border-b-gray-100">
|
||||||
|
<div className="flex flex-col items-start gap-2">
|
||||||
|
<p className="text-sm dark:text-gray-400 font-medium text-gray-600">
|
||||||
|
Profile picture
|
||||||
|
</p>
|
||||||
|
<p className="text-sm dark:text-gray-500 text-gray-600">
|
||||||
|
Add a profile picture to personalize your account
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="w-16 h-16 overflow-hidden rounded-full dark:bg-gray-400 bg-gray-700">
|
||||||
|
<img
|
||||||
|
className="w-full h-full"
|
||||||
|
src="http://192.168.178.69:9000/guard-storage/profile_eff00028-2d9e-458d-8944-677855edc147_1748099702417601900.jpg"
|
||||||
|
alt="profile pic"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Name */}
|
||||||
|
<div className="flex flex-row items-center justify-between px-2 p-4 border-b dark:border-b-gray-800 border-b-gray-100">
|
||||||
|
<div className="flex flex-col items-start gap-2">
|
||||||
|
<p className="text-sm dark:text-gray-400 font-medium text-gray-600">
|
||||||
|
Name
|
||||||
|
</p>
|
||||||
|
<p className="text dark:text-gray-200 text-gray-800">Amir Adal</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="text-gray-500">
|
||||||
|
<ChevronRight size={26} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PersonalInfo;
|
29
web/src/components/Home/TopBar/index.tsx
Normal file
29
web/src/components/Home/TopBar/index.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { type FC } from "react";
|
||||||
|
import { barItems } from "../tabs";
|
||||||
|
|
||||||
|
export interface ITopBarProps {
|
||||||
|
activeTab: string;
|
||||||
|
onChangeTab: (tab: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TopBar: FC<ITopBarProps> = ({ activeTab, onChangeTab }) => {
|
||||||
|
return (
|
||||||
|
<div className="sm:hidden flex w-full overflow-x-auto sm:overflow-x-visible max-w-full min-w-full sm:justify-center sm:space-x-4 no-scrollbar shadow-md shadow-gray-300 dark:shadow-gray-700 dark:bg-black/70 bg-white/70 pt-14">
|
||||||
|
{barItems.map((item) => (
|
||||||
|
<div
|
||||||
|
key={item.tab}
|
||||||
|
onClick={() => onChangeTab(item.tab)}
|
||||||
|
className={`flex-shrink-0 transition-all border-b-4 px-4 py-2 min-w-[120px] sm:min-w-0 sm:flex-1 flex items-center justify-center cursor-pointer select-none whitespace-nowrap text-sm font-medium ${
|
||||||
|
item.tab === activeTab
|
||||||
|
? " border-b-4 border-b-blue-500 text-blue-500"
|
||||||
|
: " border-b-transparent text-gray-500"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{item.title}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TopBar;
|
19
web/src/components/Home/tabs.tsx
Normal file
19
web/src/components/Home/tabs.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { Home, Settings2, User } from "lucide-react";
|
||||||
|
|
||||||
|
export const barItems = [
|
||||||
|
{
|
||||||
|
icon: <Home />,
|
||||||
|
title: "Home",
|
||||||
|
tab: "home",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <User />,
|
||||||
|
title: "Personal Info",
|
||||||
|
tab: "personal-info",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <Settings2 />,
|
||||||
|
title: "Data & Personalization",
|
||||||
|
tab: "data-personalization",
|
||||||
|
},
|
||||||
|
];
|
@ -1,20 +1,24 @@
|
|||||||
import { type FC } from "react";
|
import { useState, type FC } from "react";
|
||||||
|
|
||||||
// import overlay from "@/assets/overlay.jpg";
|
// import overlay from "@/assets/overlay.jpg";
|
||||||
// import darkOverlay from "@/assets/dark-overlay.jpg";
|
// import darkOverlay from "@/assets/dark-overlay.jpg";
|
||||||
|
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import { ChevronDown, ChevronRight } from "lucide-react";
|
import { ChevronRight } from "lucide-react";
|
||||||
|
import Sidebar from "@/components/Home/Sidebar";
|
||||||
|
import TopBar from "@/components/Home/TopBar";
|
||||||
|
import Home from "@/components/Home/Tabs/Home";
|
||||||
|
import PersonalInfo from "@/components/Home/Tabs/PersonalInfo";
|
||||||
|
|
||||||
const IndexPage: FC = () => {
|
const IndexPage: FC = () => {
|
||||||
// console.log(overlay);
|
const [tab, setTab] = useState<string>("home");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`relative min-h-screen bg-cover bg-center bg-white dark:bg-black bg-[url(/overlay.jpg)] dark:bg-[url(/dark-overlay.jpg)]`}
|
className={`relative min-h-screen bg-cover bg-center bg-white dark:bg-black bg-[url(/overlay.jpg)] dark:bg-[url(/dark-overlay.jpg)]`}
|
||||||
// style={{ backgroundImage: `url(${overlay})` }}
|
|
||||||
>
|
>
|
||||||
<div className="relative z-10 flex items-center justify-center min-h-screen">
|
<div className="relative z-10 flex items-center justify-center min-h-screen">
|
||||||
<Card className="sm:w-[700px] sm:min-w-[700px] sm:max-w-96 sm:max-h-[calc(100vh-70px)] overflow-y-auto sm:min-h-auto min-h-screen w-full min-w-full shadow-lg bg-white/85 dark:bg-black/85 backdrop-blur-md">
|
<Card className="overflow-y-auto min-h-screen w-full min-w-full shadow-lg bg-white/85 dark:bg-black/85 backdrop-blur-md sm:rounded-none">
|
||||||
<div className="flex flex-col items-center sm:pt-0 relative">
|
<div className="flex flex-col items-center sm:pt-0 relative">
|
||||||
<div className="flex flex-row items-center absolute left-4 top-4">
|
<div className="flex flex-row items-center absolute left-4 top-4">
|
||||||
<img src="/icon.png" alt="icon" className="w-6 h-6" />
|
<img src="/icon.png" alt="icon" className="w-6 h-6" />
|
||||||
@ -28,102 +32,19 @@ const IndexPage: FC = () => {
|
|||||||
|
|
||||||
{/* <LogIn className="w-8 h-8 text-gray-700 mb-4" /> */}
|
{/* <LogIn className="w-8 h-8 text-gray-700 mb-4" /> */}
|
||||||
<CardContent className="w-full space-y-4 flex-1" spacing={false}>
|
<CardContent className="w-full space-y-4 flex-1" spacing={false}>
|
||||||
<div className="flex flex-col w-full items-center gap-2 dark:bg-black/70 bg-white/70 shadow-md shadow-gray-300 dark:shadow-gray-700">
|
<div className="flex flex-row">
|
||||||
<div className="flex flex-col items-center gap-2 p-7 pt-14">
|
<Sidebar activeTab={tab} onChangeTab={(tab) => setTab(tab)} />
|
||||||
<div className="w-24 h-24 overflow-hidden rounded-full flex items-center justify-center bg-gray-300">
|
<div className="sm:p-4 max-w-full flex-1">
|
||||||
{/* <User size={64} /> */}
|
<div className="flex flex-col w-full items-center gap-2">
|
||||||
<img
|
<TopBar
|
||||||
className="w-full h-full"
|
activeTab={tab}
|
||||||
src="http://192.168.178.69:9000/guard-storage/profile_eff00028-2d9e-458d-8944-677855edc147_1748099702417601900.jpg"
|
onChangeTab={(tab) => setTab(tab)}
|
||||||
alt="profile pic"
|
|
||||||
/>
|
/>
|
||||||
|
{tab === "home" && <Home />}
|
||||||
|
{/* {tab === "personal-info" && <PersonalInfo />} */}
|
||||||
</div>
|
</div>
|
||||||
<h1 className="dark:text-gray-200 text-gray-800 text-2xl select-none">
|
<div className="p-4">
|
||||||
Amir Adal
|
{tab === "personal-info" && <PersonalInfo />}
|
||||||
</h1>
|
|
||||||
<div className="flex flex-row items-center gap-2 mr-[-10px] select-none">
|
|
||||||
<p className="text-gray-600 dark:text-gray-500">
|
|
||||||
qwer.009771@gmail.com
|
|
||||||
</p>
|
|
||||||
<div className="text-gray-600 dark:text-gray-500">
|
|
||||||
<ChevronDown size={18} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex w-full overflow-x-auto sm:overflow-x-visible max-w-full min-w-full sm:justify-center sm:space-x-4 no-scrollbar">
|
|
||||||
<div className="flex-shrink-0 px-4 py-2 min-w-[120px] sm:min-w-0 sm:flex-1 flex items-center justify-center border-b-4 border-b-blue-500 text-blue-500 cursor-pointer select-none whitespace-nowrap">
|
|
||||||
Home
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex-shrink-0 px-4 py-2 min-w-[140px] sm:min-w-0 sm:flex-1 flex items-center justify-center border-b-0 text-gray-500 cursor-pointer select-none whitespace-nowrap">
|
|
||||||
Personal Info
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex-shrink-0 px-4 py-2 min-w-[180px] sm:min-w-0 sm:flex-1 flex items-center justify-center border-b-0 text-gray-500 cursor-pointer select-none whitespace-nowrap">
|
|
||||||
Data & Personalization
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="p-4">
|
|
||||||
<h1 className="dark:text-gray-200 text-gray-800 text-2xl">
|
|
||||||
Your profile info in Home services
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<p className="text-gray-500 text-sm mt-2">
|
|
||||||
Personal info and options to manage it. You can make some of
|
|
||||||
this info, like your contact details, visible to others so
|
|
||||||
they can reach you easily. You can also see a summary of your
|
|
||||||
profiles.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="border dark:border-gray-800 border-gray-300 p-4 rounded mt-4">
|
|
||||||
<h3 className="dark:text-gray-300 text-gray-800">
|
|
||||||
Basic info
|
|
||||||
</h3>
|
|
||||||
<p className="text-gray-500 text-sm mt-2 mb-4">
|
|
||||||
Some info may be visible to other services and tools using
|
|
||||||
Home Guard.{" "}
|
|
||||||
<a href="#" className="text-blue-500">
|
|
||||||
Learn more
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{/* Profile Picture */}
|
|
||||||
<div className="flex flex-row items-center justify-between px-2 p-4 border-b gap-2 dark:border-b-gray-800 border-b-gray-100">
|
|
||||||
<div className="flex flex-col items-start gap-2">
|
|
||||||
<p className="text-sm dark:text-gray-400 font-medium text-gray-600">
|
|
||||||
Profile picture
|
|
||||||
</p>
|
|
||||||
<p className="text-sm dark:text-gray-500 text-gray-600">
|
|
||||||
Add a profile picture to personalize your account
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="w-16 h-16 overflow-hidden rounded-full dark:bg-gray-400 bg-gray-700">
|
|
||||||
<img
|
|
||||||
className="w-full h-full"
|
|
||||||
src="http://192.168.178.69:9000/guard-storage/profile_eff00028-2d9e-458d-8944-677855edc147_1748099702417601900.jpg"
|
|
||||||
alt="profile pic"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Name */}
|
|
||||||
<div className="flex flex-row items-center justify-between px-2 p-4 border-b dark:border-b-gray-800 border-b-gray-100">
|
|
||||||
<div className="flex flex-col items-start gap-2">
|
|
||||||
<p className="text-sm dark:text-gray-400 font-medium text-gray-600">
|
|
||||||
Name
|
|
||||||
</p>
|
|
||||||
<p className="text dark:text-gray-200 text-gray-800">
|
|
||||||
Amir Adal
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-gray-500">
|
|
||||||
<ChevronRight size={26} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user