Skip to content

Commit

Permalink
feat: 프로필 페이지 및 구성 컴포넌트 UI 구현 & sideBar를 통한 Home, Profile 페이지 이동 추가 (#8)
Browse files Browse the repository at this point in the history
**프로필 페이지 UI 구현 및 이를 위한 컴포넌트 구현 & SideBar 이동 추가**
- ProfileInfo, Highlights(Story 보관용, 우선 ui만 구현해놓고 실제 남겨두고 사용할지는 미결정),
ProfileTabs component로 구성
- Profile page 동적 패스 & SideBar(+MobileBar)를 통한 Home, Profile 페이지 이동 추가

---------

Co-authored-by: 박세준 <[email protected]>
  • Loading branch information
LikeACloud7 and 박세준 authored Jan 1, 2025
1 parent 711bf25 commit f276569
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 6 deletions.
9 changes: 7 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Navigate, Route, Routes } from 'react-router-dom';
import ExplorePage from './pages/ExplorePage';
import LoginPage from './pages/LoginPage';
import MainPage from './pages/MainPage';
import ProfilePage from './pages/ProfilePage';

export type LoginContextType = {
isLoggedIn: boolean;
Expand Down Expand Up @@ -39,11 +40,15 @@ export const App = () => {
<LoginPage handleIsLoggedIn={handleIsLoggedIn} />
)
}
></Route>
/>
<Route
path="/explore"
element={isLoggedIn ? <ExplorePage /> : <Navigate to="/" />}
></Route>
/>
<Route
path="/:username"
element={isLoggedIn ? <ProfilePage /> : <Navigate to="/" />}
/>
</Routes>
</LoginContext.Provider>
);
Expand Down
26 changes: 26 additions & 0 deletions src/components/Hilghlights.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';

type HighlightItemProps = {
name: string;
};

const HighlightItem = ({ name }: HighlightItemProps) => (
<div className="flex flex-col items-center">
<div className="w-16 h-16 rounded-full bg-gray-200 mb-1"></div>
<span className="text-xs">{name}</span>
</div>
);

const Highlights: React.FC = () => {
const highlights = ['test1', 'test2', 'test3'];

return (
<div className="flex space-x-4 mb-8 overflow-x-auto">
{highlights.map((highlight, index) => (
<HighlightItem key={index} name={highlight} />
))}
</div>
);
};

export default Highlights;
9 changes: 7 additions & 2 deletions src/components/MobileBar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Heart, Home, PlusSquare, Search, User } from 'lucide-react';
import React from 'react';
import { Link } from 'react-router-dom';

interface NavItemProps {
icon: React.ReactNode;
Expand All @@ -14,11 +15,15 @@ const NavItem = ({ icon }: NavItemProps) => (
const BottomBar = () => {
return (
<nav className="flex md:hidden justify-around py-2 bg-white border-t">
<NavItem icon={<Home />} />
<Link to="/">
<NavItem icon={<Home />} />
</Link>
<NavItem icon={<Search />} />
<NavItem icon={<PlusSquare />} />
<NavItem icon={<Heart />} />
<NavItem icon={<User />} />
<Link to="/username">
<NavItem icon={<User />} />
</Link>
</nav>
);
};
Expand Down
13 changes: 13 additions & 0 deletions src/components/PostGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const PostGrid = () => {
const posts = Array(4).fill(null);

return (
<div className="grid grid-cols-3 gap-1">
{posts.map((_, index) => (
<div key={index} className="aspect-square bg-gray-200"></div>
))}
</div>
);
};

export default PostGrid;
57 changes: 57 additions & 0 deletions src/components/ProfileInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Settings } from 'lucide-react';

type ProfileInfoProps = {
username: string;
posts: number;
followers: number;
following: number;
fullName: string;
bio: string;
};

const ProfileInfo = ({
username,
posts,
followers,
following,
fullName,
bio,
}: ProfileInfoProps) => {
return (
<div className="mb-8">
<div className="flex items-center mb-4">
<img
src="/placeholder.svg"
alt={username}
className="w-20 h-20 rounded-full mr-4"
/>
<div className="flex-1">
<div className="flex items-center mb-2">
<h1 className="text-xl font-semibold mr-4">{username}</h1>
<button className="bg-blue-500 text-white px-4 py-1 rounded-md text-sm font-semibold mr-2">
Follow
</button>
<Settings className="w-6 h-6" />
</div>
<div className="flex space-x-4 text-sm">
<span>
<strong>{posts}</strong> posts
</span>
<span>
<strong>{followers}</strong> followers
</span>
<span>
<strong>{following}</strong> following
</span>
</div>
</div>
</div>
<div className="md:hidden">
<h2 className="font-semibold">{fullName}</h2>
<p>{bio}</p>
</div>
</div>
);
};

export default ProfileInfo;
35 changes: 35 additions & 0 deletions src/components/ProfileTabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Bookmark, Grid } from 'lucide-react';
import { useState } from 'react';

import PostGrid from './PostGrid';

const ProfileTabs = () => {
const [activeTab, setActiveTab] = useState('posts');

return (
<div>
<div className="flex justify-around border-t">
<button
className={`flex-1 py-2 ${activeTab === 'posts' ? 'border-t-2 border-black' : ''}`}
onClick={() => {
setActiveTab('posts');
}}
>
<Grid className="w-6 h-6 mx-auto" />
</button>
<button
className={`flex-1 py-2 ${activeTab === 'saved' ? 'border-t-2 border-black' : ''}`}
onClick={() => {
setActiveTab('saved');
}}
>
<Bookmark className="w-6 h-6 mx-auto" />
</button>
</div>
{activeTab === 'posts' && <PostGrid />}
{activeTab === 'saved' && <div className="text-center py-8">저장됨</div>}
</div>
);
};

export default ProfileTabs;
9 changes: 7 additions & 2 deletions src/components/SideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
User,
} from 'lucide-react';
import React, { useContext } from 'react';
import { Link } from 'react-router-dom';

import { LoginContext, type LoginContextType } from '../App';

Expand Down Expand Up @@ -43,12 +44,16 @@ const Sidebar = () => {
<img src="/instagram-logo.png" alt="Instagram" className="w-24" />
</div>
<div className="flex flex-col flex-1 space-y-2">
<NavItem icon={<Home />} label="Home" active />
<Link to="/" className="no-underline">
<NavItem icon={<Home />} label="Home" active />
</Link>
<NavItem icon={<Search />} label="Search" active={false} />
<NavItem icon={<Compass />} label="Explore" active={false} />
<NavItem icon={<Heart />} label="Notifications" active={false} />
<NavItem icon={<PlusSquare />} label="Create" active={false} />
<NavItem icon={<User />} label="Profile" active={false} />
<Link to="/username" className="no-underline">
<NavItem icon={<User />} label="Profile" active={false} />
</Link>
</div>
<div className="relative mt-auto">
<button
Expand Down
44 changes: 44 additions & 0 deletions src/pages/ProfilePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useParams } from 'react-router-dom';

import Highlights from '../components/Hilghlights';
import MobileBar from '../components/MobileBar';
import MobileHeader from '../components/MobileHeader';
import ProfileInfo from '../components/ProfileInfo';
import ProfileTabs from '../components/ProfileTabs';
import SideBar from '../components/SideBar';

const ProfilePage = () => {
const { username } = useParams();
const profileData = {
username: username as string,
posts: 4,
followers: 100,
following: 100,
fullName: 'User1',
bio: 'User1 Bio',
};

return (
<div className="flex flex-col min-h-screen bg-gray-50">
<div className="flex-1 p-4 pb-16 md:pb-4 md:ml-64 overflow-y-auto">
<div className="max-w-3xl mx-auto">
<MobileHeader />
<ProfileInfo {...profileData} />
<div className="hidden md:block mb-4">
<h2 className="font-semibold">{profileData.fullName}</h2>
<p>{profileData.bio}</p>
</div>
<Highlights />
<ProfileTabs />
</div>
</div>

<div className="fixed bottom-0 left-0 right-0 md:left-0 md:top-0 md:right-auto md:w-64 bg-white border-t md:border-r md:border-t-0">
<SideBar />
<MobileBar />
</div>
</div>
);
};

export default ProfilePage;

0 comments on commit f276569

Please sign in to comment.