Skip to content

Commit

Permalink
implement side bar
Browse files Browse the repository at this point in the history
  • Loading branch information
Your Name committed Sep 4, 2024
1 parent 94997da commit fdc8e07
Show file tree
Hide file tree
Showing 66 changed files with 2,001 additions and 27 deletions.
9 changes: 8 additions & 1 deletion app/[locale]/(auth)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
export default function RootLayout({
import { getLoggedInUser } from "@/lib/actions/user.actions";
import { redirect } from "next/navigation";

export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const user = await getLoggedInUser();
if (user) {
redirect("/");
}
return (
<main className="flex min-h-screen w-full font-inter">{children}</main>
);
Expand Down
22 changes: 22 additions & 0 deletions app/[locale]/(main)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import SideBar from "@/components/SideBar";
import { getLoggedInUser } from "@/lib/actions/user.actions";
import { redirect } from "next/navigation";

const MainLayout = async ({
children,
}: Readonly<{
children: React.ReactNode;
}>) => {
const user = await getLoggedInUser();
if (!user) {
redirect("/sign-in");
}
return (
<div className="flex gap-1">
<SideBar user={user} />
{children}
</div>
);
};

export default MainLayout;
15 changes: 15 additions & 0 deletions app/[locale]/(main)/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import WordCard from "@/components/WordCard";
import {
getEnglishWordData,
getLoggedInUser,
} from "@/lib/actions/user.actions";
export default async function HomePage() {
const user = await getLoggedInUser();
const data = await getEnglishWordData("mo");
console.log(data);
return (
<div className="flex flex-wrap flex-1 min-h-screen overflow-auto p-10 gap-2 ">
<WordCard />
</div>
);
}
12 changes: 0 additions & 12 deletions app/[locale]/page.tsx

This file was deleted.

32 changes: 32 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,36 @@
.flex-center {
@apply flex items-center justify-center;
}
.sidebar {
@apply bg-[#242526] sticky left-0 top-0 flex h-screen w-fit flex-col gap-6 border-r border-l border-gray-700 pt-8 text-white max-md:hidden sm:p-4 xl:p-6 2xl:w-[355px];
}
.user-details {
@apply flex flex-col justify-around w-3/5;
}
.user-email {
@apply text-slate-200 text-[16px] font-semibold overflow-clip text-ellipsis;
}
.user-name {
@apply text-slate-400 text-sm;
}
.logout {
@apply flex justify-center items-center w-1/5 h-full cursor-pointer;
}
.languages {
@apply flex flex-col flex-grow overflow-auto gap-5 w-full;
}
.language {
@apply flex gap-1 border border-slate-600 rounded-md p-3 items-center cursor-pointer select-none w-11/12 justify-between;
}
.add-new-language {
@apply flex gap-1 border border-slate-600 rounded-md items-center cursor-pointer select-none w-11/12 justify-between;
}
.word-card {
background: rgba(17, 25, 40, 0.35);
border: 1px solid rgba(255, 255, 255, 0.125);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
border-radius: 10px;
@apply flex flex-col w-60 h-72 justify-center items-center;
}
}
23 changes: 23 additions & 0 deletions components/AddNewLanguage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
import { PlusIcon } from "lucide-react";
import { useState } from "react";
import AddNewLanguageDialog from "./AddNewLanguageDialog";

const AddNewLanguage = () => {
const [open, setOpen] = useState(false);

return (
<div className="add-new-language hover:opacity-75">
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger className="w-full h-full flex justify-between p-3">
Add Language <PlusIcon />
</DialogTrigger>
<DialogContent>
<AddNewLanguageDialog setOpen={setOpen} />
</DialogContent>
</Dialog>
</div>
);
};

export default AddNewLanguage;
60 changes: 60 additions & 0 deletions components/AddNewLanguageDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useLanguagesStore } from "@/store/userLanguages";
import { Loader2 } from "lucide-react";
import { useState } from "react";
import { Button } from "./ui/button";
import { DialogFooter, DialogHeader, DialogTitle } from "./ui/dialog";
import { Input } from "./ui/input";
import { Label } from "./ui/label";
const AddNewLanguageDialog = ({
setOpen,
}: {
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
}) => {
const { addNewLanguage } = useLanguagesStore();
const [lang, setLang] = useState("");
const [isLoading, setIsLoading] = useState(false);
const handleAddNewLang = async () => {
setIsLoading(true);
await addNewLanguage(lang);
setOpen(false);
};
return (
<>
<DialogHeader>
<DialogTitle>Add New Language</DialogTitle>
</DialogHeader>
<div className="flex items-center space-x-2">
<div className="grid flex-1 gap-2">
<Label htmlFor="language" className="sr-only">
Language
</Label>
<Input
id="language"
className="focus-visible:ring-transparent"
value={lang}
onChange={(e) => setLang(e.target.value)}
/>
</div>
</div>
<DialogFooter className="sm:justify-start">
<Button
type="button"
variant="secondary"
disabled={isLoading}
onClick={handleAddNewLang}
>
{isLoading ? (
<>
<Loader2 size={20} className="animate-spin" />
&nbsp;Loading...
</>
) : (
"Add"
)}
</Button>
</DialogFooter>
</>
);
};

export default AddNewLanguageDialog;
2 changes: 0 additions & 2 deletions components/AuthForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ const AuthForm = ({ type }: { type: "sign-up" | "sign-in" }) => {
setIsLoading(true);
setError("");
const userData = { email: data.email, password: data.password };
console.log(data);
try {
if (type === "sign-up") {
const response = await signUp(userData);
Expand All @@ -46,7 +45,6 @@ const AuthForm = ({ type }: { type: "sign-up" | "sign-in" }) => {

if (type === "sign-in") {
const response = await signIn(userData);
console.log(response);
if (!response.error) {
router.push("/");
return;
Expand Down
29 changes: 29 additions & 0 deletions components/Language.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Image from "next/image";

const Language = ({
name,
isCurrentLanguage,
handleClick,
}: {
name: string;
isCurrentLanguage: boolean;
handleClick: () => void;
}) => {
return (
<div className="language group" onClick={handleClick}>
<span className="text-white group-hover:text-gray-300 group-hover:underline">
{name}
</span>
{isCurrentLanguage && (
<Image
src="/icons/correct.svg"
width={24}
height={24}
alt="Current Language"
/>
)}
</div>
);
};

export default Language;
36 changes: 36 additions & 0 deletions components/Languages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use client";
import { useLanguagesStore } from "@/store/userLanguages";
import { useLayoutEffect } from "react";
import AddNewLanguage from "./AddNewLanguage";
import Language from "./Language";

const Languages = ({ userLangs }: { userLangs: string[] }) => {
const {
languages: allLanguages,
changeCurrentLanguage,
currentLanguage,
setLangs,
} = useLanguagesStore();
useLayoutEffect(() => {
setLangs(userLangs);
const currentLanguage = localStorage.getItem("currentLanguage") || "";
changeCurrentLanguage(currentLanguage);
}, []);

return (
<div className="languages">
<h2 className="text-xl font-semibold">Languages</h2>
{allLanguages.map((lang) => (
<Language
key={lang}
name={lang}
isCurrentLanguage={lang === currentLanguage}
handleClick={() => changeCurrentLanguage(lang)}
/>
))}
<AddNewLanguage />
</div>
);
};

export default Languages;
14 changes: 14 additions & 0 deletions components/SideBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Languages from "./Languages";
import UserCard from "./UserCard";

const SideBar = ({ user }: sideBarProps) => {
return (
<div className="sidebar">
<UserCard user={user} />
<hr className="border border-gray-500" />
<Languages userLangs={user.languages} />
</div>
);
};

export default SideBar;
48 changes: 48 additions & 0 deletions components/UserCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use client";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { logoutAccount } from "@/lib/actions/user.actions";
import { Loader2 } from "lucide-react";
import Image from "next/image";
import { useRouter } from "next/navigation";
import { useState } from "react";

const UserCard = ({ user }: userCardProps) => {
const router = useRouter();
const [isLoading, setIsLoading] = useState(false);
const handleLogOut = async () => {
if (isLoading) return;
setIsLoading(true);
await logoutAccount();
router.push("/sign-in");
};
return (
<div className="flex gap-1 border border-slate-600 rounded-md p-3 items-center">
<Avatar className="w-1/5">
<AvatarImage src="/icons/avater.svg" />
<AvatarFallback>{user.name[0].toUpperCase()}</AvatarFallback>
</Avatar>
<div className="user-details">
<div className="user-email" title={user.email}>
{user.email}
</div>
<div className="user-name" title={user.name}>
Mohamed Helmy
</div>
</div>
<div className="logout" title="Log out" onClick={handleLogOut}>
{isLoading ? (
<Loader2 size={20} className="animate-spin" />
) : (
<Image
src="/icons/logout.svg"
width="24"
height="24"
alt="logout"
/>
)}
</div>
</div>
);
};

export default UserCard;
11 changes: 11 additions & 0 deletions components/WordCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const WordCard = () => {
return (
<div className="word-card">
<div className="first-lang">كلب</div>
<div className="second-lang">Dog</div>
<div className="phonetic">/dɑːɡ/</div>
</div>
);
};

export default WordCard;
Loading

0 comments on commit fdc8e07

Please sign in to comment.