Skip to content
This repository was archived by the owner on Nov 27, 2025. It is now read-only.

Commit 872a8e2

Browse files
committed
Merge remote-tracking branch 'origin/develop'
2 parents 41a6206 + fe35184 commit 872a8e2

File tree

1 file changed

+133
-7
lines changed

1 file changed

+133
-7
lines changed

src/pages/Program/tutorial.tsx

Lines changed: 133 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,72 @@
11
import Page from "components/common/Page"
22
import React from "react"
33
import styled from "styled-components"
4+
45
import useTranslation from "utils/hooks/useTranslation"
56

7+
const KAKAO_MAP_URL = "https://place.map.kakao.com/700052629"
8+
const NAVER_MAP_URL = "https://naver.me/FfMdLRIM"
9+
const GOOGLE_MAP_URL = "https://maps.app.goo.gl/H8QiqNRrHHwa6giv7"
10+
const GOOGLE_MAP_IFRAME_SRC =
11+
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d4548.557545780045!2d126.92092772543593!3d37.55771056652137!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x357c98d855555555%3A0x843e97bd5279ea6b!2z7ZWc67mb66-465SU7Ja0KOyjvCk!5e0!3m2!1sko!2skr!4v1730765243757!5m2!1sko!2skr"
12+
13+
type MapInfoStateType = {
14+
mapType: "kakao" | "google"
15+
}
16+
617
const Tutorial = () => {
18+
const kakaoMapRef = React.useRef<HTMLDivElement>(null)
19+
const [state, setState] = React.useState<MapInfoStateType>({ mapType: "kakao" })
720
const t = useTranslation()
821

22+
const selectMap = (mapType: MapInfoStateType["mapType"]) =>
23+
setState((prevState) => ({ ...prevState, mapType }))
24+
25+
React.useEffect(() => {
26+
if (!(window.kakao && window.kakao.maps && kakaoMapRef.current)) return
27+
28+
const content = `<a href="${KAKAO_MAP_URL}"><div style="width:150px;text-align:center;color:#000">${t("한빛미디어")}</div></a>`
29+
const position = new window.kakao.maps.LatLng(37.55917491634307, 126.9278766893293)
30+
const map = new window.kakao.maps.Map(kakaoMapRef.current, { center: position, level: 3 })
31+
new kakao.maps.InfoWindow({ content }).open(map, new kakao.maps.Marker({ map, position }))
32+
})
33+
34+
const flexBoxStyle: React.CSSProperties = {
35+
display: "flex",
36+
justifyContent: "center",
37+
alignItems: "center",
38+
}
39+
const columnFlexBoxStyle: React.CSSProperties = { ...flexBoxStyle, flexDirection: "column" }
40+
const mapStyle: React.CSSProperties = { border: 0, width: "100%", height: "450px" }
41+
942
return (
1043
<Page title={t("튜토리얼")}>
11-
<h1>{t("튜토리얼")}</h1>
44+
<h1>
45+
<div style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center' }}>
46+
{t("튜토리얼")} &nbsp;
47+
<GoToRegistrationButtonContainer href="https://event-us.kr/pythonkorea/event/94452" target="_blank" rel="noreferrer">
48+
<GoToRegistrationButton>지금 등록하러 가기!</GoToRegistrationButton>
49+
</GoToRegistrationButtonContainer>
50+
</div>
51+
</h1>
1252
<div>
1353
<p>
14-
<h2>튜토리얼이란?</h2>
54+
<h3>튜토리얼이란?</h3>
1555
튜토리얼은 초보자들을 위해, 또는 새로운 것을 접하는 사람들을 위해 진행하는 교육 프로그램입니다.<br />
1656
직접 컴퓨터를 가져와서 진행하며 현장에서 질문하고 해결하는 만큼 해당 기술에 대해 좀 더 깊게 알게됩니다.<br />
1757
</p>
1858

1959
<hr />
2060

2161
<p>
22-
<h2>튜토리얼 프로그램 소개</h2>
62+
<h3>튜토리얼 프로그램 소개</h3>
2363
<small>
2464
* 튜토리얼 프로그램은 오전 / 오후 두 타임으로 구성되어 있습니다. 신청 시 시간대가 겹치지 않도록 주의해주시기 바랍니다!
2565
</small>
2666
</p>
2767
<br />
2868
<p>
29-
<h3>오전 세션 <sup>[10:00 - 13:00]</sup></h3>
69+
<h4>오전 세션 <sup>[10:00 - 13:00]</sup></h4>
3070
<TutorialProgramDetails>
3171
<summary>FastAPI로 CRUD API 서버 만들기</summary>
3272
<div>
@@ -105,7 +145,7 @@ const Tutorial = () => {
105145
</p>
106146
<br />
107147
<p>
108-
<h3>오후 세션 <sup>[14:00 - 18:00]</sup></h3>
148+
<h4>오후 세션 <sup>[14:00 - 18:00]</sup></h4>
109149
<TutorialProgramDetails>
110150
<summary>Django ORM 톺아보기</summary>
111151
<div>
@@ -253,11 +293,29 @@ const Tutorial = () => {
253293
<hr />
254294

255295
<p>
256-
<h2>시간 &amp; 장소</h2>
296+
<h3>시간 &amp; 장소</h3>
257297
<ul>
258298
<li>시간 : 10:00 ~ 18:00</li>
259-
<li>장소 : 서울 서대문구 연희로 2길 62</li>
299+
<li>
300+
장소 : 서울 서대문구 연희로 2길 62
301+
</li>
260302
</ul>
303+
<div>
304+
<div style={{ ...flexBoxStyle }}>
305+
<MapSelectTabBtn className={state.mapType === "kakao" ? "active" : ""} onClick={() => selectMap("kakao")}>{t("카카오맵")}</MapSelectTabBtn>
306+
<MapSelectTabBtn className={state.mapType === "google" ? "active" : ""} onClick={() => selectMap("google")}>{t("구글 지도")}</MapSelectTabBtn>
307+
</div>
308+
309+
<div style={{ ...columnFlexBoxStyle, display: state.mapType === "kakao" ? "flex" : "none" }}>
310+
<div ref={kakaoMapRef} style={mapStyle}></div>
311+
<FullWidthAnchorBtn href={KAKAO_MAP_URL} target="_blank" rel="noreferrer"><button className="kakao">{t("카카오맵에서 열기")}</button></FullWidthAnchorBtn>
312+
<FullWidthAnchorBtn href={NAVER_MAP_URL} target="_blank" rel="noreferrer"><button className="naver">{t("네이버 지도에서 열기")}</button></FullWidthAnchorBtn>
313+
</div>
314+
<div style={{ ...columnFlexBoxStyle, display: state.mapType === "google" ? "flex" : "none" }}>
315+
<iframe title="map" src={GOOGLE_MAP_IFRAME_SRC} style={mapStyle} allowFullScreen loading="lazy" referrerPolicy="no-referrer-when-downgrade"></iframe>
316+
<FullWidthAnchorBtn href={GOOGLE_MAP_URL} target="_blank" rel="noreferrer"><button className="google">{t("구글 지도에서 열기")}</button></FullWidthAnchorBtn>
317+
</div>
318+
</div>
261319
</p>
262320
<br />
263321
<p>
@@ -276,6 +334,19 @@ const Tutorial = () => {
276334

277335
export default Tutorial
278336

337+
const GoToRegistrationButtonContainer = styled.a`
338+
display: flex;
339+
justify-content: center;
340+
align-items: center;
341+
`
342+
343+
const GoToRegistrationButton = styled.button`
344+
font-size: 1rem;
345+
padding: 0.5rem 1rem;
346+
margin: 0;
347+
cursor: pointer;
348+
`
349+
279350
const TutorialProgramDetails = styled.details`
280351
margin: 0.5rem 0;
281352
padding: 0.5rem;
@@ -339,3 +410,58 @@ const TutorialProgramDetails = styled.details`
339410
}
340411
}
341412
`
413+
414+
const MapSelectTabBtn = styled.button`
415+
flex-grow: 1;
416+
padding: 0.25rem;
417+
418+
border: none;
419+
background-color: rgba(255, 255, 255, 0.05);
420+
font-weight: lighter;
421+
422+
border-radius: 0;
423+
424+
&:hover {
425+
background-color: rgba(255, 255, 255, 0.1);
426+
}
427+
428+
&.active {
429+
background-color: rgba(255, 255, 255, 0.3);
430+
font-weight: bold;
431+
}
432+
`
433+
434+
const FullWidthAnchorBtn = styled.a`
435+
width: 100%;
436+
height: 1.5rem;
437+
display: flex;
438+
justify-content: flex-start;
439+
align-items: center;
440+
441+
button {
442+
width: 100%;
443+
height: 100%;
444+
margin: 0;
445+
padding: 0 0.5rem;
446+
447+
font-size: 0.75rem;
448+
font-weight: bold;
449+
border: none;
450+
border-radius: unset;
451+
452+
&.kakao {
453+
background-color: #fee500;
454+
color: #191919;
455+
}
456+
457+
&.naver {
458+
background-color: #04c75b;
459+
color: #fff;
460+
}
461+
462+
&.google {
463+
background-color: #4285f4;
464+
color: #fff;
465+
}
466+
}
467+
`

0 commit comments

Comments
 (0)