diff --git a/README.md b/README.md index e97a1d649..073597e5c 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,126 @@ # πŸš‡ μ§€ν•˜μ²  노선도 λ―Έμ…˜ +## πŸ‘©πŸ»β€πŸ’» κΈ°λŠ₯ λͺ©λ‘ + +- 4개 관리 νŽ˜μ΄μ§€ 연결을 μœ„ν•œ λ²„νŠΌ 생성 +- 4개 κ΄€λ¦¬νŽ˜μ΄μ§€ μ»΄ν¬λ„ŒνŠΈ 생성 +- 각 λ²„νŠΌμ— 이벀트 λ¦¬μŠ€λ„ˆ λ“±λ‘ν•˜μ—¬ μ»΄ν¬λ„ŒνŠΈ μ—°κ²° +- μ—­ 관리 νŽ˜μ΄μ§€ UI κ΅¬ν˜„ +- μ—­ 관리 νŽ˜μ΄μ§€ 각 λ²„νŠΌμ— 이벀트 λ¦¬μŠ€λ„ˆ μ—°κ²° +- local storageλ₯Ό μ΄μš©ν•˜μ—¬ μ—­ 데이터 μ €μž₯ν•˜κΈ° +- λ…Έμ„  관리 νŽ˜μ΄μ§€ UI κ΅¬ν˜„ +- λ…Έμ„  관리 νŽ˜μ΄μ§€ 각 λ²„νŠΌμ— 이벀트 λ¦¬μŠ€λ„ˆ μ—°κ²° +- local storage에 객체λ₯Ό μ΄μš©ν•˜μ—¬ λ…Έμ„  데이터와 μ—­ 데이터 ν•¨κ»˜ μ €μž₯ν•˜κΈ° +- μ—­ 관리 데이터와 λ…Έμ„  관리 데이터 연동 +- ꡬ간 관리 νŽ˜μ΄μ§€ UI κ΅¬ν˜„ +- ꡬ간 관리 νŽ˜μ΄μ§€ λ…Έμ„  선택 λ²„νŠΌμ— 이벀트 λ¦¬μŠ€λ„ˆ μ—°κ²°ν•˜μ—¬ ν•΄λ‹Ή λ…Έμ„  정보 λ Œλ”λ§ +- ꡬ간 등둝 κ΅¬ν˜„ +- ꡬ간 제거 κ΅¬ν˜„ +- 노선도 좜λ ₯ νŽ˜μ΄μ§€ UI κ΅¬ν˜„ +- μ˜ˆμ™Έ 상황 검증 + - μ—­ 관리 + - μ€‘λ³΅λœ μ—­ 이름 μž…λ ₯ μ‹œ alert v + - 곡백 μž…λ ₯ μ‹œ alert v + - 2자 미만 μž…λ ₯ μ‹œ alert v + - 노선에 λ“±λ‘λœ μ—­ μ‚­μ œ μ‹œ alert v + - λ…Έμ„  관리 + - μ€‘λ³΅λœ λ…Έμ„  이름 μž…λ ₯ μ‹œ alert v + - 곡백 μž…λ ₯ μ‹œ alert v + - 상행 쒅점역과 ν•˜ν–‰ 쒅점역이 μ€‘λ³΅λ˜λŠ” 노선이 이미 μ‘΄μž¬ν•˜λŠ” 경우 alert v + - 상행 쒅점역과 ν•˜ν–‰ 쒅점역이 λ™μΌν•œ 역인 경우 alert v + - ꡬ간 관리 + - λ…Έμ„ μ—μ„œ 제거 μ‹œ confirm ν›„ μ‚­μ œ v + - 노선에 ν¬ν•¨λœ 역이 2개 μ΄ν•˜μΌ λ•Œ λ…Έμ„ μ—μ„œ 제거 μ‹œ alert v + - ꡬ간 등둝 μ‹œ μΈλ±μŠ€κ°€ 0μ΄κ±°λ‚˜ κ°€μž₯ 끝 인덱슀인 경우 alert v + - μˆœμ„œμ— μˆ«μžκ°€ μ•„λ‹Œ κ°’ μž…λ ₯ λΆˆκ°€ν•˜λ„λ‘ type=number둜 μ„€μ • v + - μˆœμ„œμ— 음수 μž…λ ₯ μ‹œ alert v + - 노선에 이미 μ‘΄μž¬ν•˜λŠ” ꡬ간 이름 등둝 μ‹œ alert v + - μ€‘λ³΅λ˜λŠ” μ—­ 이름, λ…Έμ„  이름 검증 ν•¨μˆ˜ 톡합 v +- λ¦¬νŒ©ν† λ§ + - μžλ°”μŠ€ν¬λ¦½νŠΈ μ»¨λ²€μ…˜μ— λ§žμΆ”μ–΄ validation depth쀄이기 및 λ¦¬νŒ©ν† λ§ v + - 폴더 μž¬κ΅¬μ„± v + - handlers μ»¨λ²€μ…˜μ— λ§žμΆ”μ–΄ validation depth쀄이기 및 λ¦¬νŒ©ν† λ§ v + - html tag κ²€ν†  v + - input value κ²€ν† , ꡬ간 type=number μ‚­μ œ ν›„ 숫자만 μž…λ ₯ κ°€λŠ₯ν•˜λ„λ‘ 검증 μΆ”κ°€ v + - return값이 μ—†λŠ” map λ©”μ†Œλ“œλ₯Ό forEach둜 μˆ˜μ • v + - μƒμˆ˜ν™” v + - css κ²€ν†  v + +## β›“ λ¬Έμ„œ ꡬ쑰 + +```plaintext +β”œβ”€β”€ src +β”‚ β”‚ +β”‚ β”œβ”€β”€ components // μ‚¬μš©μžλ‹¨μ— λ³΄μ—¬μ§ˆ νŽ˜μ΄μ§€λ₯Ό κ΄€λ¦¬ν•˜λŠ” κ³³ +β”‚ β”‚ β”‚ +β”‚ β”‚ β”œβ”€β”€ pages +β”‚ β”‚ β”‚ β”œβ”€β”€ linePages.js // λ…Έμ„  관리 νŽ˜μ΄μ§€ +β”‚ β”‚ β”‚ β”œβ”€β”€ mapPrintPages.js // 노선도 좜λ ₯ νŽ˜μ΄μ§€ +β”‚ β”‚ β”‚ β”œβ”€β”€ sectionPages.js // ꡬ간 관리 νŽ˜μ΄μ§€ +β”‚ β”‚ β”‚ └── stationPages.js // μ—­ 관리 νŽ˜μ΄μ§€ +β”‚ β”‚ β”‚ +β”‚ β”‚ └── app.js // 각 νŽ˜μ΄μ§€λ₯Ό λ Œλ”λ§ν•  λ•Œ λΌμš°νŒ…μ„ λ‹΄λ‹Ήν•˜λŠ” κ³³ +β”‚ β”‚ +β”‚ β”œβ”€β”€ constatns +β”‚ β”‚ β”‚ +β”‚ β”‚ └── tag.js // html tag μƒμˆ˜λ₯Ό λͺ¨μ•„놓은 κ³³ +β”‚ β”‚ +β”‚ β”œβ”€β”€ managers // 각 관리 νŽ˜μ΄μ§€λ₯Ό κ΄€λ¦¬ν•˜λŠ” κ³³ +β”‚ β”‚ β”‚ +β”‚ β”‚ β”œβ”€β”€ handlers +β”‚ β”‚ β”‚ β”œβ”€β”€ lineHanlderPages.js // λ…Έμ„  κ΄€λ ¨ 이벀트 관리 +β”‚ β”‚ β”‚ β”œβ”€β”€ mapPrintHandlerPages.js // 노선도 좜λ ₯ κ΄€λ ¨ 이벀트 관리 +β”‚ β”‚ β”‚ β”œβ”€β”€ sectionHandlerPages.js // ꡬ간 κ΄€λ ¨ 이벀트 관리 +β”‚ β”‚ β”‚ └── stationHandlerPages.js // μ—­ κ΄€λ ¨ 이벀트 관리 +β”‚ β”‚ β”‚ +β”‚ β”‚ └── validation // μœ νš¨μ„±μ„ κ²€μ¦ν•˜λŠ” κ³³ +β”‚ β”‚ β”‚ β”œβ”€β”€ alert.js // μœ νš¨μ„± 검증을 μœ„ν•œ alert messageλ₯Ό μƒμ„±ν•˜λŠ” κ³³ +β”‚ β”‚ β”‚ └── validation.js // μœ νš¨μ„±μ„ 검증을 ν•˜κ³  ν•„μš”ν•œ 데이터λ₯Ό λ°˜ν™˜ν•˜λŠ” κ³³ +β”‚ β”‚ β”‚ +β”‚ β”‚ └── init.js // μ΄ˆκΈ°ν™”λ₯Ό λ‹΄λ‹Ήν•˜λŠ” κ³³ +β”‚ β”‚ β”‚ +β”‚ β”‚ └── render.js // λ Œλ”λ§μ„ λ‹΄λ‹Ήν•˜λŠ” κ³³ +β”‚ β”‚ +β”‚ β”œβ”€β”€ objects +β”‚ β”‚ β”‚ +β”‚ β”‚ └── objects.js // μƒμ„±ν•œ 객체λ₯Ό λͺ¨μ•„λ‘” κ³³ +β”‚ β”‚ +β”‚ β”œβ”€β”€ index.js // μ‹œμž‘μ  +β”‚ β”‚ +β”‚ └── main.js // 초기 μž‘μ—…λ“€μ„ λ‹΄λ‹Ήν•˜λŠ” κ³³ +β”‚ +└── index.html +``` + +## πŸ€¦πŸ»β€β™€οΈ κ³ λ―Όν•œ 지점 + +- λ²„νŠΌμ— 각 κ΄€λ¦¬νŽ˜μ΄μ§€λ₯Ό μ—°κ²°ν•  λ•Œ, λ¦¬μ•‘νŠΈμ—μ„œλŠ” μ»΄ν¬λ„ŒνŠΈλ₯Ό μ‰½κ²Œ λ Œλ”λ§ν•  수 μžˆμ—ˆλŠ”λ° vanilla javascript둜 μ—°κ²°ν•˜λ €κ³ ν•˜λ‹ˆ μ–΄λ €μ› λ‹€. +- μ‚¬μš©μž λ™μž‘μ— 따라 μƒˆλ‘œμš΄ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό μΆ”κ°€ν•˜κ±°λ‚˜ μ‚­μ œν•  λ•Œ, 남은 μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό λ‹€μ‹œ renderν•˜κ³ , 이벀트 λ¦¬μŠ€λ„ˆλ₯Ό λ‹€μ‹œ μΆ”κ°€ν•˜λŠ” λ“± μ—…λ°μ΄νŠΈλœ μƒνƒœλ₯Ό κ΅¬ν˜„ν•˜λŠ” 뢀뢄이 κΉŒλ‹€λ‘œμ› κ³ , 이 방법이 κ³Όμ—° 효율적인 방법이 λ§žλŠ”μ§€ μ˜κ΅¬μ‹¬μ΄ λ“€μ—ˆλ‹€. +- station, line λ“±μ˜ 이름이 μ—¬λŸ¬ ν•¨μˆ˜, λ³€μˆ˜λͺ…에 ν¬ν•¨λ˜μ–΄ 의미 전달이 λͺ…ν™•ν•˜λ©΄μ„œλ„ 가독성이 쒋은 ν•¨μˆ˜λͺ…, λ³€μˆ˜λͺ…을 μ§“λŠ” 것이 μ–΄λ €μ› λ‹€. +- μ˜ˆμ™Έμƒν™©μ„ μ–΄λ””κΉŒμ§€ μ²΄ν¬ν•΄μ•Όν•˜λŠ”μ§€ νŒλ‹¨ν•˜λŠ” 것이 μ–΄λ €μ› λ‹€. + +--- + ## πŸš€ κΈ°λŠ₯ μš”κ΅¬μ‚¬ν•­ ### μ§€ν•˜μ²  μ—­ κ΄€λ ¨ κΈ°λŠ₯ + - μ§€ν•˜μ²  역을 λ“±λ‘ν•˜κ³  μ‚­μ œν•  수 μžˆλ‹€. (단, 노선에 λ“±λ‘λœ 역은 μ‚­μ œν•  수 μ—†λ‹€) - μ€‘λ³΅λœ μ§€ν•˜μ²  μ—­ 이름이 등둝될 수 μ—†λ‹€. - μ§€ν•˜μ²  역은 2κΈ€μž 이상이어야 ν•œλ‹€. - μ§€ν•˜μ²  μ—­μ˜ λͺ©λ‘μ„ μ‘°νšŒν•  수 μžˆλ‹€. ### μ§€ν•˜μ²  λ…Έμ„  κ΄€λ ¨ κΈ°λŠ₯ + - μ§€ν•˜μ²  노선을 λ“±λ‘ν•˜κ³  μ‚­μ œν•  수 μžˆλ‹€. - μ€‘λ³΅λœ μ§€ν•˜μ²  λ…Έμ„  이름이 등둝될 수 μ—†λ‹€. - λ…Έμ„  등둝 μ‹œ 상행 쒅점역과 ν•˜ν–‰ 쒅점역을 μž…λ ₯λ°›λŠ”λ‹€. - μ§€ν•˜μ²  λ…Έμ„ μ˜ λͺ©λ‘μ„ μ‘°νšŒν•  수 μžˆλ‹€. ### μ§€ν•˜μ²  ꡬ간 μΆ”κ°€ κΈ°λŠ₯ + - μ§€ν•˜μ²  노선에 ꡬ간을 μΆ”κ°€ν•˜λŠ” κΈ°λŠ₯은 노선에 역을 μΆ”κ°€ν•˜λŠ” κΈ°λŠ₯이라고도 ν•  수 μžˆλ‹€. - - μ—­κ³Ό 역사이λ₯Ό ꡬ간이라 ν•˜κ³  이 κ΅¬κ°„λ“€μ˜ λͺ¨μŒμ΄ 노선이닀. + - μ—­κ³Ό 역사이λ₯Ό ꡬ간이라 ν•˜κ³  이 κ΅¬κ°„λ“€μ˜ λͺ¨μŒμ΄ 노선이닀. - ν•˜λ‚˜μ˜ 역은 μ—¬λŸ¬κ°œμ˜ 노선에 좔가될 수 μžˆλ‹€. - μ—­κ³Ό μ—­ 사이에 μƒˆλ‘œμš΄ 역이 μΆ”κ°€ 될 수 μžˆλ‹€. - λ…Έμ„ μ—μ„œ κ°ˆλž˜κΈΈμ€ 생길 수 μ—†λ‹€. @@ -24,6 +128,7 @@ ### μ§€ν•˜μ²  ꡬ간 μ‚­μ œ κΈ°λŠ₯ + - 노선에 λ“±λ‘λœ 역을 μ œκ±°ν•  수 μžˆλ‹€. - 쒅점을 μ œκ±°ν•  경우 λ‹€μŒ 역이 쒅점이 λœλ‹€. - 노선에 ν¬ν•¨λœ 역이 λ‘κ°œ μ΄ν•˜μΌ λ•ŒλŠ” 역을 μ œκ±°ν•  수 μ—†λ‹€. @@ -31,6 +136,7 @@ ### μ§€ν•˜μ²  노선에 λ“±λ‘λœ μ—­ 쑰회 κΈ°λŠ₯ + - λ…Έμ„ μ˜ 상행 쒅점뢀터 ν•˜ν–‰ μ’…μ κΉŒμ§€ μ—°κ²°λœ μˆœμ„œλŒ€λ‘œ μ—­ λͺ©λ‘μ„ μ‘°νšŒν•  수 μžˆλ‹€.
@@ -38,32 +144,38 @@ ## πŸ’» ν”„λ‘œκ·Έλž¨ μ‹€ν–‰ κ²°κ³Ό ### 역관리 + ### 노선관리 + ### ꡬ간관리 + ### 노선도 좜λ ₯ - + ## βœ… ν”„λ‘œκ·Έλž˜λ° μš”κ΅¬μ‚¬ν•­ ### 메뉴 λ²„νŠΌ + - μ—­ 관리 button νƒœκ·ΈλŠ” `#station-manager-button` id값을 κ°€μ§„λ‹€. - λ…Έμ„  관리 button νƒœκ·ΈλŠ” `#line-manager-button` id값을 κ°€μ§„λ‹€. - ꡬ간 관리 button νƒœκ·ΈλŠ” `#section-manager-button` id값을 κ°€μ§„λ‹€. - μ§€ν•˜μ²  노선도 좜λ ₯ 관리 button νƒœκ·ΈλŠ” `#map-print-manager-button` id값을 κ°€μ§„λ‹€. ### μ§€ν•˜μ²  μ—­ κ΄€λ ¨ κΈ°λŠ₯ + - μ§€ν•˜μ²  역을 μž…λ ₯ν•˜λŠ” input νƒœκ·ΈλŠ” `#station-name-input` id값을 κ°€μ§„λ‹€. - μ§€ν•˜μ²  역을 μΆ”κ°€ν•˜λŠ” button νƒœκ·ΈλŠ” `#station-add-button` id값을 κ°€μ§„λ‹€. - μ§€ν•˜μ²  역을 μ‚­μ œν•˜λŠ” button νƒœκ·ΈλŠ” `.station-delete-button` class값을 κ°€μ§„λ‹€. ### μ§€ν•˜μ²  λ…Έμ„  κ΄€λ ¨ κΈ°λŠ₯ + - μ§€ν•˜μ²  λ…Έμ„ μ˜ 이름을 μž…λ ₯ν•˜λŠ” input νƒœκ·ΈλŠ” `#line-name-input` id값을 κ°€μ§„λ‹€. - μ§€ν•˜μ²  λ…Έμ„ μ˜ 상행 쒅점을 μ„ νƒν•˜λŠ” select νƒœκ·ΈλŠ” `#line-start-station-selector` id값을 κ°€μ§„λ‹€. - μ§€ν•˜μ²  λ…Έμ„ μ˜ ν•˜ν–‰ 쒅점을 μ„ νƒν•˜λŠ” select νƒœκ·ΈλŠ” `#line-end-station-selector` id값을 κ°€μ§„λ‹€. @@ -71,6 +183,7 @@ - μ§€ν•˜μ²  노선을 μ‚­μ œν•˜λŠ” button νƒœκ·ΈλŠ” `.line-delete-button` class값을 κ°€μ§„λ‹€. ### μ§€ν•˜μ²  ꡬ간 μΆ”κ°€ κΈ°λŠ₯ + - μ§€ν•˜μ²  노선을 μ„ νƒν•˜λŠ” button νƒœκ·ΈλŠ” `.section-line-menu-button` class값을 κ°€μ§„λ‹€. - μ§€ν•˜μ²  ꡬ간을 μ„€μ •ν•  μ—­ select νƒœκ·ΈλŠ” `#section-station-selector` id값을 κ°€μ§„λ‹€. - μ§€ν•˜μ²  κ΅¬κ°„μ˜ μˆœμ„œλ₯Ό μž…λ ₯ν•˜λŠ” input νƒœκ·ΈλŠ” `#section-order-input` id값을 κ°€μ§„λ‹€. @@ -78,6 +191,7 @@ - μ§€ν•˜μ²  ꡬ간을 μ œκ±°ν•˜λŠ” button νƒœκ·ΈλŠ” `.section-delete-button` class값을 κ°€μ§„λ‹€. ### μ§€ν•˜μ²  노선도 좜λ ₯ κΈ°λŠ₯ + - μ§€ν•˜μ²  노선도 좜λ ₯ λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ `
` νƒœκ·Έλ₯Ό λ§Œλ“€κ³  ν•΄λ‹Ή νƒœκ·Έ 내뢀에 노선도λ₯Ό 좜λ ₯ν•œλ‹€. ### κΈ°μ‘΄ μš”κ΅¬μ‚¬ν•­ @@ -101,7 +215,8 @@ - [https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals) ### μΆ”κ°€λœ μš”κ΅¬μ‚¬ν•­ -- [data](https://developer.mozilla.org/ko/docs/Learn/HTML/Howto/%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%86%8D%EC%84%B1_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0)속성을 ν™œμš©ν•˜μ—¬ html νƒœκ·Έμ— μ—­, λ…Έμ„ , κ΅¬κ°„μ˜ μœ μΌν•œ 데이터 값듀을 κ΄€λ¦¬ν•œλ‹€. + +- [data](https://developer.mozilla.org/ko/docs/Learn/HTML/Howto/%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%86%8D%EC%84%B1_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0)속성을 ν™œμš©ν•˜μ—¬ html νƒœκ·Έμ— μ—­, λ…Έμ„ , κ΅¬κ°„μ˜ μœ μΌν•œ 데이터 값듀을 κ΄€λ¦¬ν•œλ‹€. - [localStorage](https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage)λ₯Ό μ΄μš©ν•˜μ—¬, μƒˆλ‘œκ³ μΉ¨ν•˜λ”λΌλ„ κ°€μž₯ μ΅œκ·Όμ— μž‘μ—…ν•œ 정보듀을 뢈러올 수 μžˆλ„λ‘ ν•œλ‹€.
diff --git a/index.html b/index.html index fc99deac2..dd25c7316 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,7 @@
-

πŸš‡ μ§€ν•˜μ²  노선도 관리

+

πŸš‡ μ§€ν•˜μ²  노선도 관리

diff --git a/src/components/app.js b/src/components/app.js new file mode 100644 index 000000000..bf3d1ae95 --- /dev/null +++ b/src/components/app.js @@ -0,0 +1,20 @@ +import stationManagerPage from "./pages/stationPage.js"; +import lineManagerPage from "./pages/linePage.js"; +import sectionManagerPage from "./pages/sectionPage.js"; +import mapPrintManagerPage from "./pages/mapPrintPage.js"; + +export default function app(pageName, subwayDatas) { + let app = ``; + + if (pageName === "station") { + app = stationManagerPage(subwayDatas); + } else if (pageName === "line") { + app = lineManagerPage(subwayDatas); + } else if (pageName === "section") { + app = sectionManagerPage(subwayDatas); + } else if (pageName === "map") { + app = mapPrintManagerPage(subwayDatas); + } + + return app; +} diff --git a/src/components/pages/linePage.js b/src/components/pages/linePage.js new file mode 100644 index 000000000..b9814c3ea --- /dev/null +++ b/src/components/pages/linePage.js @@ -0,0 +1,54 @@ +import { LINE_NAME_INPUT, LINE_START_STATION_SELECTOR, LINE_END_STATION_SELECTOR, LINE_ADD_BUTTON, LINE_DELETE_BUTTON } from "../../constants/tag.js"; + +function lineManagerPage(subwayDatas) { + let options = subwayDatas.subwayStations.map((station) => ``); + let table = ``; + + subwayDatas.lines && + subwayDatas.lines.forEach( + (line) => + (table += ` + ${line.name} + ${line.stops[0]} + ${line.stops[line.stops.length - 1]} + + `) + ); + + let lineManager = ` +

λ…Έμ„  이름

+ +
+
+ + +
+ + +
+
+ +

πŸš‰μ§€ν•˜μ²  λ…Έμ„  λͺ©λ‘

+ + + + + + + + + + + ${table} + +
λ…Έμ„  이름상행 μ’…μ μ—­ν•˜ν–‰ 쒅점역섀정
+ `; + + return lineManager; +} + +export default lineManagerPage; diff --git a/src/components/pages/mapPrintPage.js b/src/components/pages/mapPrintPage.js new file mode 100644 index 000000000..a1991ea6c --- /dev/null +++ b/src/components/pages/mapPrintPage.js @@ -0,0 +1,10 @@ +function mapPrintManagerPage(subwayDatas) { + const map = subwayDatas.lines.reduce((prev, line) => { + const insideOfUl = line.stops.reduce((prev, stop) => prev + `
  • ${stop}
  • `, ""); + return prev + ``; + }, ""); + + return `
    ${map}
    `; +} + +export default mapPrintManagerPage; diff --git a/src/components/pages/sectionPage.js b/src/components/pages/sectionPage.js new file mode 100644 index 000000000..d05d93eb7 --- /dev/null +++ b/src/components/pages/sectionPage.js @@ -0,0 +1,69 @@ +import { SECTION_LINE_MENU_BUTTON, SECTION_STATION_SELECTOR, SECTION_ORDER_INPUT, SECTION_ADD_BUTTON, SECTION_DELETE_BUTTON } from "../../constants/tag.js"; + +function sectionManagerPage(subwayDatas) { + let lines = ``; + + subwayDatas.lines && + subwayDatas.lines.forEach( + (line) => + (lines += ` + `) + ); + + let sectionManager = ` +

    ꡬ간을 μˆ˜μ •ν•  노선을 μ„ νƒν•΄μ£Όμ„Έμš”.

    +
    + ${lines} +
    + `; + + if (subwayDatas.targetLine) { + let targetLine = subwayDatas.targetLine; + let options = subwayDatas.subwayStations.map((station) => ``); + let table = ``; + + subwayDatas.lines.forEach((line) => { + if (line.name === targetLine) { + line.stops.forEach((stop, idx) => { + table += ` + + ${idx} + ${stop} + + `; + }); + } + }); + + sectionManager += ` +
    +

    ${targetLine} 관리

    +
    ꡬ간 등둝
    + + + +
    +
    + + + + + + + + + + ${table} + +
    μˆœμ„œμ—­ 이름섀정
    +
    `; + } + + return sectionManager; +} + +export default sectionManagerPage; diff --git a/src/components/pages/stationPage.js b/src/components/pages/stationPage.js new file mode 100644 index 000000000..73cd92317 --- /dev/null +++ b/src/components/pages/stationPage.js @@ -0,0 +1,38 @@ +import { STATION_NAME_INPUT, STATION_ADD_BUTTON, STATION_DELETE_BUTTON } from "../../constants/tag.js"; + +function stationManagerPage(subwayDatas) { + let table = ``; + + let stations = subwayDatas.subwayStations; + stations && + stations.forEach((station) => { + table += ` + ${station.name} + + + + `; + }); + + let stationManager = ` +

    μ—­ 이름

    + + +

    πŸš‰μ§€ν•˜μ²  μ—­ λͺ©λ‘

    + + + + + + + + + + ${table} + +
    μ—­ 이름섀정
    + `; + return stationManager; +} + +export default stationManagerPage; diff --git a/src/constants/tag.js b/src/constants/tag.js new file mode 100644 index 000000000..8cc7958c5 --- /dev/null +++ b/src/constants/tag.js @@ -0,0 +1,37 @@ +const STATION_MANAGER_BUTTON = "station-manager-button"; +const LINE_MANAGER_BUTTON = "line-manager-button"; +const SECTION_MANAGER_BUTTON = "section-manager-button"; +const MAP_PRINT_MANAGER_BUTTON = "map-print-manager-button"; +const STATION_NAME_INPUT = "station-name-input"; +const STATION_ADD_BUTTON = "station-add-button"; +const STATION_DELETE_BUTTON = "station-delete-button"; +const LINE_NAME_INPUT = "line-name-input"; +const LINE_START_STATION_SELECTOR = "line-start-station-selector"; +const LINE_END_STATION_SELECTOR = "line-end-station-selector"; +const LINE_ADD_BUTTON = "line-add-button"; +const LINE_DELETE_BUTTON = "line-delete-button"; +const SECTION_LINE_MENU_BUTTON = "section-line-menu-button"; +const SECTION_STATION_SELECTOR = "section-station-selector"; +const SECTION_ORDER_INPUT = "section-order-input"; +const SECTION_ADD_BUTTON = "section-add-button"; +const SECTION_DELETE_BUTTON = "section-delete-button"; + +export { + STATION_MANAGER_BUTTON, + LINE_MANAGER_BUTTON, + SECTION_MANAGER_BUTTON, + MAP_PRINT_MANAGER_BUTTON, + STATION_NAME_INPUT, + STATION_ADD_BUTTON, + STATION_DELETE_BUTTON, + LINE_NAME_INPUT, + LINE_START_STATION_SELECTOR, + LINE_END_STATION_SELECTOR, + LINE_ADD_BUTTON, + LINE_DELETE_BUTTON, + SECTION_LINE_MENU_BUTTON, + SECTION_STATION_SELECTOR, + SECTION_ORDER_INPUT, + SECTION_ADD_BUTTON, + SECTION_DELETE_BUTTON, +}; diff --git a/src/index.js b/src/index.js index e69de29bb..88d36dfbc 100644 --- a/src/index.js +++ b/src/index.js @@ -0,0 +1,3 @@ +import main from "./main.js"; + +main(); diff --git a/src/main.js b/src/main.js new file mode 100644 index 000000000..88fd7ef11 --- /dev/null +++ b/src/main.js @@ -0,0 +1,19 @@ +import { initHTML, addEventToMainBtns } from "./managers/init.js"; +import render from "./managers/render.js"; +import app from "./components/app.js"; + +export default function main() { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + + if (!subwayDatas) { + let subwayDatas = { + subwayStations: [], + lines: [], + }; + localStorage.setItem("subwayDatas", JSON.stringify(subwayDatas)); + } + + initHTML(); + render(app()); + addEventToMainBtns(); +} diff --git a/src/managers/handlers/lineHandlers.js b/src/managers/handlers/lineHandlers.js new file mode 100644 index 000000000..187e90783 --- /dev/null +++ b/src/managers/handlers/lineHandlers.js @@ -0,0 +1,64 @@ +import render from "../render.js"; +import app from "../../components/app.js"; +import { Line } from "../../objects/objects.js"; +import { validateInput, validateStartAndEndStations } from "../validation/validation.js"; +import { LINE_NAME_INPUT, LINE_ADD_BUTTON, LINE_DELETE_BUTTON, LINE_START_STATION_SELECTOR, LINE_END_STATION_SELECTOR } from "../../constants/tag.js"; + +function onLineHandler() { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + + render(app("line", subwayDatas)); + subwayDatas && updateEvent(); +} + +function updateEvent() { + document.getElementById(LINE_ADD_BUTTON).addEventListener("click", onAddLineHandler); + + let deleteBtns = document.getElementsByClassName(LINE_DELETE_BUTTON); + for (let i = 0; i < deleteBtns.length; i++) { + deleteBtns[i].addEventListener("click", onDeleteLineHandler); + } +} + +function onAddLineHandler() { + let lineName = validateInput(document.getElementById(LINE_NAME_INPUT).value, LINE_NAME_INPUT); + + if (lineName !== "") { + let startAndEndStations = [document.getElementById(LINE_START_STATION_SELECTOR).value, document.getElementById(LINE_END_STATION_SELECTOR).value]; + let validatedStartAndEndStations = validateStartAndEndStations(startAndEndStations); + validatedStartAndEndStations && addLine(lineName, validatedStartAndEndStations); + } +} + +function addLine(lineName, validatedStartAndEndStations) { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let line = new Line(lineName, validatedStartAndEndStations); + let endStops = [line.stops[0], line.stops[line.stops.length - 1]]; + let startStopIdx = subwayDatas.subwayStations.findIndex((station) => station.name === endStops[0]); + let endStopIdx = subwayDatas.subwayStations.findIndex((station) => station.name === endStops[1]); + + subwayDatas.subwayStations[startStopIdx].line.push(lineName); + subwayDatas.subwayStations[endStopIdx].line.push(lineName); + subwayDatas.lines.push(line); + + localStorage.setItem("subwayDatas", JSON.stringify(subwayDatas)); + render(app("line", subwayDatas)); + subwayDatas && updateEvent(); +} + +function onDeleteLineHandler() { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let deleteTarget = event.target.parentNode.parentNode.childNodes[1].outerText; + let deleteTargetIdx = subwayDatas.lines.findIndex((line) => line.name === deleteTarget); + + subwayDatas.subwayStations.forEach((station) => { + station.line.splice(station.line.indexOf(deleteTarget), 1); + }); + subwayDatas.lines.splice(deleteTargetIdx, 1); + + localStorage.setItem("subwayDatas", JSON.stringify(subwayDatas)); + render(app("line", subwayDatas)); + updateEvent(); +} + +export { onLineHandler }; diff --git a/src/managers/handlers/mapPrintHandler.js b/src/managers/handlers/mapPrintHandler.js new file mode 100644 index 000000000..ce9780678 --- /dev/null +++ b/src/managers/handlers/mapPrintHandler.js @@ -0,0 +1,10 @@ +import render from "../render.js"; +import app from "../../components/app.js"; + +function onMapPrintHandler() { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + + render(app("map", subwayDatas)); +} + +export { onMapPrintHandler }; diff --git a/src/managers/handlers/sectionHandler.js b/src/managers/handlers/sectionHandler.js new file mode 100644 index 000000000..081b2d9dd --- /dev/null +++ b/src/managers/handlers/sectionHandler.js @@ -0,0 +1,93 @@ +import render from "../render.js"; +import app from "../../components/app.js"; +import { validateSectionDelete, validateOrder, validateSection } from "../validation/validation.js"; +import { SECTION_LINE_MENU_BUTTON, SECTION_STATION_SELECTOR, SECTION_ORDER_INPUT, SECTION_ADD_BUTTON, SECTION_DELETE_BUTTON } from "../../constants/tag.js"; + +function onSectionHandler() { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + + subwayDatas.targetLine = ``; + renderAndUpdateEvent(subwayDatas); +} + +function onLineSelectHandler() { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let targetLine = event.target.innerText; + + subwayDatas.targetLine = targetLine; + localStorage.setItem("subwayDatas", JSON.stringify(subwayDatas)); + renderAndUpdateEvent(subwayDatas); +} + +function onAddSectionHandler() { + let station = validateSection(document.getElementById(SECTION_STATION_SELECTOR).value); + let order = validateOrder(document.getElementById(SECTION_ORDER_INPUT).value); + + if (station && order) { + addSection(station, order); + } +} + +function addSection(station, order) { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let targetLine = subwayDatas.targetLine; + let targetLineIdx = subwayDatas.lines.findIndex((line) => line.name === targetLine); + + subwayDatas.lines[targetLineIdx].stops.splice(order, 0, station); + subwayDatas.subwayStations.forEach((addedStation, idx) => { + if (station === addedStation.name) { + subwayDatas.subwayStations[idx].line.push(subwayDatas.targetLine); + } + }); + + localStorage.setItem("subwayDatas", JSON.stringify(subwayDatas)); + renderAndUpdateEvent(subwayDatas); +} + +function onSectionDeleteHandler() { + let deleteTargetIdx = event.target.parentNode.parentNode.childNodes[1].outerText; + let deleteTarget = event.target.parentNode.parentNode.childNodes[3].outerText; + let deleteConfirmed = validateSectionDelete(); + + if (deleteConfirmed === true) { + sectionDelete(deleteTarget, deleteTargetIdx); + } +} + +function sectionDelete(deleteTarget, deleteTargetIdx) { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let targetLineIdx = subwayDatas.lines.findIndex((line) => line.name === subwayDatas.targetLine); + + subwayDatas.lines[targetLineIdx].stops.splice(deleteTargetIdx, 1); + subwayDatas.subwayStations.forEach((station) => { + if (station.name === deleteTarget) { + station.line.splice(subwayDatas.subwayStations.indexOf(subwayDatas.targetLine), 1); + } + }); + + localStorage.setItem("subwayDatas", JSON.stringify(subwayDatas)); + renderAndUpdateEvent(subwayDatas); +} + +function renderAndUpdateEvent(subwayDatas) { + render(app("section", subwayDatas)); + updateEventToBtns(); +} + +function updateEventToBtns() { + let sectionBtn = document.getElementById(SECTION_ADD_BUTTON); + sectionBtn && document.getElementById(SECTION_ADD_BUTTON).addEventListener("click", onAddSectionHandler); + + let lineBtns = document.getElementsByClassName(SECTION_LINE_MENU_BUTTON); + for (let i = 0; i < lineBtns.length; i++) { + let eachBtn = lineBtns[i]; + eachBtn.addEventListener("click", onLineSelectHandler); + } + + let deleteBtns = document.getElementsByClassName(SECTION_DELETE_BUTTON); + for (let i = 0; i < deleteBtns.length; i++) { + deleteBtns[i].addEventListener("click", onSectionDeleteHandler); + } +} + +export { onSectionHandler }; diff --git a/src/managers/handlers/stationHandlers.js b/src/managers/handlers/stationHandlers.js new file mode 100644 index 000000000..44914fb06 --- /dev/null +++ b/src/managers/handlers/stationHandlers.js @@ -0,0 +1,50 @@ +import render from "../render.js"; +import app from "../../components/app.js"; +import { validateInput, validateStationDelete } from "../validation/validation.js"; +import { Station } from "../../objects/objects.js"; +import { STATION_NAME_INPUT, STATION_ADD_BUTTON, STATION_DELETE_BUTTON } from "../../constants/tag.js"; + +function renderAndUpdateEvent(subwayDatas) { + render(app("station", subwayDatas)); + updateEvent(); +} +function onStationHandler() { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + + renderAndUpdateEvent(subwayDatas); +} + +function onAddStationHandler() { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let stationName = validateInput(document.getElementById(STATION_NAME_INPUT).value, STATION_NAME_INPUT); + + if (stationName !== "") { + let subwayStations = new Station(stationName); + subwayDatas.subwayStations.push(subwayStations); + localStorage.setItem("subwayDatas", JSON.stringify(subwayDatas)); + renderAndUpdateEvent(subwayDatas); + } +} + +function updateEvent() { + document.getElementById(STATION_ADD_BUTTON).addEventListener("click", onAddStationHandler); + + let deleteBtns = document.getElementsByClassName(STATION_DELETE_BUTTON); + for (let i = 0; i < deleteBtns.length; i++) { + deleteBtns[i].addEventListener("click", onDeleteStationHandler); + } +} + +function onDeleteStationHandler() { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let deleteTarget = validateStationDelete(event.target.parentNode.parentNode.childNodes[1].outerText); + + if (deleteTarget !== "") { + let deleteTargetIdx = subwayDatas.subwayStations.findIndex((station) => station.name === deleteTarget); + subwayDatas.subwayStations.splice(deleteTargetIdx, 1); + localStorage.setItem("subwayDatas", JSON.stringify(subwayDatas)); + renderAndUpdateEvent(subwayDatas); + } +} + +export { onStationHandler }; diff --git a/src/managers/init.js b/src/managers/init.js new file mode 100644 index 000000000..04eb6b8a4 --- /dev/null +++ b/src/managers/init.js @@ -0,0 +1,30 @@ +import { onStationHandler } from "./handlers/stationHandlers.js"; +import { onLineHandler } from "./handlers/lineHandlers.js"; +import { onSectionHandler } from "./handlers/sectionHandler.js"; +import { onMapPrintHandler } from "./handlers/mapPrintHandler.js"; +import { STATION_MANAGER_BUTTON, LINE_MANAGER_BUTTON, SECTION_MANAGER_BUTTON, MAP_PRINT_MANAGER_BUTTON } from "../constants/tag.js"; + +function initHTML() { + const buttonBox = document.createElement("div"); + + buttonBox.innerHTML = ` + + + + `; + document.body.append(buttonBox); + + const mainBox = document.createElement("div"); + + mainBox.id = "main-box"; + document.body.append(mainBox); +} + +function addEventToMainBtns() { + document.getElementById(STATION_MANAGER_BUTTON).addEventListener("click", onStationHandler); + document.getElementById(LINE_MANAGER_BUTTON).addEventListener("click", onLineHandler); + document.getElementById(SECTION_MANAGER_BUTTON).addEventListener("click", onSectionHandler); + document.getElementById(MAP_PRINT_MANAGER_BUTTON).addEventListener("click", onMapPrintHandler); +} + +export { initHTML, addEventToMainBtns }; diff --git a/src/managers/render.js b/src/managers/render.js new file mode 100644 index 000000000..58136fdc4 --- /dev/null +++ b/src/managers/render.js @@ -0,0 +1,3 @@ +export default function render(app) { + document.getElementById("main-box").innerHTML = app; +} diff --git a/src/managers/validation/alert.js b/src/managers/validation/alert.js new file mode 100644 index 000000000..00c6f5463 --- /dev/null +++ b/src/managers/validation/alert.js @@ -0,0 +1,139 @@ +function stationNameAlert(inputValue) { + return uniqueStationNameAlert(inputValue) || spaceAlert(inputValue) || underTwoCharacterAlert(inputValue); +} + +function uniqueStationNameAlert(inputValue) { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let alertMsg = ""; + + subwayDatas.subwayStations.map((station) => { + if (station.name === inputValue) { + alertMsg = "μ€‘λ³΅λœ μ—­ 이름을 μž…λ ₯ν•˜μ…¨μŠ΅λ‹ˆλ‹€."; + } + }); + + return alertMsg; +} + +function spaceAlert(inputValue) { + let alertMsg = ""; + + if (inputValue === "") { + alertMsg = "곡백을 μž…λ ₯ν•˜μ…¨μŠ΅λ‹ˆλ‹€."; + } + + return alertMsg; +} + +function underTwoCharacterAlert(inputValue) { + let alertMsg = ""; + + if (inputValue.length < 2) { + alertMsg = "2κΈ€μž μ΄μƒμœΌλ‘œ μž…λ ₯ν•΄μ£Όμ„Έμš”."; + } + + return alertMsg; +} + +function stationDeleteAlert(deleteTarget) { + return inlineAlert(deleteTarget); +} + +function inlineAlert(deleteTarget) { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let alertMsg = ""; + + subwayDatas.subwayStations.forEach((station, idx) => { + if (station.name === deleteTarget && subwayDatas.subwayStations[idx].line.length >= 1) { + alertMsg = "노선에 ν¬ν•¨λœ 역은 μ‚­μ œν•  수 μ—†μŠ΅λ‹ˆλ‹€."; + } + }); + + return alertMsg; +} + +function lineNameAlert(inputValue) { + return ununiqueLineNameAlert(inputValue) || spaceAlert(inputValue); +} + +function ununiqueLineNameAlert(inputValue) { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let alertMsg = ""; + + subwayDatas.lines.forEach((line) => { + if (line.name === inputValue) { + alertMsg = "μ€‘λ³΅λœ λ…Έμ„  이름을 μž…λ ₯ν•˜μ…¨μŠ΅λ‹ˆλ‹€."; + } + }); + + return alertMsg; +} + +function startAndEndStationAlert(startAndEndStations) { + return unUniqueLineAlert(startAndEndStations) || sameStartAndEndStationAlert(startAndEndStations); +} + +function unUniqueLineAlert(startAndEndStations) { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let alertMsg = ""; + + subwayDatas.lines.forEach((line) => { + if (line.stops[0] === startAndEndStations[0] && line.stops[line.stops.length - 1] === startAndEndStations[1]) { + alertMsg = "상행, ν•˜ν–‰ 쒅점역이 μ€‘λ³΅λ˜λŠ” 노선이 이미 μ‘΄μž¬ν•©λ‹ˆλ‹€."; + } + }); + + return alertMsg; +} + +function sameStartAndEndStationAlert(startAndEndStations) { + let alertMsg = ""; + + if (startAndEndStations[0] === startAndEndStations[1]) { + alertMsg = "상행 쒅점과 ν•˜ν–‰ μ’…μ μœΌλ‘œ λ™μΌν•œ 역을 μ„ νƒν•˜μ…¨μŠ΅λ‹ˆλ‹€."; + } + + return alertMsg; +} + +function sectionDeleteAlert() { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let alertMsg = ""; + let targetLineIdx = subwayDatas.lines.findIndex((line) => line.name === subwayDatas.targetLine); + + if (subwayDatas.lines[targetLineIdx].stops.length <= 2) { + alertMsg = "노선에 ν¬ν•¨λœ 역이 2개 μ΄ν•˜μΌ λ•Œμ—λŠ” μ‚­μ œν•  수 μ—†μŠ΅λ‹ˆλ‹€."; + } + + return alertMsg; +} + +function orderAlert(order) { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let alertMsg = ""; + let targetLineIdx = subwayDatas.lines.findIndex((line) => line.name === subwayDatas.targetLine); + + if (isNaN(Number(order))) { + alertMsg = "숫자만 μž…λ ₯ κ°€λŠ₯ν•©λ‹ˆλ‹€."; + } else if (0 > order) { + alertMsg = "μ–‘μˆ˜λ§Œ μž…λ ₯ κ°€λŠ₯ν•©λ‹ˆλ‹€."; + } else if (order <= 0 || subwayDatas.lines[targetLineIdx].stops.length <= order) { + alertMsg = "μ—­κ³Ό μ—­ μ‚¬μ΄μ—λ§Œ ꡬ간 등둝이 κ°€λŠ₯ν•©λ‹ˆλ‹€."; + } + + return alertMsg; +} + +function sectionAlert(stationName) { + let subwayDatas = JSON.parse(localStorage.getItem("subwayDatas")); + let alertMsg = ""; + let targetLineIdx = subwayDatas.lines.findIndex((line) => line.name === subwayDatas.targetLine); + + if (subwayDatas.lines[targetLineIdx].stops.indexOf(stationName) !== -1) { + alertMsg = "이미 ꡬ간에 λ“±λ‘λœ μ—­μž…λ‹ˆλ‹€."; + } + + return alertMsg; +} + +export { stationNameAlert, stationDeleteAlert, lineNameAlert, startAndEndStationAlert, sectionDeleteAlert, orderAlert, sectionAlert }; diff --git a/src/managers/validation/validation.js b/src/managers/validation/validation.js new file mode 100644 index 000000000..c277bd9bd --- /dev/null +++ b/src/managers/validation/validation.js @@ -0,0 +1,78 @@ +import { stationNameAlert, stationDeleteAlert, lineNameAlert, startAndEndStationAlert, sectionDeleteAlert, orderAlert, sectionAlert } from "./alert.js"; +import { STATION_NAME_INPUT } from "../../constants/tag.js"; + +function validateInput(input, inputTagID) { + let alertMsg = ""; + + inputTagID === STATION_NAME_INPUT ? (alertMsg = stationNameAlert(input)) : (alertMsg = lineNameAlert(input)); + + if (alertMsg) { + alert(alertMsg); + document.getElementById(inputTagID).focus(); + + return ""; + } + + return input; +} + +function validateStationDelete(deleteTarget) { + let alertMsg = stationDeleteAlert(deleteTarget); + + if (alertMsg !== "") { + alert(alertMsg); + + return ""; + } + return deleteTarget; +} + +function validateSectionDelete() { + let alertMsg = sectionDeleteAlert(); + + if (alertMsg !== "") { + alert(alertMsg); + + return ""; + } + + return confirm("μ •λ§λ‘œ λ…Έμ„ μ—μ„œ μ œκ±°ν•˜κ² μŠ΅λ‹ˆκΉŒ?"); +} + +function validateStartAndEndStations(startAndEndStations) { + let alertMsg = startAndEndStationAlert(startAndEndStations); + + if (alertMsg !== "") { + alert(alertMsg); + + return ""; + } + + return startAndEndStations; +} + +function validateOrder(order) { + let alertMsg = orderAlert(order); + + if (alertMsg !== "") { + alert(alertMsg); + + return ""; + } + + return order; +} + +function validateSection(stationName) { + let alertMsg = sectionAlert(stationName); + + if (alertMsg !== "") { + alert(alertMsg); + + return ""; + } + + return stationName; +} + +export { validateInput, validateStationDelete, validateStartAndEndStations, validateSectionDelete, validateOrder, validateSection }; diff --git a/src/objects/objects.js b/src/objects/objects.js new file mode 100644 index 000000000..4116878da --- /dev/null +++ b/src/objects/objects.js @@ -0,0 +1,11 @@ +function Line(name, endStops) { + this.name = name; + this.stops = [endStops[0], endStops[1]]; +} + +function Station(name) { + this.name = name; + this.line = []; +} + +export { Line, Station };