diff --git a/.gitignore b/.gitignore index ee440aa..e6a22c6 100644 --- a/.gitignore +++ b/.gitignore @@ -135,6 +135,9 @@ dist .vscode-test .vscode +# .idea +.idea + # yarn v2 .yarn/cache .yarn/unplugged diff --git a/apps/web/src/assets/reply.svg b/apps/web/src/assets/reply.svg new file mode 100644 index 0000000..87e4522 --- /dev/null +++ b/apps/web/src/assets/reply.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/apps/web/src/assets/video-call.svg b/apps/web/src/assets/video-call.svg new file mode 100644 index 0000000..e0f9dab --- /dev/null +++ b/apps/web/src/assets/video-call.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/apps/web/src/assets/voice-call.svg b/apps/web/src/assets/voice-call.svg new file mode 100644 index 0000000..b882efa --- /dev/null +++ b/apps/web/src/assets/voice-call.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/apps/web/src/components/layouts/direct-messages.tsx b/apps/web/src/components/layouts/direct-messages.tsx index 0befce7..5aaee91 100644 --- a/apps/web/src/components/layouts/direct-messages.tsx +++ b/apps/web/src/components/layouts/direct-messages.tsx @@ -23,7 +23,7 @@ export const DirectMessages = () => { /> {/* Online Friends */} -
+
1024 ? "bg-zinc-900" : ""}`} @@ -43,9 +43,12 @@ export const DirectMessages = () => {
{Array.from({ length: 30 }).map((_, index) => ( { + if (window.innerWidth < 1024) closeNavs(); + }} + className={`flex h-14 cursor-pointer items-center gap-2 rounded-md px-2 py-2 hover:bg-zinc-900 ${pathname === `/app/channels/me/${index}` && window.innerWidth > 1024 ? "bg-zinc-900" : ""}`} >
{/* Friend Image */} diff --git a/apps/web/src/components/layouts/friend-chat.tsx b/apps/web/src/components/layouts/friend-chat.tsx new file mode 100644 index 0000000..5cf244b --- /dev/null +++ b/apps/web/src/components/layouts/friend-chat.tsx @@ -0,0 +1,31 @@ +import { Message } from "@/components/ui/messages/message"; +import { useEffect, useRef } from "react"; + +export const FriendChat = ({ id }: { id: number }) => { + const endOfMessagesRef = useRef(null); + + useEffect(() => { + endOfMessagesRef.current?.scrollIntoView(); + }, []); + return ( +
+
+ {Array.from({ length: 25 }).map((_, index) => ( + + ))} +
+ +
+ +
+
+
+ ); +}; diff --git a/apps/web/src/components/layouts/friend-mini-profile.tsx b/apps/web/src/components/layouts/friend-mini-profile.tsx new file mode 100644 index 0000000..3975a03 --- /dev/null +++ b/apps/web/src/components/layouts/friend-mini-profile.tsx @@ -0,0 +1,34 @@ +import { Logo } from "@/components/ui/logo"; + +export const FriendMiniProfile = ({ id }: { id: number }) => { + return ( + + ); +}; diff --git a/apps/web/src/components/layouts/friend-navbar.tsx b/apps/web/src/components/layouts/friend-navbar.tsx new file mode 100644 index 0000000..5d5d05d --- /dev/null +++ b/apps/web/src/components/layouts/friend-navbar.tsx @@ -0,0 +1,69 @@ +import hambuger from "@/assets/hamburger.svg"; +import videoCall from "@/assets/video-call.svg"; +import voiceCall from "@/assets/voice-call.svg"; +import { Logo } from "@/components/ui/logo"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { useResponsive } from "@/providers/responsive-provider"; + +export const FirendNavbar = ({ id }: { id: number }) => { + const { isNavsOpen, openNavs } = useResponsive(); + return ( +
+ +
+ ); +}; diff --git a/apps/web/src/components/layouts/friends-navbar-content.tsx b/apps/web/src/components/layouts/friends-navbar-content.tsx index bc313f2..c022aaf 100644 --- a/apps/web/src/components/layouts/friends-navbar-content.tsx +++ b/apps/web/src/components/layouts/friends-navbar-content.tsx @@ -1,5 +1,6 @@ import searchIcon from "@/assets/search-icon.svg"; import { Logo } from "@/components/ui/logo"; +import { Link } from "@tanstack/react-router"; import { OnlineStatus } from "../ui/status/online"; export const FriendsNavbarContent = () => { @@ -25,7 +26,8 @@ export const FriendsNavbarContent = () => {
{Array.from({ length: 5 }).map((_, index) => ( -
@@ -45,7 +47,7 @@ export const FriendsNavbarContent = () => {

Online

-
+ ))}
diff --git a/apps/web/src/components/layouts/sidebar.tsx b/apps/web/src/components/layouts/sidebar.tsx index 21c7fc2..7f225e0 100644 --- a/apps/web/src/components/layouts/sidebar.tsx +++ b/apps/web/src/components/layouts/sidebar.tsx @@ -27,7 +27,7 @@ export const Sidebar = () => { >
1024 ? "top-3 h-2/3 " : "top-1/2 h-2 group-hover:top-5 group-hover:h-6"}`} + className={`absolute left-0 flex w-1 items-center justify-center overflow-hidden rounded-full bg-white duration-100 ${pathname.startsWith("/app/channels/me") && window.innerWidth > 1024 ? "top-3 h-2/3" : "top-1/2 h-2 group-hover:top-5 group-hover:h-6"}`} >
diff --git a/apps/web/src/components/ui/messages/message-actions.tsx b/apps/web/src/components/ui/messages/message-actions.tsx new file mode 100644 index 0000000..882faaf --- /dev/null +++ b/apps/web/src/components/ui/messages/message-actions.tsx @@ -0,0 +1,26 @@ +import reply from "@/assets/reply.svg"; + +export const MessageActions = ({ + reactHandler, +}: { + reactHandler: Function; +}) => { + const emojis = ["👍", "❤️", "😂", "😢", "😡"]; + + return ( +
+ {emojis.map((emoji, index) => ( + + ))} + +
+ ); +}; diff --git a/apps/web/src/components/ui/messages/message.tsx b/apps/web/src/components/ui/messages/message.tsx new file mode 100644 index 0000000..96e81d7 --- /dev/null +++ b/apps/web/src/components/ui/messages/message.tsx @@ -0,0 +1,43 @@ +import { Logo } from "@/components/ui/logo"; +import { MessageActions } from "@/components/ui/messages/message-actions"; +import { useState } from "react"; + +export const Message = ({ index, id }: { index: number; id: string }) => { + const [react, setReact] = useState(null); + + const reactHandler = (emoji: string) => { + setReact(emoji); + }; + + return ( +
+
+ +
+ + + +
+
+

+ {index % 2 === 0 ? `Friend ${id}` : `TheGoatt`} +

+

+ {new Date().toLocaleString()} +

+
+

Welcome this is a message number {index}

+
+
+ ); +}; diff --git a/apps/web/src/index.css b/apps/web/src/index.css index 6fb0b76..2b24699 100644 --- a/apps/web/src/index.css +++ b/apps/web/src/index.css @@ -66,4 +66,19 @@ @apply bg-background text-foreground; font-family: "Open Sans", sans-serif; } + ::-webkit-scrollbar { + width: 5px; + } + + ::-webkit-scrollbar-track { + @apply bg-zinc-900; + } + + ::-webkit-scrollbar-thumb { + @apply bg-zinc-500 rounded-md; + } + + ::-webkit-scrollbar-thumb:hover { + @apply bg-zinc-400; + } } diff --git a/apps/web/src/routeTree.gen.ts b/apps/web/src/routeTree.gen.ts index f271641..99aefe8 100644 --- a/apps/web/src/routeTree.gen.ts +++ b/apps/web/src/routeTree.gen.ts @@ -19,6 +19,7 @@ import { Route as AuthRegisterImport } from './routes/auth.register' import { Route as AuthLoginImport } from './routes/auth.login' import { Route as AuthAppImport } from './routes/_auth.app' import { Route as AuthAppChannelsMeImport } from './routes/_auth.app.channels.me' +import { Route as AuthAppChannelsMeFriendIdImport } from './routes/_auth.app.channels.me.$friendId' // Create/Update Routes @@ -62,6 +63,11 @@ const AuthAppChannelsMeRoute = AuthAppChannelsMeImport.update({ getParentRoute: () => AuthAppRoute, } as any) +const AuthAppChannelsMeFriendIdRoute = AuthAppChannelsMeFriendIdImport.update({ + path: '/$friendId', + getParentRoute: () => AuthAppChannelsMeRoute, +} as any) + // Populate the FileRoutesByPath interface declare module '@tanstack/react-router' { @@ -122,17 +128,35 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthAppChannelsMeImport parentRoute: typeof AuthAppImport } + '/_auth/app/channels/me/$friendId': { + id: '/_auth/app/channels/me/$friendId' + path: '/$friendId' + fullPath: '/app/channels/me/$friendId' + preLoaderRoute: typeof AuthAppChannelsMeFriendIdImport + parentRoute: typeof AuthAppChannelsMeImport + } } } // Create and export the route tree +interface AuthAppChannelsMeRouteChildren { + AuthAppChannelsMeFriendIdRoute: typeof AuthAppChannelsMeFriendIdRoute +} + +const AuthAppChannelsMeRouteChildren: AuthAppChannelsMeRouteChildren = { + AuthAppChannelsMeFriendIdRoute: AuthAppChannelsMeFriendIdRoute, +} + +const AuthAppChannelsMeRouteWithChildren = + AuthAppChannelsMeRoute._addFileChildren(AuthAppChannelsMeRouteChildren) + interface AuthAppRouteChildren { - AuthAppChannelsMeRoute: typeof AuthAppChannelsMeRoute + AuthAppChannelsMeRoute: typeof AuthAppChannelsMeRouteWithChildren } const AuthAppRouteChildren: AuthAppRouteChildren = { - AuthAppChannelsMeRoute: AuthAppChannelsMeRoute, + AuthAppChannelsMeRoute: AuthAppChannelsMeRouteWithChildren, } const AuthAppRouteWithChildren = @@ -156,7 +180,8 @@ export interface FileRoutesByFullPath { '/app': typeof AuthAppRouteWithChildren '/auth/login': typeof AuthLoginRoute '/auth/register': typeof AuthRegisterRoute - '/app/channels/me': typeof AuthAppChannelsMeRoute + '/app/channels/me': typeof AuthAppChannelsMeRouteWithChildren + '/app/channels/me/$friendId': typeof AuthAppChannelsMeFriendIdRoute } export interface FileRoutesByTo { @@ -167,7 +192,8 @@ export interface FileRoutesByTo { '/app': typeof AuthAppRouteWithChildren '/auth/login': typeof AuthLoginRoute '/auth/register': typeof AuthRegisterRoute - '/app/channels/me': typeof AuthAppChannelsMeRoute + '/app/channels/me': typeof AuthAppChannelsMeRouteWithChildren + '/app/channels/me/$friendId': typeof AuthAppChannelsMeFriendIdRoute } export interface FileRoutesById { @@ -179,7 +205,8 @@ export interface FileRoutesById { '/_auth/app': typeof AuthAppRouteWithChildren '/auth/login': typeof AuthLoginRoute '/auth/register': typeof AuthRegisterRoute - '/_auth/app/channels/me': typeof AuthAppChannelsMeRoute + '/_auth/app/channels/me': typeof AuthAppChannelsMeRouteWithChildren + '/_auth/app/channels/me/$friendId': typeof AuthAppChannelsMeFriendIdRoute } export interface FileRouteTypes { @@ -193,6 +220,7 @@ export interface FileRouteTypes { | '/auth/login' | '/auth/register' | '/app/channels/me' + | '/app/channels/me/$friendId' fileRoutesByTo: FileRoutesByTo to: | '/' @@ -203,6 +231,7 @@ export interface FileRouteTypes { | '/auth/login' | '/auth/register' | '/app/channels/me' + | '/app/channels/me/$friendId' id: | '__root__' | '/' @@ -213,6 +242,7 @@ export interface FileRouteTypes { | '/auth/login' | '/auth/register' | '/_auth/app/channels/me' + | '/_auth/app/channels/me/$friendId' fileRoutesById: FileRoutesById } @@ -284,7 +314,14 @@ export const routeTree = rootRoute }, "/_auth/app/channels/me": { "filePath": "_auth.app.channels.me.tsx", - "parent": "/_auth/app" + "parent": "/_auth/app", + "children": [ + "/_auth/app/channels/me/$friendId" + ] + }, + "/_auth/app/channels/me/$friendId": { + "filePath": "_auth.app.channels.me.$friendId.tsx", + "parent": "/_auth/app/channels/me" } } } diff --git a/apps/web/src/routes/_auth.app.channels.me.$friendId.tsx b/apps/web/src/routes/_auth.app.channels.me.$friendId.tsx new file mode 100644 index 0000000..08f5342 --- /dev/null +++ b/apps/web/src/routes/_auth.app.channels.me.$friendId.tsx @@ -0,0 +1,22 @@ +import { FriendChat } from "@/components/layouts/friend-chat"; +import { FriendMiniProfile } from "@/components/layouts/friend-mini-profile"; +import { FirendNavbar } from "@/components/layouts/friend-navbar"; +import { createFileRoute, useLocation } from "@tanstack/react-router"; + +export const Route = createFileRoute("/_auth/app/channels/me/$friendId")({ + component: FriendRoot, +}); + +function FriendRoot() { + const pathname = useLocation().pathname; + + return ( + <> + +
+ + +
+ + ); +} diff --git a/apps/web/src/routes/_auth.app.channels.me.tsx b/apps/web/src/routes/_auth.app.channels.me.tsx index 66dca49..efa3e45 100644 --- a/apps/web/src/routes/_auth.app.channels.me.tsx +++ b/apps/web/src/routes/_auth.app.channels.me.tsx @@ -2,7 +2,7 @@ import { DirectMessages } from "@/components/layouts/direct-messages"; import { FriendsNavbar } from "@/components/layouts/friends-navbar"; import { FriendsNavbarContent } from "@/components/layouts/friends-navbar-content"; import { useResponsive } from "@/providers/responsive-provider"; -import { createFileRoute } from "@tanstack/react-router"; +import { Outlet, createFileRoute, useLocation } from "@tanstack/react-router"; export const Route = createFileRoute("/_auth/app/channels/me")({ component: MeRoot, @@ -10,6 +10,7 @@ export const Route = createFileRoute("/_auth/app/channels/me")({ function MeRoot() { const { isNavsOpen } = useResponsive(); + const pathname = useLocation().pathname; return ( <> @@ -17,8 +18,16 @@ function MeRoot() {
- - + {pathname === "/app/channels/me" ? ( + <> + + + + ) : ( + <> + + + )}
); diff --git a/apps/web/src/routes/_auth.tsx b/apps/web/src/routes/_auth.tsx index 44696b6..46f4d6a 100644 --- a/apps/web/src/routes/_auth.tsx +++ b/apps/web/src/routes/_auth.tsx @@ -1,3 +1,4 @@ +import { useAuth } from "@/providers/auth-provider"; import { Outlet, createFileRoute, @@ -5,8 +6,6 @@ import { useRouter, } from "@tanstack/react-router"; -import { useAuth } from "@/providers/auth-provider"; - export const Route = createFileRoute("/_auth")({ beforeLoad: ({ context, location }) => { if (!context.auth.isAuthenticated) { @@ -38,7 +37,7 @@ function AuthLayout() { return ( <> -
+
Welcome back, {auth.user}!