Showing
24 changed files
with
542 additions
and
141 deletions
... | @@ -37,7 +37,7 @@ services: | ... | @@ -37,7 +37,7 @@ services: |
37 | volumes: | 37 | volumes: |
38 | - ./node:/app | 38 | - ./node:/app |
39 | - ./config:/app/config | 39 | - ./config:/app/config |
40 | - command: bash -c "npm install && node app.js" | 40 | + command: bash -c "npm install && node_modules/.bin/nodemon app.js" |
41 | environment: | 41 | environment: |
42 | - NODE_ENV=production | 42 | - NODE_ENV=production |
43 | restart: on-failure | 43 | restart: on-failure | ... | ... |
... | @@ -6,6 +6,6 @@ let routes = require('./routes'); | ... | @@ -6,6 +6,6 @@ let routes = require('./routes'); |
6 | app.use(bodyParser.urlencoded({ extended: false })); | 6 | app.use(bodyParser.urlencoded({ extended: false })); |
7 | app.use(bodyParser.json()); | 7 | app.use(bodyParser.json()); |
8 | 8 | ||
9 | -app.get('/api/home', routes.home); | 9 | +app.get('/api/character', routes.character.getCharacter); |
10 | 10 | ||
11 | let server = app.listen(80); | 11 | let server = app.listen(80); |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
app/node/model/job.js
0 → 100644
This diff is collapsed. Click to expand it.
app/node/model/stat.js
0 → 100644
app/node/model/weapon.js
0 → 100644
1 | +module.exports = { | ||
2 | + '한손검': 1.2, | ||
3 | + '한손도끼': 1.2, | ||
4 | + '한손둔기': 1.2, | ||
5 | + '스태프': 1, | ||
6 | + '완드': 1, | ||
7 | + '샤이닝 로드': 1.2, | ||
8 | + '단검': 1.3, | ||
9 | + '케인': 1.3, | ||
10 | + '데스페라도': 1.3, | ||
11 | + '에너지소드': 1.5, | ||
12 | + '소울 슈터': 1.7, | ||
13 | + 'ESP 리미터': 1.2, | ||
14 | + '체인': 1.3, | ||
15 | + '매직 건틀렛': 1.2, | ||
16 | + '부채': 1.3, | ||
17 | + '튜너': 1.3, | ||
18 | + '두손검': 1.34, | ||
19 | + '두손도끼': 1.34, | ||
20 | + '두손둔기': 1.34, | ||
21 | + '창': 1.34, | ||
22 | + '폴암': 1.49, | ||
23 | + '태도': 1.34, | ||
24 | + '건틀렛 리볼버': 1.7, | ||
25 | + '활': 1.3, | ||
26 | + '석궁': 1.35, | ||
27 | + '듀얼 보우건': 1.3, | ||
28 | + '에인션트 보우': 1.3, | ||
29 | + '아대': 1.75, | ||
30 | + '건': 1.5, | ||
31 | + '너클': 1.7, | ||
32 | + '핸드캐논': 1.5 | ||
33 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
This diff is collapsed. Click to expand it.
... | @@ -9,7 +9,11 @@ | ... | @@ -9,7 +9,11 @@ |
9 | "author": "", | 9 | "author": "", |
10 | "license": "ISC", | 10 | "license": "ISC", |
11 | "dependencies": { | 11 | "dependencies": { |
12 | + "axios": "^0.19.2", | ||
12 | "express": "^4.17.1", | 13 | "express": "^4.17.1", |
13 | - "http": "0.0.1-security" | 14 | + "http": "0.0.1-security", |
15 | + "jquery": "^3.5.1", | ||
16 | + "jsdom": "^16.2.2", | ||
17 | + "nodemon": "^2.0.4" | ||
14 | } | 18 | } |
15 | } | 19 | } | ... | ... |
app/node/routes/character.js
0 → 100644
This diff is collapsed. Click to expand it.
app/node/routes/home.js
deleted
100644 → 0
This diff is collapsed. Click to expand it.
... | @@ -10,12 +10,13 @@ | ... | @@ -10,12 +10,13 @@ |
10 | "@rollup/plugin-commonjs": "11.0.2", | 10 | "@rollup/plugin-commonjs": "11.0.2", |
11 | "@rollup/plugin-node-resolve": "^7.0.0", | 11 | "@rollup/plugin-node-resolve": "^7.0.0", |
12 | "rollup": "^1.20.0", | 12 | "rollup": "^1.20.0", |
13 | - "rollup-plugin-livereload": "^1.0.0", | ||
14 | "rollup-plugin-svelte": "^5.0.3", | 13 | "rollup-plugin-svelte": "^5.0.3", |
15 | "rollup-plugin-terser": "^5.1.2", | 14 | "rollup-plugin-terser": "^5.1.2", |
16 | "svelte": "^3.0.0" | 15 | "svelte": "^3.0.0" |
17 | }, | 16 | }, |
18 | "dependencies": { | 17 | "dependencies": { |
18 | + "@lottiefiles/svelte-lottie-player": "^0.1.4", | ||
19 | + "axios": "^0.19.2", | ||
19 | "rollup-plugin-copy": "^3.3.0", | 20 | "rollup-plugin-copy": "^3.3.0", |
20 | "sirv-cli": "^0.4.4", | 21 | "sirv-cli": "^0.4.4", |
21 | "svelte-spa-router": "^2.1.0" | 22 | "svelte-spa-router": "^2.1.0" | ... | ... |
app/web/public/favicon.png
deleted
100644 → 0
3.05 KB
1 | <!DOCTYPE html> | 1 | <!DOCTYPE html> |
2 | <html lang="en"> | 2 | <html lang="en"> |
3 | -<head> | ||
4 | - <meta charset='utf-8'> | ||
5 | - <meta name='viewport' content='width=device-width,initial-scale=1'> | ||
6 | 3 | ||
7 | - <title>Svelte app</title> | 4 | +<head lang="ko"> |
5 | + <meta charset='utf-8'> | ||
6 | + <meta name='viewport' content='width=device-width,initial-scale=1'> | ||
8 | 7 | ||
9 | - <link rel='icon' type='image/png' href='/favicon.png'> | 8 | + <title>::메이플스토리 스펙 계산기::</title> |
10 | - <link rel='stylesheet' href='/global.css'> | ||
11 | - <link rel='stylesheet' href='/build/bundle.css'> | ||
12 | 9 | ||
13 | - <script defer src='/build/bundle.js'></script> | 10 | + <link rel='icon' type='shortcut icon' href='./build/static/images/favicon.ico'> |
11 | + <link rel='stylesheet' href='./static/css/global.css'> | ||
12 | + <link rel='stylesheet' href='/build/bundle.css'> | ||
13 | + <meta property="og:image" content="./build/static/images/ogimage.png"> | ||
14 | + <meta property="og:title" content="::메이플스토리 스펙 계산기::"> | ||
15 | + <meta property="og:description" content="당신의 메이플스토리 스펙 효율을 빠르게 계산해보세요!"> | ||
16 | + | ||
17 | + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"> | ||
18 | + <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> | ||
19 | + <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> | ||
20 | + | ||
21 | + <script defer src='/build/bundle.js'></script> | ||
14 | </head> | 22 | </head> |
15 | 23 | ||
16 | <body> | 24 | <body> |
17 | </body> | 25 | </body> |
18 | -</html> | 26 | + |
27 | +</html> | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
1 | -html, body { | 1 | +html, |
2 | - position: relative; | 2 | +body { |
3 | - width: 100%; | 3 | + position: relative; |
4 | - height: 100%; | 4 | + width: 100%; |
5 | + height: 100%; | ||
6 | + background-color: #ffebee; | ||
5 | } | 7 | } |
6 | 8 | ||
7 | body { | 9 | body { |
8 | - color: #333; | 10 | + color: #333; |
9 | - margin: 0; | 11 | + margin: 0; |
10 | - padding: 8px; | 12 | + box-sizing: border-box; |
11 | - box-sizing: border-box; | 13 | + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; |
12 | - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; | ||
13 | } | 14 | } |
14 | 15 | ||
15 | a { | 16 | a { |
16 | - color: rgb(0,100,200); | 17 | + color: rgb(0, 100, 200); |
17 | - text-decoration: none; | 18 | + text-decoration: none; |
18 | } | 19 | } |
19 | 20 | ||
20 | a:hover { | 21 | a:hover { |
21 | - text-decoration: underline; | 22 | + text-decoration: underline; |
22 | } | 23 | } |
23 | 24 | ||
24 | a:visited { | 25 | a:visited { |
25 | - color: rgb(0,80,160); | 26 | + color: rgb(0, 80, 160); |
26 | } | 27 | } |
27 | 28 | ||
28 | label { | 29 | label { |
29 | - display: block; | 30 | + display: block; |
30 | } | 31 | } |
31 | 32 | ||
32 | -input, button, select, textarea { | 33 | +input, |
33 | - font-family: inherit; | 34 | +button, |
34 | - font-size: inherit; | 35 | +select, |
35 | - padding: 0.4em; | 36 | +textarea { |
36 | - margin: 0 0 0.5em 0; | 37 | + font-family: inherit; |
37 | - box-sizing: border-box; | 38 | + font-size: inherit; |
38 | - border: 1px solid #ccc; | 39 | + padding: 0.4em; |
39 | - border-radius: 2px; | 40 | + margin: 0 0 0.5em 0; |
41 | + box-sizing: border-box; | ||
42 | + border: 1px solid #ccc; | ||
43 | + border-radius: 2px; | ||
40 | } | 44 | } |
41 | 45 | ||
42 | input:disabled { | 46 | input:disabled { |
43 | - color: #ccc; | 47 | + color: #ccc; |
44 | } | 48 | } |
45 | 49 | ||
46 | input[type="range"] { | 50 | input[type="range"] { |
47 | - height: 0; | 51 | + height: 0; |
48 | } | 52 | } |
49 | 53 | ||
50 | button { | 54 | button { |
51 | - color: #333; | 55 | + color: #333; |
52 | - background-color: #f4f4f4; | 56 | + background-color: #f4f4f4; |
53 | - outline: none; | 57 | + outline: none; |
54 | } | 58 | } |
55 | 59 | ||
56 | button:disabled { | 60 | button:disabled { |
57 | - color: #999; | 61 | + color: #999; |
58 | } | 62 | } |
59 | 63 | ||
60 | button:not(:disabled):active { | 64 | button:not(:disabled):active { |
61 | - background-color: #ddd; | 65 | + background-color: #ddd; |
62 | } | 66 | } |
63 | 67 | ||
64 | button:focus { | 68 | button:focus { |
65 | - border-color: #666; | 69 | + border-color: #666; |
66 | -} | 70 | +} |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
1 | import svelte from 'rollup-plugin-svelte'; | 1 | import svelte from 'rollup-plugin-svelte'; |
2 | import resolve from '@rollup/plugin-node-resolve'; | 2 | import resolve from '@rollup/plugin-node-resolve'; |
3 | import commonjs from '@rollup/plugin-commonjs'; | 3 | import commonjs from '@rollup/plugin-commonjs'; |
4 | -import livereload from 'rollup-plugin-livereload'; | ||
5 | import { terser } from 'rollup-plugin-terser'; | 4 | import { terser } from 'rollup-plugin-terser'; |
6 | import copy from 'rollup-plugin-copy'; | 5 | import copy from 'rollup-plugin-copy'; |
7 | 6 | ||
8 | const production = !process.env.ROLLUP_WATCH; | 7 | const production = !process.env.ROLLUP_WATCH; |
9 | 8 | ||
10 | export default { | 9 | export default { |
11 | - input: 'src/main.js', | 10 | + input: 'src/main.js', |
12 | - output: { | 11 | + output: { |
13 | - sourcemap: true, | 12 | + sourcemap: true, |
14 | - format: 'iife', | 13 | + format: 'iife', |
15 | - name: 'app', | 14 | + name: 'app', |
16 | - file: 'public/build/bundle.js' | 15 | + file: 'public/build/bundle.js' |
17 | - }, | 16 | + }, |
18 | - plugins: [ | 17 | + plugins: [ |
19 | - svelte({ | 18 | + svelte({ |
20 | - // enable run-time checks when not in production | 19 | + // enable run-time checks when not in production |
21 | - dev: !production, | 20 | + dev: !production, |
22 | - // we'll extract any component CSS out into | 21 | + // we'll extract any component CSS out into |
23 | - // a separate file - better for performance | 22 | + // a separate file - better for performance |
24 | - css: css => { | 23 | + css: css => { |
25 | - css.write('public/build/bundle.css'); | 24 | + css.write('public/build/bundle.css'); |
26 | - } | 25 | + } |
27 | - }), | 26 | + }), |
28 | 27 | ||
29 | - // If you have external dependencies installed from | 28 | + // If you have external dependencies installed from |
30 | - // npm, you'll most likely need these plugins. In | 29 | + // npm, you'll most likely need these plugins. In |
31 | - // some cases you'll need additional configuration - | 30 | + // some cases you'll need additional configuration - |
32 | - // consult the documentation for details: | 31 | + // consult the documentation for details: |
33 | - // https://github.com/rollup/plugins/tree/master/packages/commonjs | 32 | + // https://github.com/rollup/plugins/tree/master/packages/commonjs |
34 | - resolve({ | 33 | + resolve({ |
35 | - browser: true, | 34 | + browser: true, |
36 | - dedupe: ['svelte'] | 35 | + dedupe: ['svelte'] |
37 | - }), | 36 | + }), |
38 | - commonjs(), | 37 | + commonjs(), |
39 | 38 | ||
40 | - copy({ | 39 | + copy({ |
41 | - targets:[ | 40 | + targets: [ |
42 | - { src:'src/images', dest:'public' } | 41 | + { src: 'src/images', dest: 'public/build/static' } |
43 | - ] | 42 | + ] |
44 | - }), | 43 | + }), |
45 | 44 | ||
46 | - // In dev mode, call `npm run start` once | 45 | + // In dev mode, call `npm run start` once |
47 | - // the bundle has been generated | 46 | + // the bundle has been generated |
48 | - !production && serve(), | 47 | + !production && serve(), |
49 | 48 | ||
50 | - // Watch the `public` directory and refresh the | 49 | + // If we're building for production (npm run build |
51 | - // browser on changes when not in production | 50 | + // instead of npm run dev), minify |
52 | - !production && livereload('public'), | 51 | + production && terser() |
53 | - | 52 | + ], |
54 | - // If we're building for production (npm run build | 53 | + watch: { |
55 | - // instead of npm run dev), minify | 54 | + clearScreen: false |
56 | - production && terser() | 55 | + } |
57 | - ], | ||
58 | - watch: { | ||
59 | - clearScreen: false | ||
60 | - } | ||
61 | }; | 56 | }; |
62 | 57 | ||
63 | function serve() { | 58 | function serve() { |
64 | - let started = false; | 59 | + let started = false; |
65 | 60 | ||
66 | - return { | 61 | + return { |
67 | - writeBundle() { | 62 | + writeBundle() { |
68 | - if (!started) { | 63 | + if (!started) { |
69 | - started = true; | 64 | + started = true; |
70 | 65 | ||
71 | - require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], { | 66 | + require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], { |
72 | - stdio: ['ignore', 'inherit', 'inherit'], | 67 | + stdio: ['ignore', 'inherit', 'inherit'], |
73 | - shell: true | 68 | + shell: true |
74 | - }); | 69 | + }); |
75 | - } | 70 | + } |
76 | - } | 71 | + } |
77 | - }; | 72 | + }; |
78 | -} | 73 | +} |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
app/web/src/components/Loading.svelte
0 → 100644
1 | +<script> | ||
2 | + import {LottiePlayer} from '@lottiefiles/svelte-lottie-player'; | ||
3 | + | ||
4 | + export let count = 0; | ||
5 | +</script> | ||
6 | + | ||
7 | +<div id="loading" class:show={count > 0}> | ||
8 | + <LottiePlayer | ||
9 | + src="https://assets5.lottiefiles.com/packages/lf20_kblbXu.json" background="transparent" speed="1" width={300} height={300} controls={false} controlsLayout={null} loop autoplay> | ||
10 | + </LottiePlayer> | ||
11 | +</div> | ||
12 | + | ||
13 | +<style> | ||
14 | +#loading { position:fixed; width:100%; height:100%; z-index:9999; background-color:rgba(0,0,0,0.3); align-items:center; justify-content:center; display:none; } | ||
15 | +#loading.show { display:flex; } | ||
16 | +</style> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
app/web/src/images/favicon.ico
0 → 100644
No preview for this file type
app/web/src/images/ogimage.png
0 → 100644
7.47 KB
1 | -import App from './App.svelte'; | 1 | +import App from './App.svelte'; |
2 | 2 | ||
3 | const app = new App({ | 3 | const app = new App({ |
4 | - target: document.body, | 4 | + target: document.body |
5 | - props: { | ||
6 | - name: 'world' | ||
7 | - } | ||
8 | }); | 5 | }); |
9 | 6 | ||
10 | export default app; | 7 | export default app; |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
1 | -import Home from './routes/Home.svelte'; | 1 | +import Search from './routes/Search.svelte'; |
2 | +import Character from './routes/Character.svelte'; | ||
2 | 3 | ||
3 | const routes = { | 4 | const routes = { |
4 | - '/': Home, | 5 | + '/': Search, |
6 | + '/character': Character, | ||
7 | + '/character/:character': Character, | ||
5 | }; | 8 | }; |
6 | 9 | ||
7 | export default routes; | 10 | export default routes; |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
app/web/src/routes/Character.svelte
0 → 100644
1 | +<script> | ||
2 | + export let params = {}; | ||
3 | + | ||
4 | + import {push} from 'svelte-spa-router'; | ||
5 | + import axios from 'axios'; | ||
6 | + import Loading from '../components/Loading.svelte'; | ||
7 | + | ||
8 | + let callCount = 0; | ||
9 | + let isBuff = false; | ||
10 | + let isCharacterLoading = false; | ||
11 | + let stats; | ||
12 | + | ||
13 | + let character = { | ||
14 | + info:{ | ||
15 | + avatar:'', | ||
16 | + nickname:'', | ||
17 | + characterCode:'', | ||
18 | + job:'', | ||
19 | + majorName:'', | ||
20 | + attackPowerName:'', | ||
21 | + server:{ | ||
22 | + name:'', | ||
23 | + icon:'' | ||
24 | + }, | ||
25 | + level:237 | ||
26 | + }, | ||
27 | + analysis:{ | ||
28 | + default:{ | ||
29 | + stats:{ | ||
30 | + major:{ | ||
31 | + pure:0, | ||
32 | + percent:0, | ||
33 | + added:0, | ||
34 | + }, | ||
35 | + minor:0, | ||
36 | + damage:{ | ||
37 | + all:0, | ||
38 | + boss:0 | ||
39 | + }, | ||
40 | + finalDamage:0, | ||
41 | + criticalDamage:0, | ||
42 | + attackPower:{ | ||
43 | + pure:0, | ||
44 | + percent:0, | ||
45 | + }, | ||
46 | + ignoreGuard:0 | ||
47 | + }, | ||
48 | + efficiency:{ | ||
49 | + major:{ | ||
50 | + pure:1, | ||
51 | + percent:1 | ||
52 | + }, | ||
53 | + attackPower:{ | ||
54 | + pure:1, | ||
55 | + percent:1 | ||
56 | + }, | ||
57 | + damage:1, | ||
58 | + criticalDamage:1, | ||
59 | + ignoreGuard:1 | ||
60 | + } | ||
61 | + } | ||
62 | + }, | ||
63 | + buff:{ | ||
64 | + stats:{ | ||
65 | + major:{ | ||
66 | + pure:0, | ||
67 | + percent:0, | ||
68 | + added:0, | ||
69 | + }, | ||
70 | + minor:0, | ||
71 | + damage:{ | ||
72 | + all:0, | ||
73 | + boss:0 | ||
74 | + }, | ||
75 | + finalDamage:0, | ||
76 | + criticalDamage:0, | ||
77 | + attackPower:{ | ||
78 | + pure:0, | ||
79 | + percent:0, | ||
80 | + }, | ||
81 | + ignoreGuard:0 | ||
82 | + }, | ||
83 | + efficiency:{ | ||
84 | + major:{ | ||
85 | + pure:1, | ||
86 | + percent:1 | ||
87 | + }, | ||
88 | + attackPower:{ | ||
89 | + pure:1, | ||
90 | + percent:1 | ||
91 | + }, | ||
92 | + damage:1, | ||
93 | + criticalDamage:1, | ||
94 | + ignoreGuard:1 | ||
95 | + } | ||
96 | + } | ||
97 | + } | ||
98 | + | ||
99 | + function init() { | ||
100 | + let nickname; | ||
101 | + | ||
102 | + if(!params.character) { | ||
103 | + M.toast({html:"캐릭터명을 입력해주세요."}); | ||
104 | + push("/"); | ||
105 | + } | ||
106 | + | ||
107 | + nickname = decodeURI(params.character); | ||
108 | + | ||
109 | + callCount++; | ||
110 | + axios.get('/api/character', { | ||
111 | + params:{ | ||
112 | + nickname:nickname | ||
113 | + } | ||
114 | + }).then(function(response) { | ||
115 | + character = response.data; | ||
116 | + isCharacterLoading = true; | ||
117 | + }).catch(function(error) { | ||
118 | + switch(error.response.status) { | ||
119 | + case 404: | ||
120 | + M.toast({html:"존재하지 않는 캐릭터입니다."}); | ||
121 | + break; | ||
122 | + case 403: | ||
123 | + M.toast({html:"캐릭터 정보 공개설정이 필요합니다."}); | ||
124 | + setTimeout(function() { | ||
125 | + window.open("https://maplestory.nexon.com/MyMaple/Account/Character/Visibility"); | ||
126 | + }, 2000); | ||
127 | + break; | ||
128 | + case 503: | ||
129 | + M.toast({html:"메이플스토리가 점검중입니다."}); | ||
130 | + break; | ||
131 | + default: | ||
132 | + M.toast({html:"서버와의 통신이 원활하지 않습니다.<br><br>잠시 후에 시도해주세요."}); | ||
133 | + break; | ||
134 | + } | ||
135 | + push('/'); | ||
136 | + }).finally(function() { | ||
137 | + callCount--; | ||
138 | + }); | ||
139 | + } | ||
140 | + | ||
141 | + function showValue(value) { | ||
142 | + return parseFloat(value).toFixed(2); | ||
143 | + } | ||
144 | + | ||
145 | + function goBack() { | ||
146 | + push('/'); | ||
147 | + } | ||
148 | + | ||
149 | + $: | ||
150 | + if(isCharacterLoading && isBuff) { | ||
151 | + stats = character.analysis.buff; | ||
152 | + } else { | ||
153 | + stats = character.analysis.default; | ||
154 | + } | ||
155 | + | ||
156 | + init(); | ||
157 | +</script> | ||
158 | + | ||
159 | +<svelte:head> | ||
160 | + | ||
161 | +</svelte:head> | ||
162 | + | ||
163 | +<Loading count={callCount} /> | ||
164 | +<section> | ||
165 | + {#if isCharacterLoading} | ||
166 | + <article class="info-box"> | ||
167 | + <div class="row"> | ||
168 | + <div class="col s12 m10 l8 offset-m1 offset-l2"> | ||
169 | + <div class="row"> | ||
170 | + <div class="col s12 m4 l3"> | ||
171 | + <div class="card character-card"> | ||
172 | + <div class="card-stacked"> | ||
173 | + <div class="card-content"> | ||
174 | + <div class="character-img"> | ||
175 | + <img src={character.info.avatar} class="responsive-img" alt="캐릭터"> | ||
176 | + </div> | ||
177 | + <h6 class="pink-text text-accent-3"> | ||
178 | + <img src={character.info.server.icon} alt={character.info.server.name}> | ||
179 | + {character.info.nickname} | ||
180 | + </h6> | ||
181 | + <div class="job grey-text text-darken-2"> | ||
182 | + {character.info.job} | ||
183 | + </div> | ||
184 | + <div class="level grey-text text-darken-2"> | ||
185 | + Lv.{character.info.level} | ||
186 | + </div> | ||
187 | + </div> | ||
188 | + </div> | ||
189 | + </div> | ||
190 | + <div class="back-button-box"> | ||
191 | + <button class="btn waves-light btn red accent-2" on:click={goBack}> | ||
192 | + <i class="material-icons">arrow_back</i> | ||
193 | + <span>뒤로가기</span> | ||
194 | + </button> | ||
195 | + </div> | ||
196 | + </div> | ||
197 | + <div class="col s12 m8 l9"> | ||
198 | + <div class="card character-card"> | ||
199 | + <div class="card-stacked"> | ||
200 | + <div class="card-content"> | ||
201 | + <div class="buff-switch"> | ||
202 | + <div class="switch"> | ||
203 | + <label> | ||
204 | + 노버프 | ||
205 | + <input type="checkbox" bind:checked={isBuff}> | ||
206 | + <span class="lever"></span> | ||
207 | + 버프(자벞,링크,노블,영메) | ||
208 | + </label> | ||
209 | + </div> | ||
210 | + </div> | ||
211 | + <table class="table-efficiency"> | ||
212 | + <thead> | ||
213 | + <tr> | ||
214 | + <th>스탯</th> | ||
215 | + <th>효율</th> | ||
216 | + </tr> | ||
217 | + </thead> | ||
218 | + <tbody> | ||
219 | + <tr> | ||
220 | + <th rowspan="2">{character.info.majorName} 1%</th> | ||
221 | + <td>{character.info.majorName} {showValue(stats.efficiency.major.percent)}</td> | ||
222 | + </tr> | ||
223 | + <tr> | ||
224 | + <td>{character.info.attackPowerName} {showValue(stats.efficiency.major.percent / stats.efficiency.attackPower.pure)}</td> | ||
225 | + </tr> | ||
226 | + <tr> | ||
227 | + <th>{character.info.attackPowerName} 1</th> | ||
228 | + <td>{character.info.majorName} {showValue(stats.efficiency.attackPower.pure)}</td> | ||
229 | + </tr> | ||
230 | + <tr> | ||
231 | + <th rowspan="5">{character.info.attackPowerName} 1%</th> | ||
232 | + <td>{character.info.majorName} {showValue(stats.efficiency.attackPower.percent)}</td> | ||
233 | + </tr> | ||
234 | + <tr> | ||
235 | + <td>{character.info.majorName} {showValue(stats.efficiency.attackPower.percent / stats.efficiency.major.percent)}%</td> | ||
236 | + </tr> | ||
237 | + <tr> | ||
238 | + <td>{character.info.attackPowerName} {showValue(stats.efficiency.attackPower.percent / stats.efficiency.attackPower.pure)}</td> | ||
239 | + </tr> | ||
240 | + <tr> | ||
241 | + <td>데미지(보공) {showValue(stats.efficiency.attackPower.percent / stats.efficiency.damage)}%</td> | ||
242 | + </tr> | ||
243 | + <tr> | ||
244 | + <td>방무 {showValue(stats.efficiency.attackPower.percent / stats.efficiency.ignoreGuard)}%</td> | ||
245 | + </tr> | ||
246 | + <tr> | ||
247 | + <th rowspan="2">데미지(보공) 1%</th> | ||
248 | + <td>{character.info.majorName} {showValue(stats.efficiency.damage)}</td> | ||
249 | + </tr> | ||
250 | + <tr> | ||
251 | + <td>방무 {showValue(stats.efficiency.damage / stats.efficiency.ignoreGuard)}%</td> | ||
252 | + </tr> | ||
253 | + <tr> | ||
254 | + <th rowspan="2">크뎀 1%</th> | ||
255 | + <td>{character.info.majorName} {showValue(stats.efficiency.criticalDamage)}</td> | ||
256 | + </tr> | ||
257 | + <tr> | ||
258 | + <td>{character.info.majorName} {showValue(stats.efficiency.criticalDamage / stats.efficiency.major.percent)}%</td> | ||
259 | + </tr> | ||
260 | + <tr> | ||
261 | + <th>방무 1%</th> | ||
262 | + <td>{character.info.majorName} {showValue(stats.efficiency.ignoreGuard)}</td> | ||
263 | + </tr> | ||
264 | + </tbody> | ||
265 | + </table> | ||
266 | + </div> | ||
267 | + </div> | ||
268 | + </div> | ||
269 | + </div> | ||
270 | + </div> | ||
271 | + </div> | ||
272 | + </div> | ||
273 | + </article> | ||
274 | + {/if} | ||
275 | +</section> | ||
276 | + | ||
277 | +<style> | ||
278 | +section { width:100%; height:100%; display:flex; flex-direction:column; padding:20px 0; } | ||
279 | +.info-box { margin:auto 0; } | ||
280 | +.info-box > .row > .col > .row > .col { margin-bottom:.5rem; } | ||
281 | +.character-card .card-content { text-align:center; } | ||
282 | +.character-card .card-content .job { font-size:0.8em } | ||
283 | +.character-card .card-content .level { font-size:0.8em } | ||
284 | +.character-card .card-content h6 img { width:14px; height:14px; } | ||
285 | +.character-card .card-content h6 { font-weight:bold; } | ||
286 | +.table-efficiency td, .table-efficiency th { text-align:left; } | ||
287 | +.back-button-box button { width:100%; display:block; height:48px; line-height:48px; } | ||
288 | +.back-button-box button i.material-icons { vertical-align:middle; } | ||
289 | +.back-button-box button span { vertical-align:middle; } | ||
290 | +.buff-switch .switch label input[type=checkbox]:checked+.lever:after { background-color:#e57373; } | ||
291 | +.buff-switch .switch label input[type=checkbox]:not(:checked)+.lever { background-color:#ffcdd2; } | ||
292 | +.buff-switch .switch label input[type=checkbox]:checked+.lever { background-color:#ef9a9a ; } | ||
293 | +</style> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
app/web/src/routes/Home.svelte
deleted
100644 → 0
1 | -<main> | ||
2 | - <h1>Hello, This is Home!</h1> | ||
3 | - <p>Visit the <a href="https://svelte.dev/tutorial">Svelte tutorial</a> to learn how to build Svelte apps.</p> | ||
4 | -</main> | ||
5 | - | ||
6 | -<style> | ||
7 | - main { | ||
8 | - text-align: center; | ||
9 | - padding: 1em; | ||
10 | - max-width: 240px; | ||
11 | - margin: 0 auto; | ||
12 | - } | ||
13 | - | ||
14 | - h1 { | ||
15 | - color: #ff3e00; | ||
16 | - text-transform: uppercase; | ||
17 | - font-size: 4em; | ||
18 | - font-weight: 100; | ||
19 | - } | ||
20 | - | ||
21 | - @media (min-width: 640px) { | ||
22 | - main { | ||
23 | - max-width: none; | ||
24 | - } | ||
25 | - } | ||
26 | -</style> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
app/web/src/routes/Search.svelte
0 → 100644
1 | +<script> | ||
2 | + import {push} from 'svelte-spa-router'; | ||
3 | + | ||
4 | + let character; | ||
5 | + | ||
6 | + function searchCharacter() { | ||
7 | + if(!character) { | ||
8 | + M.toast({html:"캐릭터명을 입력해주세요."}); | ||
9 | + return false; | ||
10 | + } | ||
11 | + | ||
12 | + push('/character/' + character); | ||
13 | + } | ||
14 | +</script> | ||
15 | + | ||
16 | +<svelte:head> | ||
17 | + | ||
18 | +</svelte:head> | ||
19 | + | ||
20 | +<section> | ||
21 | + <article class="search-box row"> | ||
22 | + <div class="col l4 m6 s12 offset-l4 offset-m3"> | ||
23 | + <div class="card"> | ||
24 | + <div class="card-stacked"> | ||
25 | + <div class="card-content"> | ||
26 | + <h4>내 캐릭터 분석하기</h4> | ||
27 | + <form class="search-form" on:submit={searchCharacter} onsubmit="return false;"> | ||
28 | + <div class="input-field"> | ||
29 | + <label>캐릭터명</label> | ||
30 | + <input type="text" bind:value={character}> | ||
31 | + <button class="btn waves-effect waves-light red darken-1">확인</button> | ||
32 | + </div> | ||
33 | + </form> | ||
34 | + </div> | ||
35 | + <div class="card-action"> | ||
36 | + <p class="teal-text text-lighten-2"> | ||
37 | + 메이플스토리 스펙 계산기를 이용하기 위해서는 캐릭터 정보 공개(기본정보, 장비, 스킬)가 필요합니다. | ||
38 | + </p> | ||
39 | + <p> | ||
40 | + <a href="https://maplestory.nexon.com/MyMaple/Account/Character/Visibility" target="_BLANK">공개설정하러 가기</a> | ||
41 | + </p> | ||
42 | + <p class="red-text text-accent-1"> | ||
43 | + <i class="material-icons">info_outline</i> | ||
44 | + <span>제논, 데몬어벤져는 지원하지 않습니다.</span> | ||
45 | + </p> | ||
46 | + </div> | ||
47 | + </div> | ||
48 | + </div> | ||
49 | + </div> | ||
50 | + </article> | ||
51 | +</section> | ||
52 | + | ||
53 | +<style> | ||
54 | +section { width:100%; height:100%; display:flex; flex-direction:column; } | ||
55 | +.search-box { width:100%; margin:auto 0; } | ||
56 | +h4 { font-size:20px; text-align:center; } | ||
57 | +.input-field { padding-right:70px; } | ||
58 | +.input-field button { position:absolute; right:0; top:7px; } | ||
59 | +.card-action i.material-icons { font-size:1.1em; vertical-align:middle; } | ||
60 | +.card-action i.material-icons ~ span { vertical-align:middle; } | ||
61 | +</style> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or login to post a comment