├── .gitignore ├── .prettierrc ├── public ├── favicon.ico ├── robots.txt ├── airpods-max.mp4 └── index.html ├── web-test-runner.config.js ├── src ├── App.test.tsx ├── index.tsx ├── routes │ ├── NotFound.tsx │ ├── Home.tsx │ └── Mac.tsx ├── App.tsx ├── components │ ├── Menu.tsx │ └── Menu.css └── logo.svg ├── .eslintrc.js ├── snowpack.config.js ├── tsconfig.json ├── README.md ├── LICENSE ├── types └── static.d.ts └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .build 2 | build 3 | web_modules 4 | node_modules -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } 5 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wonderlandpark/apple-clone/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/airpods-max.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wonderlandpark/apple-clone/HEAD/public/airpods-max.mp4 -------------------------------------------------------------------------------- /web-test-runner.config.js: -------------------------------------------------------------------------------- 1 | // NODE_ENV=test - Needed by "@snowpack/web-test-runner-plugin" 2 | process.env.NODE_ENV = 'test'; 3 | 4 | module.exports = { 5 | plugins: [require('@snowpack/web-test-runner-plugin')()], 6 | }; 7 | -------------------------------------------------------------------------------- /src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { render } from '@testing-library/react' 3 | import { expect } from 'chai' 4 | import App from './App' 5 | 6 | describe('', () => { 7 | it('renders learn react link', () => { 8 | const { getByText } = render() 9 | const linkElement = getByText(/learn react/i) 10 | expect(document.body.contains(linkElement)) 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | import 'bootstrap/dist/css/bootstrap.css' 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ) 13 | 14 | // Hot Module Replacement (HMR) - Remove this snippet to remove HMR. 15 | // Learn more: https://www.snowpack.dev/#hot-module-replacement 16 | if (import.meta.hot) { 17 | import.meta.hot.accept() 18 | } 19 | -------------------------------------------------------------------------------- /src/routes/NotFound.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Container, Input } from 'reactstrap' 3 | 4 | export default function NotFound () { 5 | return ( 6 | 7 |

영어할 줄 아세요?

8 |

찾으시는 페이지가 없는 듯하네요.

9 |
10 | 11 |
12 |
13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | commonjs: true, 5 | es6: true, 6 | node: true 7 | }, 8 | extends: ['standard', 'standard-react'], 9 | globals: { 10 | Atomics: 'readonly', 11 | SharedArrayBuffer: 'readonly' 12 | }, 13 | parser: 'babel-eslint', 14 | parserOptions: { 15 | ecmaVersion: 2021 16 | }, 17 | rules: { 18 | semi: ['error', 'never'], 19 | indent: [ 20 | 'error', 21 | 2, 22 | { 23 | SwitchCase: 1, 24 | VariableDeclarator: 'first' 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /snowpack.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import("snowpack").SnowpackUserConfig } */ 2 | module.exports = { 3 | mount: { 4 | public: '/', 5 | src: '/_dist_' 6 | }, 7 | plugins: [ 8 | '@snowpack/plugin-react-refresh', 9 | '@snowpack/plugin-dotenv', 10 | '@snowpack/plugin-typescript' 11 | ], 12 | install: [ 13 | /* ... */ 14 | ], 15 | installOptions: { 16 | /* ... */ 17 | }, 18 | devOptions: { 19 | /* ... */ 20 | }, 21 | buildOptions: { 22 | /* ... */ 23 | }, 24 | proxy: { 25 | /* ... */ 26 | }, 27 | alias: { 28 | /* ... */ 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { BrowserRouter, Route, Switch } from 'react-router-dom' 3 | import Menu from './components/Menu' 4 | 5 | import Home from './routes/Home' 6 | import Mac from './routes/Mac' 7 | import NotFound from './routes/NotFound' 8 | 9 | function App () { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ) 22 | } 23 | 24 | export default App 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src", "types"], 3 | "compilerOptions": { 4 | "module": "esnext", 5 | "target": "esnext", 6 | "moduleResolution": "node", 7 | "jsx": "preserve", 8 | "baseUrl": "./", 9 | /* paths - If you configure Snowpack import aliases, add them here. */ 10 | "paths": {}, 11 | /* noEmit - Snowpack builds (emits) files, not tsc. */ 12 | "noEmit": true, 13 | /* Additional Options */ 14 | "strict": true, 15 | "skipLibCheck": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "resolveJsonModule": true, 18 | "allowSyntheticDefaultImports": true, 19 | "importsNotUsedAsValues": "error" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/Menu.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import './Menu.css' 4 | 5 | export default function Menu () { 6 | return ( 7 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # apple-clone 2 | 3 | [애플](https://apple.kr) 클론 4 | 5 | 애플의 여러 사건들을 이용하여 애플 웹페이지를 클론 코딩해보았습니다. 6 | 7 | ## 반응형 디자인 8 | 9 | 이 아닙니다. 구형기기를 지원하지 않는 애플처럼 저는 모바일이나 테블릿을 지원하지 않겠습니다. 10 | ## Available Scripts 11 | 12 | ### npm start 13 | 14 | Runs the app in the development mode. 15 | Open http://localhost:8080 to view it in the browser. 16 | 17 | The page will reload if you make edits. 18 | You will also see any lint errors in the console. 19 | 20 | ### npm run build 21 | 22 | Builds a static copy of your site to the `build/` folder. 23 | Your app is ready to be deployed! 24 | 25 | **For the best production performance:** Add a build bundler plugin like "@snowpack/plugin-webpack" to your `snowpack.config.js` config file. 26 | 27 | ### npm test 28 | 29 | Launches the application test runner. 30 | Run with the `--watch` flag (`npm test -- --watch`) to run in interactive watch mode. 31 | -------------------------------------------------------------------------------- /src/routes/Home.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Button, Container } from 'reactstrap' 3 | 4 | export default function Home () { 5 | return ( 6 |
7 | 9 |
10 |

Airpods Max

11 |

프리미엄 귀마개.

12 |
13 | 14 | 15 |
16 |
17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Fred K. Schott 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 | -------------------------------------------------------------------------------- /src/components/Menu.css: -------------------------------------------------------------------------------- 1 | nav { 2 | background: rgba(0,0,0,0.8); 3 | backdrop-filter: saturate(100%) blur(20px); 4 | height: 44px; 5 | } 6 | nav .content { 7 | max-width: 1024px; 8 | margin: 0 auto; 9 | padding-left: calc(max(22px, env(safe-area-inset-left))); 10 | padding-right: calc(max(22px, env(safe-area-inset-right))); 11 | display: flex; 12 | justify-content: space-between; 13 | } 14 | nav .content a { 15 | position: relative; 16 | font-size: 14px; 17 | font-weight: 300; 18 | letter-spacing: -.01em; 19 | line-height: 3.14286; 20 | text-decoration: none; 21 | opacity: .8; 22 | color: #f5f5f7; 23 | } 24 | 25 | nav .content a[href]:hover { 26 | opacity: 1; 27 | } 28 | 29 | nav .search { 30 | background-position: 0 0; 31 | background-size: 18px 88px; 32 | background-repeat: no-repeat; 33 | background-image: url(https://www.apple.com/ac/globalnav/6/en_US/images/be15095f-5a20-57d0-ad14-cf4c638e223a/globalnav_search_image__fca9mfoh8a2q_large.svg); 34 | width: 18px; 35 | opacity: .8; 36 | } 37 | 38 | nav .search:hover { 39 | opacity: 1; 40 | } 41 | 42 | nav .bag { 43 | background-size: 17px 44px; 44 | background-repeat: no-repeat; 45 | background-image: url(https://www.apple.com/ac/globalnav/6/en_US/images/be15095f-5a20-57d0-ad14-cf4c638e223a/globalnav_bag_image__bmix8075eg4i_large.svg); 46 | background-position: center center; 47 | width: 17px; 48 | opacity: 0.7; 49 | } 50 | 51 | nav .bag:hover { 52 | opacity: 1; 53 | } -------------------------------------------------------------------------------- /types/static.d.ts: -------------------------------------------------------------------------------- 1 | /* Use this file to declare any custom file extensions for importing */ 2 | /* Use this folder to also add/extend a package d.ts file, if needed. */ 3 | 4 | /* CSS MODULES */ 5 | declare module '*.module.css' { 6 | const classes: { [key: string]: string }; 7 | export default classes; 8 | } 9 | declare module '*.module.scss' { 10 | const classes: { [key: string]: string }; 11 | export default classes; 12 | } 13 | declare module '*.module.sass' { 14 | const classes: { [key: string]: string }; 15 | export default classes; 16 | } 17 | declare module '*.module.less' { 18 | const classes: { [key: string]: string }; 19 | export default classes; 20 | } 21 | declare module '*.module.styl' { 22 | const classes: { [key: string]: string }; 23 | export default classes; 24 | } 25 | 26 | /* CSS */ 27 | declare module '*.css'; 28 | declare module '*.scss'; 29 | declare module '*.sass'; 30 | declare module '*.less'; 31 | declare module '*.styl'; 32 | 33 | /* IMAGES */ 34 | declare module '*.svg' { 35 | const ref: string; 36 | export default ref; 37 | } 38 | declare module '*.bmp' { 39 | const ref: string; 40 | export default ref; 41 | } 42 | declare module '*.gif' { 43 | const ref: string; 44 | export default ref; 45 | } 46 | declare module '*.jpg' { 47 | const ref: string; 48 | export default ref; 49 | } 50 | declare module '*.jpeg' { 51 | const ref: string; 52 | export default ref; 53 | } 54 | declare module '*.png' { 55 | const ref: string; 56 | export default ref; 57 | } 58 | 59 | /* CUSTOM: ADD YOUR OWN HERE */ 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "start": "snowpack dev --reload", 4 | "build": "snowpack build --clean", 5 | "serve": "serve -s build", 6 | "test": "web-test-runner \"src/**/*.test.tsx\"", 7 | "eslint": "eslint --fix \"src/**/*.{js,jsx,ts,tsx}\"", 8 | "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\"", 9 | "lint": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\"" 10 | }, 11 | "dependencies": { 12 | "bootstrap": "^4.5.3", 13 | "react": "^17.0.1", 14 | "react-dom": "^17.0.1", 15 | "react-router-dom": "^5.2.0", 16 | "reactstrap": "^8.7.1" 17 | }, 18 | "devDependencies": { 19 | "@snowpack/plugin-dotenv": "^2.0.4", 20 | "@snowpack/plugin-react-refresh": "^2.3.7", 21 | "@snowpack/plugin-typescript": "^1.1.0", 22 | "@snowpack/web-test-runner-plugin": "^0.1.4", 23 | "@testing-library/react": "^11.0.0", 24 | "@types/chai": "^4.2.13", 25 | "@types/react": "^16.9.49", 26 | "@types/react-dom": "^16.9.8", 27 | "@types/react-router-dom": "^5.1.6", 28 | "@types/snowpack-env": "^2.3.2", 29 | "@web/test-runner": "^0.9.7", 30 | "babel-eslint": "^10.1.0", 31 | "chai": "^4.2.0", 32 | "eslint": "^7.14.0", 33 | "eslint-config-standard": "^16.0.2", 34 | "eslint-config-standard-jsx": "^10.0.0", 35 | "eslint-config-standard-react": "^11.0.1", 36 | "eslint-plugin-import": "^2.22.1", 37 | "eslint-plugin-node": "^11.1.0", 38 | "eslint-plugin-promise": "^4.2.1", 39 | "eslint-plugin-react": "^7.21.5", 40 | "prettier": "^2.0.5", 41 | "snowpack": "^2.17.1", 42 | "typescript": "^4.0.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Apple 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/routes/Mac.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Container, Row, Col, Button } from 'reactstrap' 3 | 4 | export default function Mac () { 5 | return ( 6 |
7 |
8 | 9 |
10 | 11 |

이미 도래한
Mac의 미래.

12 | 13 | 14 | New 15 |

MacBook English

16 |

English의 흐름을 바꾸다.

17 |

₩1,290,000부터

18 |

출시일은 추후 공개됩니다.

19 |

20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | New 29 |

13형 모델
MacBook Math

30 |

Math중에 수학.

31 |

₩1,690,000부터

32 |

33 | 34 |
35 | 36 | 37 | 38 | New 39 |

Mac Science

40 |

새로운 원소. 어마무시한 가능성.

41 |

₩890,000부터

42 |

43 | 44 | 45 | 46 | 47 | 48 |
49 |
50 |
51 | ) 52 | } 53 | --------------------------------------------------------------------------------