1
+ 'use client' ;
2
+
3
+ import React , { useState , useEffect } from 'react' ;
4
+ import MakerCard from './components/MakerCard' ;
5
+
6
+ // 포지션 약어 정의
7
+ const abbr = {
8
+ SO : 'SysOp' ,
9
+ PM : 'Project Manager' ,
10
+ DS : 'Designer' ,
11
+ DV : 'Developer'
12
+ } ;
13
+
14
+ // 프로젝트 데이터 - 모든 프로젝트 포함
15
+ const projects = [
16
+ {
17
+ name : 'SPARCS BBS' , // Eagle BBs 기반 아라
18
+ period : '1991~1998' ,
19
+ launched : '1991' ,
20
+ description :
21
+ `1991년에 창립된 SPARCS가 가장 먼저 선보였던 아라입니다.
22
+ Eagle BBS (Pirite BBS) 기반으로 개발된 아라로, 우리나라에서 두번째로 생긴
23
+ Internet에 연결된 BBS (Bulletin Board System) 서비스입니다. 이때부터 아라는
24
+ 계속해서 리뉴얼되어 왔으며, 현존하는 BBS 서비스 중에서는 가장 오래되었습니다.` ,
25
+ members : {
26
+ SO : [ 'cdpark:박종대' ]
27
+ }
28
+ } ,
29
+ {
30
+ name : 'NeoAra' , // NNTP 기반 아라
31
+ period : '1998~2006' ,
32
+ launched : '1998' ,
33
+ description :
34
+ `NeoAra는 NewsGroup을 연동하고자 한 NNTP 기반의 아라입니다.
35
+ KAIST 구성원만을 위한 NewsGroup 뿐만 아니라 KAIST 주변의 한국 내 인터넷 사용자
36
+ 모두를 위한 NewsGroup 으로서의 역할도 하려고 하였습니다` ,
37
+ members : {
38
+ SO : [
39
+ 'kaien:박상진' , 'godslord:권용철' , 'algepher:변창환' ,
40
+ 'neosado:김영준' , 'tapung:채주병'
41
+ ]
42
+ }
43
+ } ,
44
+ {
45
+ name : 'NeoAra & WebAra' ,
46
+ period : '2006~2008' ,
47
+ launched : '2006' ,
48
+ description :
49
+ `NeoAra & WebAra는 웹과의 연동이 시작된 아라입니다.
50
+ 덕분에 Telnet, NNTP 뿐만 아니라 Web 으로도 아라를 이용이 가능해졌습니다.
51
+ 또한 파일 첨부기능이 추가되어 학우들이 더 다양한 방식으로 아라를 이용할 수 있었습니다.` ,
52
+ members : {
53
+ SO : [ 'airlover:김유승' , 'pcpenpal:박용수' , 'softdie:김동주' ]
54
+ }
55
+ } ,
56
+ {
57
+ name : 'Arara 1세대' ,
58
+ period : '2008~2010' ,
59
+ launched : '2008' ,
60
+ description :
61
+ `Arara 1세대는 유지보수가 어려워진 NeoAra & WebAra를 대체하기 위해 출범하였으며,
62
+ 이종 언어가 자유로이 쓰이는 확장가능 구조로 개발되었습니다.
63
+ Python을 기반으로 백엔드에서는 SQLAlchemy, 미들웨어로는 Thrift RPC,
64
+ 프론트엔드에서는 Django Template Engine 을 사용하였습니다.` ,
65
+ members : {
66
+ DV : [
67
+ 'serialx:홍성진' , 'pipocket:서우석' , 'ssaljalu:조준희' , 'breadfish:구성모' ,
68
+ 'jcob:조지혁' , 'peremen:박신조' , 'combacsa:변규홍'
69
+ ]
70
+ }
71
+ } ,
72
+ {
73
+ name : 'Arara 2세대' , // XpressEngine 기반 아라
74
+ period : '2010~2020' ,
75
+ launched : '2011' ,
76
+ description :
77
+ `Arara 2세대는 2010년부터 2020년 10월까지 학우들이 가장 오랫동안 이용한 아라입니다.
78
+ 2011년 리뉴얼된 당시 동시접속자수 200명, 하루 평균 접속자수가 7000명으로 KAIST 학내
79
+ 공식 커뮤니티로서 아라의 위상을 확인할 수 있었습니다.
80
+ 기존 ARAra 엔진 디자인을 새롭게 하고, 동시에 XpressEngine 기반 아라를 개발하려는
81
+ 노력이 있었습니다. 또한 RSS 등 사용자들이 필요로 한 기능이 구현되었습니다.` ,
82
+ members : {
83
+ PM : [ 'combacsa:변규홍' ] ,
84
+ DV : [
85
+ 'mikkang:김문범' , 'reniowood:김진혁' , 'harry:이대근' , 'jeanclaire:이현진' ,
86
+ 'ssaljalu:조준희' , 'anna418:조유정' , 'richking:김창하' , 'xhark:김재홍' ,
87
+ 'leopine:이가영' , 'snogar:차동훈' , 'imai:배성경' , 'r4t5y6:임규리' ,
88
+ 'kuss:안재만' , 'hodduc:이준성' , 'leeopop:이근홍'
89
+ ]
90
+ }
91
+ } ,
92
+ {
93
+ name : '모바일 아라' ,
94
+ period : '2011~2020' ,
95
+ launched : '2012' ,
96
+ description :
97
+ `모바일 아라는 아라를 모바일로 이용하는 수요가 늘면서,
98
+ 그에 맞게 디자인을 개선시키고 Arara의 엔진 성능을 개선하고자한 프로젝트입니다.` ,
99
+ members : {
100
+ PM : [ 'hodduc:이준성' ] ,
101
+ DV : [
102
+ 'richking:김창하' , 'combasa:변규홍' , 'grandmarnier:차준호' , 'bbashong:최낙현' ,
103
+ 'panda:조민지' , 'elaborate:안병욱' , 'penguin:민서영' , 'pocari:이경태' ,
104
+ 'zzongaly:정진근'
105
+ ]
106
+ }
107
+ } ,
108
+ {
109
+ name : '아라리' ,
110
+ period : '2012~2013' ,
111
+ members : {
112
+ PM : [ 'zzongaly:정진근' ] ,
113
+ DV : [
114
+ 'bbashong:최낙현' , 'undead:이창원' , 'boolgom:심규민' , 'rodumani:정창제' ,
115
+ 'panda:조민지' , 'naldo:박지혁' , 'yasik:박중언' , 'apple:김영석' ,
116
+ 'veritas:정진훈' , 'jjus:김지현' , 'alice:문슬기' , 'penguin:민서영'
117
+ ]
118
+ }
119
+ } ,
120
+ {
121
+ name : '아라2' ,
122
+ period : '2013~2014' ,
123
+ members : {
124
+ PM : [ 'serialx:홍성진' ] ,
125
+ DV : [
126
+ 'hodduc:이준성' , 'raon:김강인' , 'bbashong:최낙현' , 'richking:김창하'
127
+ ]
128
+ }
129
+ } ,
130
+ {
131
+ name : '아라플러스' ,
132
+ period : '2015~2016' ,
133
+ description :
134
+ `아라플러스는 KAIST 학생 사회에서 ARA를 다시 활성화하기 위해, 커뮤니티 활동을 즐길 수
135
+ 있는 풍부한 기능들을 새로운 UI와 함께 제공하고자 했던 프로젝트입니다. 사용자들이 특정
136
+ 주제에 대해 채팅을 나눌 수 있는 '불판', 동아리나 자치단체, 소모임을 위한 '그룹게시판',
137
+ 익명 글작성, 포인트 제도 등 재미있는 기능들이 기획되고 개발되었습니다.` ,
138
+ members : {
139
+ PM : [
140
+ 'story:김동화' , 'kyeome:김태겸'
141
+ ] ,
142
+ DV : [
143
+ 'kanon:김민수' , 'apple:김영석' , 'zealot:한승현' , 'undead:이창원' ,
144
+ 'mandu:황태현' , 'samjo:조성원' , 'suckzoo:홍석주' , 'luan:이상국' ,
145
+ 'george:조형준' , 'jara:이문영'
146
+ ]
147
+ }
148
+ } ,
149
+ {
150
+ name : '뉴아라' ,
151
+ period : '2017~On-going' ,
152
+ launched : '2020' ,
153
+ description :
154
+ `2020년 11월 출범한 뉴아라는 '가장 정확한 정보를 가장 신속하게'라는 슬로건으로 10년간
155
+ 이용되던 Arara 를 새롭게 리뉴얼한 프로젝트입니다. 뉴아라에서는 카이스트 포탈공지를
156
+ 아라에서도 제공하기 시작했고, 기존 ARA의 게시물과 댓글을 모두 이전시켰음에도 빠른 속도를
157
+ 유지했으며, elasticsearch를 도입해 발전된 검색기능을 선보였습니다.
158
+ 또한 아라의 아이덴티티가 잘 드러나도록 홈페이지 디자인을 개선하였습니다.` ,
159
+ members : {
160
+ PM : [
161
+ [ 'killerwhale:박승범' , '2025~' ] , [ 'hyooyh:권효진' , '2024' ] , [ 'yuwol:황인준' , '2022~2023' ] ,
162
+ [ 'jessie:윤지수' , '2021' ] , [ 'victory:김주연' , '2020' ] , [ 'leo:정진우' , '2019' ] ,
163
+ [ 'yujingaya:김유진' , '2018' ] , [ 'swan:지수환' , '2018' ] , [ 'raon:김강인' , '2017' ]
164
+ ] ,
165
+ DV : [
166
+ 'casio:임가은' , 'soom:이수민' , 'edge:정재현' , 'hyuk:장승혁' ,
167
+ 'king:김세종' , 'roul:신도윤' , 'default:김현수' , 'phenol:권영완' ,
168
+ 'arcticfox:고예준' , 'alvin:김상오' , 'retro:최상아' , 'ina:송인화' ,
169
+ 'ddungiii:김기영' , 'duncan:이동재' , 'panya:김지연' , 'ivy:이융희' ,
170
+ 'jungnoh:노정훈' , 'water:김윤수' , 'triangle:주예준' , 'hanski:한석휘' ,
171
+ 'idev:이재현' , 'doolly:김제윤' , 'nenw:김요한' , 'fi:김도현' ,
172
+ 'james:문재호' , 'busan:안재웅' , 'kidevelop:함종현' , 'holymolly:김태원' ,
173
+ 'gunwoo:김건우' , 'todo:김동관' , 'his:황인승' , 'rongrong:이승민' ,
174
+ 'leesia:강현우' , 'seol:설윤아' , 'youns:최윤서' , 'appleseed:강찬규'
175
+ ] ,
176
+ DS : [
177
+ 'yumyum:조유민' , 'nine:배세윤' , 'cheddar:최다은' ,
178
+ 'stitch:이채영' , 'zero:임현정' , 'luny:김나영'
179
+ ]
180
+ }
181
+ }
182
+ ] ;
183
+
1
184
export default function Makers ( ) {
2
- return (
3
- < div >
4
- < h1 > 만든사람들</ h1 >
185
+ const [ selected , setSelected ] = useState ( 9 ) ; // 기본 선택은 뉴아라 (마지막 항목)
186
+ const positions = [ 'SO' , 'PM' , 'DS' , 'DV' ] ;
187
+
188
+ useEffect ( ( ) => {
189
+ document . body . style . background = '#fafafa' ;
190
+ return ( ) => {
191
+ document . body . style . background = '' ;
192
+ } ;
193
+ } , [ ] ) ;
194
+
195
+ // 프로젝트 이름 포맷팅
196
+ const projectName = ( project : any ) => {
197
+ return project . launched ? `🚀 ${ project . name } ` : project . name ;
198
+ } ;
199
+
200
+ // 멤버 이름 추출
201
+ const memberName = ( member : any ) => {
202
+ if ( Array . isArray ( member ) ) member = member [ 0 ] ;
203
+ return member . split ( ':' ) [ 1 ] ;
204
+ } ;
205
+
206
+ // 멤버 닉네임 추출
207
+ const memberNickname = ( member : any ) => {
208
+ if ( Array . isArray ( member ) ) member = member [ 0 ] ;
209
+ return member . split ( ':' ) [ 0 ] ;
210
+ } ;
211
+
212
+ // 멤버 포지션 포맷팅
213
+ const memberPosition = ( member : any , position : string ) => {
214
+ if ( Array . isArray ( member ) ) {
215
+ return `${ member [ 1 ] } ${ abbr [ position as keyof typeof abbr ] } ` ;
216
+ } else {
217
+ return abbr [ position as keyof typeof abbr ] ;
218
+ }
219
+ } ;
220
+
221
+ return (
222
+ < div className = "max-w-[1280px] mx-auto px-4 py-8 bg-[#fafafa]" >
223
+ < h1 className = "text-[20px] font-bold leading-[1.45] mb-[18px] mx-[90px] md:mx-0 sm:mx-[50px] xs:mx-[20px]" >
224
+ Project
225
+ </ h1 >
226
+
227
+ < div className = "grid gap-[10px] justify-center mb-[48px] grid-cols-[repeat(auto-fit,minmax(220px,max-content))] sm:grid-cols-[repeat(auto-fit,minmax(110px,max-content))]" >
228
+ { projects . map ( ( project , index ) => (
229
+ < MakerCard
230
+ key = { project . name }
231
+ title = { projectName ( project ) }
232
+ subtitle = { project . period }
233
+ active = { selected === index }
234
+ launched = { project . launched }
235
+ isProject = { true }
236
+ onClick = { ( ) => setSelected ( index ) }
237
+ />
238
+ ) ) }
5
239
</ div >
6
- ) ;
7
- }
8
-
240
+
241
+ { projects [ selected ] ?. description && (
242
+ < div className = "flex w-full flex-col justify-center my-[48px]" >
243
+ < h2 className = "text-[20px] font-bold leading-[1.45] mb-[18px] mx-[90px] md:mx-0 sm:mx-[50px] xs:mx-[20px]" >
244
+ Description
245
+ </ h2 >
246
+ < div className = "rounded-[10px] shadow-md bg-white p-[22px_64px] mt-[30px] mx-[90px] md:mx-0 sm:mx-[50px] sm:p-[22px_22px] xs:mx-[20px]" >
247
+ < p className = "text-[15px] font-medium leading-[1.47] text-left sm:text-[12px]" >
248
+ { projects [ selected ] . description }
249
+ </ p >
250
+ </ div >
251
+ </ div >
252
+ ) }
253
+
254
+ < h2 className = "text-[20px] font-bold leading-[1.45] mb-[18px] mx-[90px] md:mx-0 sm:mx-[50px] xs:mx-[20px]" >
255
+ Member
256
+ </ h2 >
257
+
258
+ < div className = "grid gap-[10px] justify-center mt-[48px] mb-[10px] grid-cols-[repeat(auto-fit,minmax(280px,max-content))] sm:grid-cols-[repeat(auto-fit,minmax(120px,max-content))]" >
259
+ { positions . map ( position =>
260
+ projects [ selected ] . members [ position as keyof typeof projects [ typeof selected ] [ 'members' ] ] ?. map ( ( member : any ) => (
261
+ < MakerCard
262
+ key = { Array . isArray ( member ) ? member [ 0 ] : member }
263
+ title = { memberName ( member ) }
264
+ subtitle = { memberNickname ( member ) }
265
+ position = { memberPosition ( member , position ) }
266
+ isProject = { false }
267
+ />
268
+ ) )
269
+ ) }
270
+ </ div >
271
+ </ div >
272
+ ) ;
273
+ }
0 commit comments