11import Page from "components/common/Page"
22import React from "react"
33import styled from "styled-components"
4+
45import 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+
617const 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 ( "튜토리얼" ) }
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 > 시간 & 장소</ h2 >
296+ < h3 > 시간 & 장소</ 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
277335export 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+
279350const 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