diff --git a/client/src/components/icons/svgIcons.tsx b/client/src/components/icons/svgIcons.tsx
index 603aa7295..1c766aa6a 100644
--- a/client/src/components/icons/svgIcons.tsx
+++ b/client/src/components/icons/svgIcons.tsx
@@ -2488,3 +2488,18 @@ export const RightIcon = ({ width, ...props }: SVGProps) => (
);
+
+export const NoImageIcon = ({ width, ...props }: SVGProps) => (
+
+);
diff --git a/client/src/components/roadmapDetailPage/extraInfo/ExtraInfo.styles.ts b/client/src/components/roadmapDetailPage/extraInfo/ExtraInfo.styles.ts
new file mode 100644
index 000000000..98aa0449c
--- /dev/null
+++ b/client/src/components/roadmapDetailPage/extraInfo/ExtraInfo.styles.ts
@@ -0,0 +1,48 @@
+import styled from 'styled-components';
+import media from '@styles/media';
+
+export const ExtraInfo = styled.div`
+ ${({ theme }) => theme.fonts.description5};
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ justify-content: space-between;
+
+ width: 30%;
+ height: 55rem;
+
+ ${media.mobile`
+ display: none;
+ `}
+`;
+
+export const RoadmapMetadata = styled.div`
+ display: flex;
+ flex-direction: column;
+
+ & > div:not(:last-child) {
+ margin-bottom: 3rem;
+ }
+`;
+
+export const Category = styled.div`
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+`;
+
+export const Difficulty = styled.div`
+ text-align: end;
+`;
+
+export const RecommendedRoadmapPeriod = styled.div`
+ text-align: end;
+`;
+
+export const Tags = styled.div`
+ color: ${({ theme }) => theme.colors.main_dark};
+
+ & > div {
+ text-align: end;
+ }
+`;
diff --git a/client/src/components/roadmapDetailPage/extraInfo/ExtraInfo.tsx b/client/src/components/roadmapDetailPage/extraInfo/ExtraInfo.tsx
new file mode 100644
index 000000000..4959bca11
--- /dev/null
+++ b/client/src/components/roadmapDetailPage/extraInfo/ExtraInfo.tsx
@@ -0,0 +1,33 @@
+import { RoadmapDetailType } from '@myTypes/roadmap/internal';
+import * as S from './ExtraInfo.styles';
+import SVGIcon from '@components/icons/SVGIcon';
+import { CategoriesInfo } from '@constants/roadmap/category';
+
+type ExtraInfoProps = {
+ roadmapInfo: RoadmapDetailType;
+};
+
+const ExtraInfo = ({ roadmapInfo }: ExtraInfoProps) => {
+ return (
+
+ Created by {roadmapInfo.creator.name}
+
+
+ 카테고리: {roadmapInfo.category.name}
+
+
+ 난이도: {roadmapInfo.difficulty}
+
+ 예상 소요시간: {roadmapInfo.recommendedRoadmapPeriod}일
+
+
+
+ {roadmapInfo.tags.map((tag) => (
+ #{tag.name}
+ ))}
+
+
+ );
+};
+
+export default ExtraInfo;
diff --git a/client/src/components/roadmapDetailPage/introduction/Introduction.styles.ts b/client/src/components/roadmapDetailPage/introduction/Introduction.styles.ts
new file mode 100644
index 000000000..bd5f1e6bf
--- /dev/null
+++ b/client/src/components/roadmapDetailPage/introduction/Introduction.styles.ts
@@ -0,0 +1,47 @@
+import media from '@styles/media';
+import styled from 'styled-components';
+
+export const IntroductionWrapper = styled.div`
+ width: 70%;
+
+ ${media.mobile`
+ width:100%;
+ `}
+`;
+
+export const Introduction = styled.div<{ isExpanded: boolean }>`
+ ${({ theme }) => theme.fonts.description5};
+ overflow: hidden;
+ max-height: ${({ isExpanded }) => (isExpanded ? 'auto' : '55rem')};
+
+ & > p:not(:last-child) {
+ margin-bottom: 2rem;
+ }
+
+ & div {
+ ${({ theme }) => theme.fonts.h1};
+ margin-bottom: 0.5rem;
+ color: ${({ theme }) => theme.colors.main_dark};
+ }
+`;
+
+export const LineShadow = styled.div`
+ position: relative;
+ width: 100%;
+ height: 0.2rem;
+ box-shadow: 0 -4px 6px rgba(0, 0, 0, 1);
+`;
+
+export const ReadMoreButton = styled.button`
+ position: relative;
+ top: calc(-2rem - 4px);
+ left: 50%;
+ transform: translateX(-5rem);
+
+ width: 10rem;
+ height: 4rem;
+
+ background-color: ${({ theme }) => theme.colors.white};
+ border-radius: 8px;
+ box-shadow: ${({ theme }) => theme.shadows.main};
+`;
diff --git a/client/src/components/roadmapDetailPage/introduction/Introduction.tsx b/client/src/components/roadmapDetailPage/introduction/Introduction.tsx
new file mode 100644
index 000000000..3069efacf
--- /dev/null
+++ b/client/src/components/roadmapDetailPage/introduction/Introduction.tsx
@@ -0,0 +1,51 @@
+import { RoadmapDetailType } from '@myTypes/roadmap/internal';
+import * as S from './Introduction.styles';
+import { useEffect, useRef, useState } from 'react';
+
+type IntroductionProps = {
+ roadmapInfo: RoadmapDetailType;
+};
+
+const Introduction = ({ roadmapInfo }: IntroductionProps) => {
+ const [isExpanded, setIsExpanded] = useState(false);
+ const [showMoreButton, setShowMoreButton] = useState(false);
+ const introRef = useRef(null);
+
+ useEffect(() => {
+ if (!introRef.current) return;
+
+ const element = introRef.current;
+ if (element.scrollHeight > element.clientHeight) {
+ setShowMoreButton(true);
+ }
+ }, []);
+
+ const toggleExpand = () => {
+ setIsExpanded((prev) => !prev);
+ };
+
+ return (
+
+
+
+
설명
+ {roadmapInfo.introduction}
+
+
+
본문
+ {roadmapInfo.content.content === ''
+ ? '로드맵에 대한 설명이 없어요🥲'
+ : roadmapInfo.content.content}
+
+
+ {showMoreButton && !isExpanded && (
+ <>
+
+ 더 보기
+ >
+ )}
+
+ );
+};
+
+export default Introduction;
diff --git a/client/src/components/roadmapDetailPage/nodeContent/NodeContent.styles.ts b/client/src/components/roadmapDetailPage/nodeContent/NodeContent.styles.ts
new file mode 100644
index 000000000..695e6a26b
--- /dev/null
+++ b/client/src/components/roadmapDetailPage/nodeContent/NodeContent.styles.ts
@@ -0,0 +1,90 @@
+import styled from 'styled-components';
+import media from '@styles/media';
+
+export const SliderContent = styled.div`
+ display: flex;
+ aspect-ratio: 5 / 3.5;
+ background-color: ${({ theme }) => theme.colors.gray100};
+ border-radius: 8px;
+
+ ${media.mobile`
+ aspect-ratio: 0;
+ `}
+`;
+
+export const LeftContent = styled.div`
+ width: 45%;
+
+ ${media.mobile`
+ display: none;
+ `}
+`;
+
+export const NodeImg = styled.img`
+ width: 100%;
+ height: 100%;
+ padding: 1.5rem;
+ object-fit: cover;
+`;
+
+export const NoImg = styled.div`
+ ${({ theme }) => theme.fonts.title_large}
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+
+ width: 100%;
+ height: 100%;
+`;
+
+export const Separator = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 0.2rem;
+ height: 100%;
+
+ & > div {
+ height: 50%;
+ }
+
+ & > div:last-child {
+ background-color: black;
+ }
+`;
+
+export const RightContent = styled.div`
+ ${({ theme }) => theme.fonts.h1}
+ overflow: scroll;
+ width: 55%;
+ padding: 1.5rem;
+ padding-top: 3rem;
+
+ ${media.mobile`
+ width: 100%;
+ height: 60rem;
+ padding-top: 1.5rem;
+ `}
+`;
+
+export const ContentTitle = styled.div`
+ ${({ theme }) => theme.fonts.title_large}
+ display: flex;
+ align-items: center;
+ margin-bottom: 1rem;
+`;
+
+export const Step = styled.div`
+ ${({ theme }) => theme.fonts.h2}
+ display: flex;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: center;
+
+ width: 3rem;
+ height: 3rem;
+ margin-right: 0.5rem;
+
+ border: 0.3rem solid black;
+ border-radius: 50%;
+`;
diff --git a/client/src/components/roadmapDetailPage/nodeContent/NodeContent.tsx b/client/src/components/roadmapDetailPage/nodeContent/NodeContent.tsx
new file mode 100644
index 000000000..f2ffb7e60
--- /dev/null
+++ b/client/src/components/roadmapDetailPage/nodeContent/NodeContent.tsx
@@ -0,0 +1,38 @@
+import type { NodeType } from '@myTypes/roadmap/internal';
+import * as S from './NodeContent.styles';
+import SVGIcon from '@components/icons/SVGIcon';
+
+type NodeContentProps = {
+ node: NodeType;
+ index: number;
+};
+
+const NodeContent = ({ node, index }: NodeContentProps) => {
+ return (
+
+
+ {node.imageUrls[0] ? (
+
+ ) : (
+
+
+ No Image
+
+ )}
+
+
+
+
+
+
+
+ {index + 1}
+ {node.title}
+
+ {node.description}
+
+
+ );
+};
+
+export default NodeContent;
diff --git a/client/src/components/roadmapDetailPage/roadmapDetail/RoadmapDetail.styles.ts b/client/src/components/roadmapDetailPage/roadmapDetail/RoadmapDetail.styles.ts
index 4cafaf5cf..93c0b17ce 100644
--- a/client/src/components/roadmapDetailPage/roadmapDetail/RoadmapDetail.styles.ts
+++ b/client/src/components/roadmapDetailPage/roadmapDetail/RoadmapDetail.styles.ts
@@ -1,43 +1,52 @@
-import media from '@styles/media';
import styled from 'styled-components';
export const RoadmapDetail = styled.div`
- position: relative;
- margin: 4rem 0;
- padding: 0 2rem;
- white-space: pre-line;
-
- ${media.mobile`
- flex-direction: column;
- align-items: center;
- `}
+ padding: 2rem 0 4rem 0;
`;
-export const RoadmapBody = styled.p`
- ${({ theme }) => theme.fonts.button1}
- width: 50%;
- padding: 4rem 4rem;
- height: 35rem;
+export const RoadmapInfo = styled.div``;
- overflow: scroll;
+export const Title = styled.div`
+ ${({ theme }) => theme.fonts.title_large};
+ margin-bottom: 2rem;
+ color: ${({ theme }) => theme.colors.main_dark};
+`;
- border-radius: 18px;
- box-shadow: ${({ theme }) => theme.shadows.box};
+export const Description = styled.div`
+ display: flex;
+`;
- color: ${({ theme }) => theme.colors.gray300};
+export const ButtonsWrapper = styled.div`
+ position: relative;
+ width: 100%;
+`;
- ${media.mobile`
- padding: 4rem 4rem;
- `}
+export const Buttons = styled.div`
+ bottom: 3rem;
- & > strong {
- ${({ theme }) => theme.fonts.h1};
- margin-bottom: 4rem;
- color: ${({ theme }) => theme.colors.main_dark};
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+
+ margin: 2rem 0;
+
+ background-color: ${({ theme }) => theme.colors.main_dark};
+ border-radius: 8px;
+
+ & > div {
+ width: 0.2rem;
+ height: 5.5rem;
+ background-color: ${({ theme }) => theme.colors.white};
}
`;
-export const PageOnTop = styled.div`
- display: flex;
- justify-content: space-around;
+export const Button = styled.button`
+ ${({ theme }) => theme.fonts.nav_text}
+ width: 50%;
+ height: 5.5rem;
+
+ color: ${({ theme }) => theme.colors.white};
+
+ background-color: ${({ theme }) => theme.colors.main_dark};
+ border-radius: 8px;
`;
diff --git a/client/src/components/roadmapDetailPage/roadmapDetail/RoadmapDetail.tsx b/client/src/components/roadmapDetailPage/roadmapDetail/RoadmapDetail.tsx
index 94da78baa..912425ee5 100644
--- a/client/src/components/roadmapDetailPage/roadmapDetail/RoadmapDetail.tsx
+++ b/client/src/components/roadmapDetailPage/roadmapDetail/RoadmapDetail.tsx
@@ -1,36 +1,41 @@
-import RoadmapItem from '../../_common/roadmapItem/RoadmapItem';
-import Button from '../../_common/button/Button';
import * as S from './RoadmapDetail.styles';
-import useValidParams from '@/hooks/_common/useValidParams';
+import useValidParams from '@hooks/_common/useValidParams';
import { useNavigate } from 'react-router-dom';
-import { useRoadmapDetail } from '@/hooks/queries/roadmap';
-import RoadmapNodeList from '../roadmapNodeList/RoadmapNodeList';
+import { useRoadmapDetail } from '@hooks/queries/roadmap';
+
+import Slider from '@components/_common/slider/Slider';
+import NodeContent from '../nodeContent/NodeContent';
+import ExtraInfo from '../extraInfo/ExtraInfo';
+import Introduction from '../introduction/Introduction';
const RoadmapDetail = () => {
const { id: roadmapId } = useValidParams<{ id: string }>();
const navigate = useNavigate();
const { roadmapInfo } = useRoadmapDetail(Number(roadmapId));
- const moveToGoalRoomCreatePage = () => {
- navigate(`/roadmap/${roadmapId}/goalroom-create`);
- };
-
return (
-
-
-
- 로드맵 설명
- {roadmapInfo.content.content === ''
- ? '로드맵에 대한 설명이 없어요🥲'
- : roadmapInfo.content.content}
-
-
-
-
+
+ {roadmapInfo.roadmapTitle}
+
+
+
+
+
+
+ navigate(`/roadmap/${roadmapId}/goalroom-create`)}>
+ 모임 생성하기
+
+
+ navigate(`/roadmap/${roadmapId}/goalroom-list`)}>
+ 진행중인 모임보기
+
+
+
+ {roadmapInfo.content.nodes.map((node, index) => (
+
+ ))}
+
);
};