├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .github
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
├── auto_assign.yml
└── workflows
│ └── build.yml
├── .gitignore
├── LICENSE
├── README.md
├── assets
├── css
│ ├── common.css
│ ├── index.css
│ ├── modules
│ │ └── modal.css
│ └── pages
│ │ ├── coffee-material.css
│ │ └── coffee-order.css
└── images
│ ├── btn-bg1.png
│ ├── closed.jpg
│ ├── coffee-cup.gif
│ └── oop-cafe.png
├── index.html
├── package-lock.json
├── package.json
├── src
└── main.ts
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 |
7 | [*.{js,json,yml}]
8 | charset = utf-8
9 | indent_style = space
10 | indent_size = 2
11 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # don't ever lint node_modules
2 | node_modules
3 | # don't lint build output (make sure it's set to your correct build folder name)
4 | dist
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2021": true,
5 | "jest": true,
6 | "node": true
7 | },
8 | "extends": [
9 | "eslint:recommended",
10 | "prettier",
11 | "plugin:@typescript-eslint/eslint-recommended",
12 | "plugin:@typescript-eslint/recommended"
13 | ],
14 | "plugins": [
15 | "prettier",
16 | "@typescript-eslint"
17 | ],
18 | "parserOptions": {
19 | "parser": "@typescript-eslint/parser",
20 | "ecmaVersion": 12,
21 | "sourceType": "module"
22 | },
23 | "rules": {
24 | "@typescript-eslint/no-var-requires": 0,
25 | "prettier/prettier": [
26 | "error",
27 | {
28 | "singleQuote": true,
29 | "semi": true,
30 | "useTabs": false,
31 | "tabWidth": 2,
32 | "trailingComma": "all",
33 | "printWidth": 120,
34 | "bracketSpacing": true,
35 | "arrowParens": "avoid",
36 | "endOfLine": "auto"
37 | }
38 | ]
39 | }
40 | }
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## 🔎 개요
2 |
3 | -
4 |
5 |
6 |
7 | ## 📝 진행상황
8 |
9 | - [ ]
10 | - [ ]
11 |
12 |
13 |
14 | ## 💬 의견
15 |
16 | -
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## 🔎 개요
2 |
3 | - closed #
4 |
5 | -
6 |
7 |
8 |
9 | ## 📝 진행상황
10 |
11 | - [ ]
12 | - [ ]
13 |
14 |
15 |
16 | ## 🖼 스크린샷
17 |
18 | ## 💬 의견
19 |
20 | -
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.github/auto_assign.yml:
--------------------------------------------------------------------------------
1 | # Set to true to add reviewers to pull requests
2 | addReviewers: true
3 |
4 | # Set to true to add assignees to pull requests
5 | addAssignees: author
6 |
7 | # A list of reviewers to be added to pull requests (GitHub user name)
8 | reviewers:
9 | - InSeong-So
10 |
11 | # A number of reviewers added to the pull request
12 | # Set 0 to add all the reviewers (default: 0)
13 | numberOfReviewers: 0
14 | # A list of assignees, overrides reviewers if set
15 | assignees:
16 | - InSeong-So
17 |
18 | # A number of assignees to add to the pull request
19 | # Set to 0 to add all of the assignees.
20 | # Uses numberOfReviewers if unset.
21 | # numberOfAssignees: 2
22 |
23 | # A list of keywords to be skipped the process that add reviewers if pull requests include it
24 | # skipKeywords:
25 | # - wip
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Timer Build CI
2 |
3 | # 구독할 이벤트
4 | on:
5 | push:
6 | branches: [main]
7 | pull_request:
8 | branches: [main]
9 |
10 | # jobs 단위로 개별 서버(정확히는 Docker 컨테이너 단위라고 한다.)에서 작업이 수행된다.
11 | # 각 작업은 병렬로 실행 된다고 하는데, needs: build와 같이 표시해서 기다릴 수도 있다.
12 | jobs:
13 | build:
14 | # Ubuntu, Windows, MacOS를 지원한다.
15 | runs-on: ubuntu-latest
16 |
17 | # 영상에서도 소개됐는데, 변수 개념으로 생각하면 된다.
18 | # node-version 과 같이 배열로 돼있으면, 해당 원소를 순회하면서 작업이 반복해서 실행된다.
19 | # matrix 때문인지 배열만 되는 것 같다. (TODO)
20 | # 응용해서 runs-on에 여러 OS에서 돌릴 수도 있다.
21 | strategy:
22 | matrix:
23 | node-version: [14.x] # 템플릿 기본값: [10.x, 12.x, 14.x]
24 |
25 | # uses 개념은 다른 사람이 작성한 내용을 실행하는 개념이다.
26 | # actions/checkout: GitHub의 마지막 커밋으로 Checkout 한다.
27 | # actions/setup-node: Node.js를 설치한다.
28 | # run 개념은 명령어를 실행한다. 셸 스크립트와 동일하다.
29 | steps:
30 | - uses: actions/checkout@v2
31 | - name: Timer Package Setup ${{ matrix.node-version }}
32 | uses: actions/setup-node@v1
33 | with:
34 | node-version: ${{ matrix.node-version }}
35 |
36 | # --if-present 옵션은 npm 스크립트가 존재할 때만 실행시키라는 의미이다.
37 | # 만약 build 스크립트가 없는 경우, 오류 없이 지나간다.
38 | - name: npm run install and build
39 | run: |
40 | npm install
41 | npm run build
42 |
43 | - name: Git init
44 | run: |
45 | git config --global user.name '${{github.actor}}'
46 | git config --global user.email '${{github.actor}}@users.noreply.github.com'
47 |
48 | - name: Git add
49 | run: git add --force ./dist
50 |
51 | - name: Git commit
52 | run: git commit -m "publish"
53 |
54 | - name: Push dist to branch
55 | run: |
56 | git subtree split --branch dist --prefix dist
57 | git push -f origin dist:dist
58 | git branch -D dist
59 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 FECrash
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 | # ================= CSS from
24 | Copyright (c) 2022 by Romina (https://codepen.io/RominaMartin/pen/KKgQmEW)
25 |
26 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
27 |
28 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
29 |
30 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 |
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
☕ 타입스크립트 객체 지향 카페 ☕
6 |
객체를 설계하고 상태를 고민하는 OOP 카페 앱
7 |
8 |
9 |
10 |
11 |
 
12 |
 
13 |
 
14 |
 
15 |
16 |
17 |
18 |
19 |

20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | ## ⚙️ BEFORE STARTED
28 | ```sh
29 | # clone repository
30 | git clone https://github.com/FECrash/TypeScript-OOP.git
31 |
32 | # change directory
33 | cd ./TypeScript-OOP
34 |
35 | # install
36 | npm install # or npm i
37 |
38 | # run
39 | npm run dev
40 |
41 | # build
42 | npm run build
43 | ```
44 |
45 |
46 |
47 | ## 📖 TEMPLATE
48 | ### 🏷 주문 관리
49 | ```html
50 |
51 |
52 |
53 |
주문 목록
54 |
55 |
56 |
57 |
58 |
59 |
73 |
74 |
1
75 |
아메리카노
76 |
Tall
77 |
2
78 |
-
79 |
ICE
80 |
각얼음
81 |
-
82 |
-
83 |
1회용 컵
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
현재까지 서빙된 커피
99 |
100 |
101 |
107 |
108 |
1
109 |
아메리카노(3)
110 |
2022.05.02 20:44:32
111 |
2022.05.02 20:46:17
112 |
113 |
114 |
1
115 |
에스프레소(1)
116 |
2022.05.02 20:51:37
117 |
2022.05.02 20:53:11
118 |
119 |
120 |
121 |
122 |
123 |
124 | 주방
125 |
126 |
Choose your coffee
127 |
128 |
129 |
커피
130 |
물
131 |
리퀴르
132 |
우유
133 |
휘핑 크림
134 |
밀크 폼
135 |
데운 우유
136 |
초콜릿
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
165 |
166 |
167 |
168 | ```
169 |
170 |
171 |
172 | ### 🧾 재료 관리
173 | > CSS 구현 중이에요😖
174 |
175 | ```html
176 |
177 |
178 | 재료 추가하기
179 |
185 |
186 |
187 | 재료 현황
188 |
189 |
190 |
191 | 재료명 |
192 | 가격 |
193 | 수량 |
194 | 관리 |
195 |
196 |
197 |
198 |
199 | 커피 원두 |
200 | 1,000원 |
201 | 10봉지 |
202 |
203 |
204 | |
205 |
206 |
207 |
208 |
209 |
210 | ```
211 | ```html
212 |
213 |
227 | ```
228 |
229 |
230 |
231 | ## 💎 MISSION
232 | ### 📂 Info
233 | > 커피 제조법
234 |
235 | - ☕ 아메리카노: (물 `6`, 커피 `4`)
236 |
237 | - ☕ 카페 오레: (우유 `5`, 커피 `5`)
238 |
239 | - ☕ 카푸치노: (커피 `3.5`, 데운 우유 `3`, 밀크 폼 `3.5`)
240 |
241 | - ☕ 코레또: (커피 `5.5`, 리퀴르 `2`)
242 |
243 | - ☕ 에스프레소: (커피 `4`)
244 |
245 | - ☕ 카페 라떼: (커피 `4`, 데운 우유 `4`, 밀크 폼 `2`)
246 |
247 | - ☕ 룽고: (커피 `5`, 물 `5`)
248 |
249 | - ☕ 마끼야또: (커피 `3`, 밀크 폼 `7`)
250 |
251 | - ☕ 카페 모카: (커피 `4`, 초콜릿 `2`, 데운 우유 `2`, 휘핑 크림 `2`)
252 |
253 | - ☕ 리스트레또: (커피 `2`)
254 |
255 |
256 |
257 | ### 💻 1st week : 온보딩 + Vanilla JavaScript 적응기
258 | #### 📝 설계
259 | - [UML 그리기](https://app.diagrams.net/)
260 |
261 |
262 |
263 | #### 💡 기능
264 | - [ ] 주문 받기를 클릭하면 랜덤으로 주문 목록 테이블에 추가됩니다.
265 |
266 | - [ ] 주문 목록의 `수정하기`를 클릭하면 해당 주문을 수정할 수 있습니다.
267 | - TIP: `div 태그에 contenteditable 속성을 부여합니다.`
268 |
269 | - [ ] 주문 목록의 `삭제하기`를 클릭하면 해당 주문이 삭제됩니다.
270 |
271 | - [ ] 주문이 존재하지 않으면 주방의 `커피 선택 버튼`이 `비활성` 됩니다.
272 | - 가령 `아메리카노 하나만 주문 목록에 존재하면 아메리카노 버튼만 활성화` 되어야 합니다.
273 |
274 | - 아무 주문도 없다면 주방은 `CLOSE` 됩니다.
275 | ```html
276 |
279 | ```
280 |
281 | - [ ] 주문이 존재하지 않음에도 `커피 선택 버튼`이나 `만들기` 버튼을 클릭하면 `경고창`을 출력합니다.
282 |
283 |
284 |
285 | ### 💻 2nd week : 구조/프로세스 설계
286 | - [ ] `주문 관리 탭`을 클릭하면 `커피를 주문하고 만드는 화면`으로 전환됩니다.
287 | - [ ] `재료 관리 탭`을 클릭하면 `커피 재료를 관리하는 화면`으로 전환됩니다.
288 | - [ ] 만들 커피가 선택되어 `만들기 버튼`을 클릭하면 옵션을 설정하는 `Modal 창이 출력`됩니다.
289 | - [ ] 출력되는 Modal 창의 상단에는 `해당되는 커피 목록`이 출력됩니다.
290 | - [ ] 커피는 반드시 가장 위에 있는 `주문 순서대로 서빙`되어야 합니다.
291 | - [ ] 옵션이 `제대로 추가되지 않은 채` `커피 서빙하기 버튼`을 클릭하면 `경고창`을 출력합니다.
292 | - [ ] 만약 커피를 서빙하지 않고 Modal 창이 닫혔다면 해당 작업 내역은 `저장`되어야 합니다.
293 | - 다시 Modal 창을 출력하는 경우 `마지막으로 선택한 옵션들이 체크`되어야 합니다.
294 | - [ ] 정상적으로 커피가 서빙 되었다면 `알림창`을 출력하고 `커피 선택 레이어`와 `Modal 창의 작업 내용`을 `초기화` 합니다.
295 | - [ ] 정상적으로 커피가 서빙 되었다면 `현재까지 서빙된 커피 테이블`에 추가됩니다.
296 | - `주문한 순서대로` 목록이 추가됩니다.
297 | - 동일한 커피가 주문되면 `괄호 안의 수량이 증가`됩니다.
298 | - 동일한 커피가 주문되면 `최근 주문 시간`과 `최근 서빙 완료 시간`이 갱신됩니다.
299 | - [ ] 정상적으로 커피가 서빙 되었다면 `주문 목록 테이블`의 주문에 `삭선 처리`합니다.
300 |
301 |
302 |
303 | ### 💻 3rd week : Web Storage
304 | - [ ] 웹을 다시 접속해도 기존 상태가 `유지` 되어야 합니다.
305 | - [ ] 상태를 관리하는 무언가는 단독으로 사용하지 않고 `객체 또는 모듈화` 되어야 합니다.
306 |
307 |
308 |
309 | ### 💻 4th week : Promise/Loading
310 | - [ ] `주문받기` 버튼 클릭 시 `1초의 Delay`가 존재해야 합니다.
311 | - 1초 동안 `Loading 화면`을 출력합니다. Loading Icon은 `assets/images/coffee-cup.gif` 입니다.
312 |
313 | - [ ] `커피 서빙하기` 버튼 클릭 시 `2초의 Delay`가 존재해야 합니다.
314 | - 2초 동안 `Loading 화면`을 출력합니다. Loading Icon은 `assets/images/coffee-cup.gif` 입니다.
315 |
316 |
317 |
318 | ### 🧸 추가 기능
319 | - [ ] 만들 커피의 수량을 지정할 수 있습니다.
320 | ```html
321 |
332 | ```
333 |
334 | - [ ] ~~Server에 데이터를 저장합니다.~~
335 | - 2022.05.06 부 구현되지 않은 요구사항입니다.
336 |
337 |
338 |
339 | ## 📔 COMMIT CONVENTION
340 |
341 | |태그|설명|
342 | |---|----|
343 | |`✒️Feat: `|새로운 기능을 추가할 경우|
344 | |`🛠Fix: `|버그를 고친 경우|
345 | |`✍️Design: `|CSS 등 사용자 UI 디자인 변경|
346 | |`❗️♻️BREAKING CHANGE: `|커다란 API 변경의 경우|
347 | |`❗️✔️HOTFIX: `|급하게 치명적인 버그를 고쳐야하는 경우|
348 | |`🎆Style: `|코드 포맷 변경, 세미 콜론 누락, 코드 수정이 없는 경우|
349 | |`🗃Refactor: `|프로덕션 코드 리팩토링|
350 | |`💬Comment: `|필요한 주석 추가 및 변경|
351 | |`📝Docs: `|문서를 수정한 경우|
352 | |`🧪Test: `|테스트 추가, 테스트 리팩토링(프로덕션 코드 변경 X)|
353 | |`🔬Chore: `|빌드 태스트 업데이트, 패키지 매니저를 설정하는 경우(프로덕션 코드 변경 X)|
354 | |`✂️Rename: `|파일 혹은 폴더명을 수정하거나 옮기는 작업만인 경우|
355 | |`🧺Remove: `|파일을 삭제하는 작업만 수행한 경우|
356 |
357 |
358 |
359 | ## 📜 LICENSE
360 |
361 | [MIT](https://opensource.org/licenses/MIT)
362 |
363 |
--------------------------------------------------------------------------------
/assets/css/common.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'KyoboHand';
3 | src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_20-04@1.0/KyoboHand.woff') format('woff');
4 | font-weight: normal;
5 | font-style: normal;
6 | }
7 |
8 | :root {
9 | --cup-color: #474747;
10 | --cup-width: 150px;
11 | --cup-height: 120px;
12 | --cup-handle-width: 25px;
13 | --cup-handle-height: calc(2 * var(--cup-handle-width));
14 | --cup-border-width: 10px;
15 | --cup-inside-width: calc(var(--cup-width) - var(--cup-border-width));
16 | --cup-inside-height: calc(var(--cup-height) - var(--cup-border-width));
17 | --border-width: 10px;
18 | --main-border: var(--border-width) solid var(--cup-color);
19 | --plate-width: 125px;
20 | --plate-height: 10px;
21 | --coffee-bottom: 40%;
22 | --water-bottom: 0;
23 | --milk-bottom: 0;
24 | --liquor-bottom: 0;
25 | --whipped_cream-bottom: 0;
26 | --steamed_milk-bottom: 0;
27 | --milk_foam-bottom: 0;
28 | --chocolate-bottom: 0;
29 | --coffee-color: #3c302f;
30 | --water-color: #b1dce2;
31 | --milk-color: #f0ebe5;
32 | --liquor-color: #fc8626;
33 | --whipped_cream-color: #fceecb;
34 | --milk_foam-color: #fceecb;
35 | --steamed_milk-color: #ffd7b3;
36 | --chocolate-color: #391e09;
37 | }
38 |
39 | * {
40 | font-family: 'KyoboHand';
41 | box-sizing: border-box;
42 | }
43 |
44 | body {
45 | margin: auto;
46 | }
47 |
48 | header {
49 | height: 20%;
50 | display: flex;
51 | flex-direction: column;
52 | justify-content: center;
53 | align-items: center;
54 | }
55 |
56 | nav {
57 | margin-top: 1em;
58 | position: relative;
59 | display: flex;
60 | text-align: center;
61 | background-color: #ffffff;
62 | width: 400px;
63 | height: 60px;
64 | line-height: 60px;
65 | border-radius: 50px;
66 | box-shadow: 0 3px 6px rgba(0, 0, 0, .5);
67 | }
68 |
69 | nav input {
70 | display: none;
71 | }
72 |
73 | nav label {
74 | position: relative;
75 | color: #000000;
76 | width: 100%;
77 | font-size: 20px;
78 | text-transform: uppercase;
79 | z-index: 2;
80 | cursor: pointer;
81 | transition: all .6s cubic-bezier(0.68, -0.55, 0, 0.98);
82 | }
83 |
84 | nav label:hover {
85 | color: #a36239;
86 | }
87 |
88 | nav .tab {
89 | position: absolute;
90 | top: 0;
91 | left: 0;
92 | bottom: 0;
93 | z-index: 1;
94 | height: 100%;
95 | width: 50%;
96 | border-radius: 50px;
97 | background: linear-gradient(to right, #c7ab99, #a36239);
98 | transition: all .6s cubic-bezier(0.68, -0.55, 0, 0.98);
99 | }
100 |
101 | nav #order-management:checked~.tab {
102 | left: 0;
103 | }
104 |
105 | nav #material-management:checked~.tab {
106 | left: 200px;
107 | }
108 |
109 | nav #order-management:checked~label.order-management,
110 | nav #material-management:checked~label.material-management {
111 | color: #ffffff;
112 | }
113 |
114 | main {
115 | width: 100%;
116 | height: 100%;
117 | display: flex;
118 | }
119 |
120 | h1 {
121 | margin: 0;
122 | }
123 |
124 | button {
125 | border-radius: 15px;
126 | }
127 |
128 | button:hover {
129 | cursor: pointer;
130 | }
131 |
132 | /* button:disabled {
133 | cursor: not-allowed !important;
134 | color: #ffffff !important;
135 | background-color: #a2a2a2 !important;
136 | } */
137 |
138 | .wrapper {
139 | margin: 0 auto;
140 | text-align: center;
141 | }
142 |
143 | .table {
144 | width: 100%;
145 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
146 | display: table;
147 | }
148 |
149 | .table-row {
150 | display: table-row;
151 | background: #f6f6f6;
152 | }
153 |
154 | .table-row:nth-of-type(odd) {
155 | background: #e9e9e9;
156 | }
157 |
158 | .table-row.header {
159 | font-weight: 900;
160 | color: #ffffff;
161 | background: #a36239;
162 | }
163 |
164 | .table-row.green {
165 | background: #27ae60;
166 | }
167 |
168 | .table-row.blue {
169 | background: #2980b9;
170 | }
171 |
172 | .cell {
173 | padding: 6px 12px;
174 | display: table-cell;
175 | }
176 |
177 | @media screen and (max-width: 1408px) {
178 | .wrapper {
179 | font-size: 16px;
180 | line-height: 22px;
181 | text-align: left;
182 | min-width: 0;
183 | }
184 |
185 | .table {
186 | display: block;
187 | text-align: left;
188 | }
189 |
190 | .table-row {
191 | padding: 14px 0 7px;
192 | display: block;
193 | }
194 |
195 | .table-row.header {
196 | padding: 0;
197 | height: 6px;
198 | }
199 |
200 | .table-row.header .cell {
201 | display: none;
202 | }
203 |
204 | .table-row .cell {
205 | margin-bottom: 10px;
206 | }
207 |
208 | .table-row .cell:before {
209 | margin-bottom: 3px;
210 | content: attr(data-title);
211 | min-width: 98px;
212 | font-size: 10px;
213 | line-height: 10px;
214 | font-weight: bold;
215 | text-transform: uppercase;
216 | color: #969696;
217 | display: block;
218 | }
219 |
220 | .cell {
221 | padding: 2px 16px;
222 | display: block;
223 | }
224 | }
--------------------------------------------------------------------------------
/assets/css/index.css:
--------------------------------------------------------------------------------
1 | @import url('./common.css');
2 | @import url('./pages/coffee-order.css');
3 | @import url('./pages/coffee-material.css');
4 | @import url('./modules/modal.css');
5 |
6 | #app {
7 | width: 100vw;
8 | height: 100vh;
9 | display: flex;
10 | flex-direction: column;
11 | align-items: center;
12 | }
13 |
14 | .hidden {
15 | opacity: 0;
16 | visibility: hidden;
17 | }
18 |
19 | .none {
20 | display: none;
21 | }
22 |
23 | .row {
24 | display: flex;
25 | flex-direction: column;
26 | align-items: center;
27 | gap: 1em;
28 | }
29 |
30 | #left-section {
31 | width: 65%;
32 | }
33 |
34 | #right-section {
35 | border-radius: 20px;
36 | background-color: #eee6d9;
37 | }
38 |
39 | @media screen and (max-width: 1408px) {
40 | #app {
41 | gap: 2em;
42 | }
43 |
44 | main#order, main#material {
45 | display: flex;
46 | flex-direction: column;
47 | align-items: center;
48 | gap: 1em;
49 | }
50 |
51 | #left-section, #right-section {
52 | width: 90% !important;
53 | height: 100% !important;
54 | }
55 | }
--------------------------------------------------------------------------------
/assets/css/modules/modal.css:
--------------------------------------------------------------------------------
1 | .modal-layout {
2 | top: 0;
3 | bottom: 0;
4 | left: 0;
5 | right: 0;
6 | position: absolute;
7 | background-color: #ffffff;
8 | display: flex;
9 | flex-direction: column;
10 | justify-content: center;
11 | align-items: center;
12 | z-index: 100;
13 | transition: 0.4s ease-in-out;
14 | gap: 2em;
15 | }
16 |
17 | .modal-header {
18 | position: relative;
19 | }
20 |
21 | .modal-header h1 {
22 | margin: 0;
23 | }
24 |
25 | .modal-header span {
26 | position: absolute;
27 | top: 0px;
28 | right: -480px;
29 | }
30 |
31 | .modal-header span:hover {
32 | cursor: pointer;
33 | }
34 |
35 | @supports (-webkit-appearance: none) or (-moz-appearance: none) {
36 |
37 | .modal-layout input[type=checkbox],
38 | .modal-layout input[type=radio] {
39 | --active: #275EFE;
40 | --active-inner: #fff;
41 | --focus: 2px rgba(39, 94, 254, .3);
42 | --border: #BBC1E1;
43 | --border-hover: #275EFE;
44 | --background: #fff;
45 | --disabled: #F6F8FF;
46 | --disabled-inner: #E1E6F9;
47 | -webkit-appearance: none;
48 | -moz-appearance: none;
49 | height: 21px;
50 | outline: none;
51 | display: inline-block;
52 | vertical-align: top;
53 | position: relative;
54 | margin: 0;
55 | cursor: pointer;
56 | border: 1px solid var(--bc, var(--border));
57 | background: var(--b, var(--background));
58 | transition: background 0.3s, border-color 0.3s, box-shadow 0.2s;
59 | }
60 |
61 | .modal-layout input[type=checkbox]:after,
62 | .modal-layout input[type=radio]:after {
63 | content: "";
64 | display: block;
65 | left: 0;
66 | top: 0;
67 | position: absolute;
68 | transition: transform var(--d-t, 0.3s) var(--d-t-e, ease), opacity var(--d-o, 0.2s);
69 | }
70 |
71 | .modal-layout input[type=checkbox]:checked,
72 | .modal-layout input[type=radio]:checked {
73 | --b: var(--active);
74 | --bc: var(--active);
75 | --d-o: .3s;
76 | --d-t: .6s;
77 | --d-t-e: cubic-bezier(.2, .85, .32, 1.2);
78 | }
79 |
80 | .modal-layout input[type=checkbox]:disabled,
81 | .modal-layout input[type=radio]:disabled {
82 | --b: var(--disabled);
83 | cursor: not-allowed;
84 | opacity: 0.9;
85 | }
86 |
87 | .modal-layout input[type=checkbox]:disabled:checked,
88 | .modal-layout input[type=radio]:disabled:checked {
89 | --b: var(--disabled-inner);
90 | --bc: var(--border);
91 | }
92 |
93 | .modal-layout input[type=checkbox]:disabled+label,
94 | .modal-layout input[type=radio]:disabled+label {
95 | cursor: not-allowed;
96 | }
97 |
98 | .modal-layout input[type=checkbox]:hover:not(:checked):not(:disabled),
99 | .modal-layout input[type=radio]:hover:not(:checked):not(:disabled) {
100 | --bc: var(--border-hover);
101 | }
102 |
103 | .modal-layout input[type=checkbox]:focus,
104 | .modal-layout input[type=radio]:focus {
105 | box-shadow: 0 0 0 var(--focus);
106 | }
107 |
108 | .modal-layout input[type=checkbox]:not(.switch),
109 | .modal-layout input[type=radio]:not(.switch) {
110 | width: 21px;
111 | }
112 |
113 | .modal-layout input[type=checkbox]:not(.switch):after,
114 | .modal-layout input[type=radio]:not(.switch):after {
115 | opacity: var(--o, 0);
116 | }
117 |
118 | .modal-layout input[type=checkbox]:not(.switch):checked,
119 | .modal-layout input[type=radio]:not(.switch):checked {
120 | --o: 1;
121 | }
122 |
123 | .modal-layout input[type=checkbox]+label,
124 | .modal-layout input[type=radio]+label {
125 | font-size: 14px;
126 | line-height: 21px;
127 | display: inline-block;
128 | vertical-align: top;
129 | cursor: pointer;
130 | margin-left: 4px;
131 | }
132 |
133 | .modal-layout input[type=checkbox]:not(.switch) {
134 | border-radius: 7px;
135 | }
136 |
137 | .modal-layout input[type=checkbox]:not(.switch):after {
138 | width: 5px;
139 | height: 9px;
140 | border: 2px solid var(--active-inner);
141 | border-top: 0;
142 | border-left: 0;
143 | left: 7px;
144 | top: 4px;
145 | transform: rotate(var(--r, 20deg));
146 | }
147 |
148 | .modal-layout input[type=checkbox]:not(.switch):checked {
149 | --r: 43deg;
150 | }
151 |
152 | .modal-layout input[type=checkbox].switch {
153 | width: 38px;
154 | border-radius: 11px;
155 | }
156 |
157 | .modal-layout input[type=checkbox].switch:after {
158 | left: 2px;
159 | top: 2px;
160 | border-radius: 50%;
161 | width: 15px;
162 | height: 15px;
163 | background: var(--ab, var(--border));
164 | transform: translateX(var(--x, 0));
165 | }
166 |
167 | .modal-layout input[type=checkbox].switch:checked {
168 | --ab: var(--active-inner);
169 | --x: 17px;
170 | }
171 |
172 | .modal-layout input[type=checkbox].switch:disabled:not(:checked):after {
173 | opacity: 0.6;
174 | }
175 |
176 | .modal-layout input[type=radio] {
177 | border-radius: 50%;
178 | }
179 |
180 | .modal-layout input[type=radio]:after {
181 | width: 19px;
182 | height: 19px;
183 | border-radius: 50%;
184 | background: var(--active-inner);
185 | opacity: 0;
186 | transform: scale(var(--s, 0.7));
187 | }
188 |
189 | .modal-layout input[type=radio]:checked {
190 | --s: .5;
191 | }
192 | }
193 |
194 | .modal-layout ul {
195 | display: flex;
196 | flex-direction: row;
197 | gap: 10px;
198 | margin: 12px;
199 | padding: 0;
200 | list-style: none;
201 | }
202 |
203 | .modal-layout ul li {
204 | position: relative;
205 | }
206 |
207 | .modal-table-wrapper {
208 | width: 1100px;
209 | /* width: 74%; */
210 | text-align: center;
211 | }
212 |
213 | .modal-table {
214 | width: 100%;
215 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
216 | display: table;
217 | }
218 |
219 | .modal-content {
220 | display: flex;
221 | flex-direction: column;
222 | gap: 1em;
223 | width: 100%;
224 | }
225 |
226 | .modal-content form {
227 | display: flex;
228 | flex-direction: row;
229 | justify-content: center;
230 | gap: 2em;
231 | }
232 |
233 | .modal-content-side {
234 | min-width: 530px;
235 | border-radius: 15px;
236 | background-color: #f3d8b0;
237 | padding: 20px;
238 | }
239 |
240 | .modal-content p {
241 | font-size: 18px;
242 | border-radius: 15px;
243 | padding: 5px;
244 | text-align: center;
245 | background-color: #a36239;
246 | color: #ffffff;
247 | }
248 |
249 | .modal-content-side ul {
250 | display: flex;
251 | flex-direction: row;
252 | justify-content: space-evenly;
253 | }
254 |
255 | .modal-confirm {
256 | width: 100%;
257 | text-align: center;
258 | }
259 |
260 | .modal-confirm button {
261 | border: none;
262 | padding: 10px;
263 | height: 60px;
264 | /* width: 74.5%; */
265 | width: 1100px;
266 | font-size: 1.5em;
267 | transition: 0.3s ease-in-out;
268 | }
269 |
270 | .modal-confirm button:hover {
271 | background-color: #ddb477;
272 | }
273 |
274 | @media screen and (max-width: 1408px) {}
--------------------------------------------------------------------------------
/assets/css/pages/coffee-material.css:
--------------------------------------------------------------------------------
1 | main#material {
2 | flex-direction: column;
3 | align-items: center;
4 | }
5 |
6 | main#material section {
7 | flex-direction: column;
8 | justify-content: center;
9 | align-items: center;
10 | }
--------------------------------------------------------------------------------
/assets/css/pages/coffee-order.css:
--------------------------------------------------------------------------------
1 | main#order {
2 | flex-direction: row;
3 | }
4 |
5 | main#order section {
6 | width: 45%;
7 | margin: 0 2.5%;
8 | height: 95%;
9 | display: flex;
10 | flex-direction: column;
11 | align-items: center;
12 | justify-content: space-evenly;
13 | }
14 |
15 | .order-list, .maked-list {
16 | width: 100%;
17 | text-align: center;
18 | }
19 |
20 | .order-list h3 {
21 | margin: 0;
22 | }
23 |
24 | .order-list button {
25 | border: none;
26 | transition: 0.3s ease-in-out;
27 | font-size: 1em;
28 | }
29 |
30 | .order-list button:hover {
31 | background-color: #ddb477;
32 | }
33 |
34 | .order-button-area {
35 | display: flex;
36 | justify-content: flex-end;
37 | margin-bottom: 1em;
38 | }
39 |
40 | .order-button {
41 | padding: 10px;
42 | border: 2px double #eeeeee;
43 | }
44 |
45 | .order-list table tr th:nth-child(2), .order-list table tr td:nth-child(2) {
46 | width: 160px;
47 | }
48 |
49 | .order-list table tr th:last-of-type, .order-list table tr td:last-of-type {
50 | width: 60px;
51 | }
52 |
53 | .edit-order:hover, .remove-order:hover {
54 | cursor: pointer;
55 | }
56 |
57 | .maked-list table tr th:nth-child(2), .maked-list table tr td:nth-child(2) {
58 | width: 400px;
59 | }
60 |
61 | .maked-list table tr th:nth-child(3), .maked-list table tr td:nth-child(3),
62 | .maked-list table tr th:last-of-type, .maked-list table tr td:last-of-type {
63 | width: 150px;
64 | }
65 |
66 | .maked-list-view {
67 | opacity: 0;
68 | visibility: 0;
69 | height: 0;
70 | display: flex;
71 | justify-content: center;
72 | }
73 |
74 | .maked-list-view button {
75 | width: 100%;
76 | border: none;
77 | transition: 0.3s ease-in-out;
78 | font-size: 1em;
79 | }
80 |
81 | .maked-list-view button:hover {
82 | background-color: #ddb477;
83 | }
84 |
85 | .maked-list h1 {
86 | margin-bottom: 2em;
87 | }
88 |
89 | .coffee-container {
90 | display: flex;
91 | flex-direction: column;
92 | align-items: center;
93 | justify-content: center;
94 | }
95 |
96 | .coffee_name {
97 | color: #000000;
98 | text-align: center;
99 | font-size: 20px;
100 | margin: 1em 0;
101 | }
102 |
103 | .cup {
104 | width: var(--cup-width);
105 | height: var(--cup-height);
106 | border-radius: 0 0 100px 100px;
107 | position: relative;
108 | background-color: var(--cup-color);
109 | z-index: 10;
110 | box-sizing: border-box;
111 | }
112 |
113 | .cup::after {
114 | z-index: -10;
115 | content: "";
116 | position: absolute;
117 | top: 10%;
118 | left: calc(100% - 10px);
119 | width: var(--cup-handle-width);
120 | height: var(--cup-handle-height);
121 | border: var(--main-border);
122 | border-radius: 50% 30%;
123 | }
124 |
125 | .plate {
126 | position: absolute;
127 | top: calc(100% + 10px);
128 | left: calc((var(--cup-width) - var(--plate-width)) / 2);
129 | width: var(--plate-width);
130 | background: var(--cup-color);
131 | height: var(--plate-height);
132 | border-radius: 10px;
133 | }
134 |
135 | .filling {
136 | position: absolute;
137 | left: calc(var(--cup-border-width) / 2);
138 | bottom: calc(var(--cup-border-width) / 2);
139 | width: var(--cup-inside-width);
140 | height: var(--cup-inside-height);
141 | overflow: hidden;
142 | border-radius: 0 0 100px 100px;
143 | background-color: var(--main-bg-color);
144 | bottom: 10px;
145 | }
146 |
147 | .filling div {
148 | position: absolute;
149 | width: 100%;
150 | transition: all 1s linear;
151 | color: #817f75;
152 | display: flex;
153 | align-items: flex-start;
154 | justify-content: center;
155 | height: 0;
156 | overflow: hidden;
157 | font-size: 14px;
158 | height: 100%;
159 | bottom: -100%;
160 | box-sizing: border-box;
161 | }
162 |
163 | .filling.reset.americano {
164 | --water-bottom: 0;
165 | --coffee-bottom: -60%;
166 | }
167 |
168 | .filling.reset.au_lait {
169 | --coffee-bottom: -50%;
170 | --milk-bottom: 0%;
171 | }
172 |
173 | .filling.reset.capuccino {
174 | --coffee-bottom: -65%;
175 | --steamed_milk-bottom: -35%;
176 | --milk_foam-bottom: 0;
177 | }
178 |
179 | .filling.reset.espresso {
180 | --coffee-bottom: -60%;
181 | }
182 |
183 | .filling.reset.latte {
184 | --coffee-bottom: -60%;
185 | --steamed_milk-bottom: -20%;
186 | --milk_foam-bottom: 0%;
187 | }
188 |
189 | .filling.reset.corretto {
190 | --coffee-bottom: -45%;
191 | --liquor-bottom: -25%;
192 | }
193 |
194 | .filling.reset.lungo {
195 | --water-bottom: 0;
196 | --coffee-bottom: -50%;
197 | }
198 |
199 | .filling.reset.macchiato {
200 | --coffee-bottom: -70%;
201 | --milk_foam-bottom: 0;
202 | }
203 |
204 | .filling.reset.mocha {
205 | --coffee-bottom: -60%;
206 | --chocolate-bottom: -40%;
207 | --steamed_milk-bottom: -20%;
208 | --whipped_cream-bottom: 0%;
209 | }
210 |
211 | .filling.reset.ristretto {
212 | --coffee-bottom: -80%;
213 | }
214 |
215 | div.chocolate {
216 | background: var(--chocolate-color);
217 | bottom: var(--chocolate-bottom);
218 | z-index: 6;
219 | }
220 |
221 | div.coffee {
222 | background: var(--coffee-color);
223 | bottom: var(--coffee-bottom);
224 | z-index: 7;
225 | }
226 |
227 | div.liquor {
228 | background: var(--liquor-color);
229 | bottom: var(--liquor-bottom);
230 | z-index: 4;
231 | }
232 |
233 | div.milk {
234 | background: var(--milk-color);
235 | bottom: var(--milk-bottom);
236 | z-index: 2;
237 | }
238 |
239 | div.milk_foam {
240 | background: var(--milk_foam-color);
241 | bottom: var(--milk_foam-bottom);
242 | z-index: 5;
243 | }
244 |
245 | div.steamed_milk {
246 | background: var(--steamed_milk-color);
247 | bottom: var(--steamed_milk-bottom);
248 | z-index: 6;
249 | }
250 |
251 | div.water {
252 | background: var(--water-color);
253 | bottom: var(--water-bottom);
254 | }
255 |
256 | div.whipped_cream {
257 | background: var(--whipped_cream-color);
258 | bottom: var(--whipped_cream-bottom);
259 | z-index: 4;
260 | }
261 |
262 | .filling.reset {
263 | --coffee-bottom: -100%;
264 | --water-bottom: -100%;
265 | --milk-bottom: -100%;
266 | --liquor-bottom: -100%;
267 | --whipped_cream-bottom: -100%;
268 | --steamed_milk-bottom: -100%;
269 | --milk_foam-bottom: -100%;
270 | --chocolate-bottom: -100%;
271 | }
272 |
273 | .select-coffee-container {
274 | margin-top: 20px;
275 | display: flex;
276 | flex-direction: column;
277 | gap: 1em;
278 | align-items: center;
279 | box-sizing: border-box;
280 | }
281 |
282 | .coffee-category-button {
283 | user-select: none;
284 | background: rgba(214, 217, 227, 0.6);
285 | outline: none;
286 | font-size: 1rem;
287 | border: 2px solid #a67a60;
288 | box-shadow: none;
289 | color: #363636;
290 | box-sizing: border-box;
291 | border-radius: 10px;
292 | padding: 4px;
293 | }
294 |
295 | .coffee-category-button:hover {
296 | background: rgba(255, 255, 255, 0.6);
297 | }
298 |
299 | .select-coffee-container .selected {
300 | background: rgba(255, 255, 255, 0.8);
301 | box-sizing: border-box;
302 | }
303 |
304 | .coffee-add-area {
305 | margin: 2em 0;
306 | }
307 |
308 | .coffee-add-area form {
309 | display: flex;
310 | flex-direction: row;
311 | justify-content: center;
312 | align-items: center;
313 | gap: 10px;
314 | position: relative;
315 | }
316 |
317 | /* Chrome, Safari, Edge, Opera */
318 | input::-webkit-outer-spin-button,
319 | input::-webkit-inner-spin-button {
320 | -webkit-appearance: none;
321 | margin: 0;
322 | }
323 |
324 | /* Firefox */
325 | input[type=number] {
326 | -moz-appearance: textfield;
327 | }
328 |
329 | .coffee-add-area input {
330 | border: 2px solid #000000;
331 | padding: 10px 10px 10px 3px;
332 | width: 80px;
333 | text-align: center;
334 | font-size: 24px;
335 | border-radius: 5px;
336 | }
337 |
338 | .ms {
339 | position: absolute;
340 | right: 80px;
341 | }
342 |
343 | .coffee-add-area button {
344 | border: none;
345 | padding: 20px;
346 | transition: 0.3s ease-in-out;
347 | background-color: #ddb477;
348 | box-shadow: rgba(14, 30, 37, 0.12) 0px 2px 4px 0px, rgba(14, 30, 37, 0.32) 0px 2px 16px 0px;
349 | }
350 |
351 | .coffee-add-area button:hover {
352 | background-color: #a36239;
353 | color: #ffffff;
354 | }
355 |
356 | .coffee-serve-area a {
357 | position: relative;
358 | width: 300px;
359 | height: 75px;
360 | margin: 10px 0;
361 | font-size: 24px;
362 | display: inline-flex;
363 | justify-content: center;
364 | align-items: center;
365 | text-decoration: none;
366 | color: #000000;
367 | transition: 0.5s;
368 | }
369 |
370 | .coffee-serve-area a:hover {
371 | color: #ffffff;
372 | }
373 |
374 | .coffee-serve-area a::before {
375 | content: '';
376 | position: absolute;
377 | top: 0;
378 | left: 0;
379 | width: 0;
380 | height: 100%;
381 | background: url('../images/btn-bg1.png');
382 | background-size: cover;
383 | transform-origin: left;
384 | transition: 0.5s;
385 | }
386 |
387 | .coffee-serve-area a:hover::before {
388 | width: 100%;
389 | }
390 |
391 | .coffee-serve-area a span {
392 | position: relative;
393 | z-index: 1;
394 | }
395 |
396 | #none-order {
397 | width: 100%;
398 | height: 100%;
399 | border-radius: 20px;
400 | background-image: url('../../images/closed.jpg');
401 | background-position: center;
402 | background-size: cover;
403 | }
404 |
405 | @media screen and (max-width: 1408px) {
406 | .maked-list {
407 | display: none;
408 | }
409 |
410 | .maked-list-view {
411 | opacity: 1;
412 | visibility: visible;
413 | height: 50px;
414 | margin-bottom: 1em;
415 | width: 90%;
416 | margin-top: 2em
417 | }
418 |
419 | .coffee-container {
420 | margin: 1em 0 3em 0;
421 | }
422 | }
--------------------------------------------------------------------------------
/assets/images/btn-bg1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pagers-org/TypeScript-OOP/70c65bceace6eb7f18b7dcd661ee633c93580423/assets/images/btn-bg1.png
--------------------------------------------------------------------------------
/assets/images/closed.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pagers-org/TypeScript-OOP/70c65bceace6eb7f18b7dcd661ee633c93580423/assets/images/closed.jpg
--------------------------------------------------------------------------------
/assets/images/coffee-cup.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pagers-org/TypeScript-OOP/70c65bceace6eb7f18b7dcd661ee633c93580423/assets/images/coffee-cup.gif
--------------------------------------------------------------------------------
/assets/images/oop-cafe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pagers-org/TypeScript-OOP/70c65bceace6eb7f18b7dcd661ee633c93580423/assets/images/oop-cafe.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | OOP Cafe
9 |
10 |
11 |
12 |
13 |
14 |
15 |
25 |
26 |
27 |
28 |
주문 목록
29 |
30 |
31 |
32 |
33 |
34 |
48 |
49 |
1
50 |
아메리카노
51 |
Tall
52 |
2
53 |
-
54 |
ICE
55 |
각얼음
56 |
-
57 |
-
58 |
1회용 컵
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
현재까지 서빙된 커피
74 |
75 |
76 |
82 |
83 |
1
84 |
아메리카노(3)
85 |
2022.05.02 20:44:32
86 |
2022.05.02 20:46:17
87 |
88 |
89 |
1
90 |
에스프레소(1)
91 |
2022.05.02 20:51:37
92 |
2022.05.02 20:53:11
93 |
94 |
95 |
96 |
97 |
98 |
99 | 주방
100 |
101 |
Choose your coffee
102 |
103 |
104 |
커피
105 |
물
106 |
리퀴르
107 |
우유
108 |
휘핑 크림
109 |
밀크 폼
110 |
데운 우유
111 |
초콜릿
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
140 |
141 |
142 |
143 |
144 |
145 |
149 |
150 |
151 |
163 |
164 |
1
165 |
아메리카노
166 |
Tall
167 |
2
168 |
-
169 |
ICE
170 |
각얼음
171 |
-
172 |
-
173 |
1회용 컵
174 |
175 |
176 |
177 |
325 |
328 |
329 |
330 |
331 |
332 |
333 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "oop-cafe",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vite --open",
7 | "build": "vite build --base=./"
8 | },
9 | "keywords": [],
10 | "author": "InSeong-So",
11 | "devDependencies": {
12 | "@typescript-eslint/eslint-plugin": "^5.21.0",
13 | "@typescript-eslint/parser": "^5.21.0",
14 | "eslint": "^8.14.0",
15 | "eslint-config-prettier": "^8.5.0",
16 | "eslint-plugin-prettier": "^4.0.0",
17 | "prettier": "^2.6.2",
18 | "prettier-eslint": "^14.0.2",
19 | "ts-node": "^10.7.0",
20 | "typescript": "^4.6.4",
21 | "vite": "^2.9.6"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | let currentElement: HTMLButtonElement | null = null;
2 | const pageNav = document.querySelector('header') as HTMLHeadElement;
3 | const coffeeName = document.querySelector('.coffee_name') as HTMLHeadingElement;
4 | const coffeeFilling = document.querySelector('.filling') as HTMLDivElement;
5 | const buttons = document.querySelectorAll('.coffee-category-button');
6 | const addCoffeeOptionsForm = document.querySelector('.coffee-add-area form') as HTMLFormElement;
7 | const modalLayout = document.querySelector('.modal-layout') as HTMLDivElement;
8 |
9 | pageNav.addEventListener('click', (event: MouseEvent) => {
10 | const $target = event.target as HTMLInputElement;
11 | if (!$target.matches('[type="radio"]')) return;
12 | event.preventDefault();
13 | alert('아직 준비되지 않았네요🥺');
14 | });
15 |
16 | buttons.forEach(button =>
17 | button.addEventListener('click', () => {
18 | if (currentElement) {
19 | currentElement.classList.remove('selected');
20 | coffeeFilling.classList.remove(currentElement.id);
21 | }
22 |
23 | currentElement = button;
24 | coffeeFilling.classList.add(currentElement.id);
25 | currentElement.classList.add('selected');
26 | coffeeName.innerText = button.innerText;
27 | }),
28 | );
29 |
30 | addCoffeeOptionsForm.addEventListener('submit', event => {
31 | event.preventDefault();
32 | modalLayout.classList.toggle('hidden');
33 | });
34 |
35 | modalLayout.addEventListener('click', (event: MouseEvent) => {
36 | const $target = event.target as HTMLElement;
37 | if (!$target.matches('#close-icon')) return;
38 | modalLayout.classList.toggle('hidden');
39 | });
40 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "moduleResolution": "Node",
5 | "resolveJsonModule": true,
6 | "esModuleInterop": true,
7 | "strict": true,
8 | "target": "es6",
9 | "lib": [
10 | "ES5",
11 | "ES6",
12 | "ESNext",
13 | "DOM"
14 | ],
15 | "skipLibCheck": true,
16 | "baseUrl": ".",
17 | "forceConsistentCasingInFileNames": true,
18 | "module": "esnext",
19 | "isolatedModules": false,
20 | "outDir": "dist",
21 | "paths": {
22 | "~/*": [
23 | "*"
24 | ],
25 | "@/*": [
26 | "src/*"
27 | ],
28 | },
29 | "typeRoots": [
30 | "@types/"
31 | ]
32 | },
33 | "include": [
34 | "**/*.ts"
35 | ],
36 | "exclude": [
37 | "node_modules"
38 | ]
39 | }
--------------------------------------------------------------------------------